26
.gitignore
vendored
@ -1,8 +1,34 @@
|
||||
harbor
|
||||
make/common/config/*
|
||||
make/dev/adminserver/harbor_adminserver
|
||||
make/dev/ui/harbor_ui
|
||||
make/dev/jobservice/harbor_jobservice
|
||||
src/adminserver/adminserver
|
||||
src/ui/ui
|
||||
src/jobservice/jobservice
|
||||
src/common/dao/dao.test
|
||||
*.pyc
|
||||
jobservice/test
|
||||
|
||||
src/ui/static/*.html
|
||||
src/ui/static/*.bundle.js
|
||||
src/ui/static/*.bundle.js.map
|
||||
src/ui/static/harbor-logo.*.png
|
||||
src/ui/static/i18n/lang/en-us-lang.json
|
||||
src/ui/static/i18n/lang/zh-cn-lang.json
|
||||
|
||||
src/ui_ng/coverage/
|
||||
src/ui_ng/dist/
|
||||
src/ui_ng/html-report/
|
||||
src/ui_ng/node_modules/
|
||||
src/ui_ng/typings/
|
||||
**/*npm-debug.log.*
|
||||
**/*yarn-error.log.*
|
||||
.idea/
|
||||
.DS_Store
|
||||
**/node_modules
|
||||
**/ssl/
|
||||
**/proxy.config.json
|
||||
**/npm*.log
|
||||
**/*ngsummary.json
|
||||
**/*ngfactory.ts
|
||||
|
42
.travis.yml
@ -3,7 +3,7 @@ sudo: true
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.6.2
|
||||
- 1.7.3
|
||||
|
||||
go_import_path: github.com/vmware/harbor
|
||||
|
||||
@ -13,25 +13,25 @@ services:
|
||||
dist: trusty
|
||||
|
||||
env:
|
||||
DB_HOST: 127.0.0.1
|
||||
DB_PORT: 3306
|
||||
DB_USR: root
|
||||
DB_PWD: root123
|
||||
MYSQL_HOST: localhost
|
||||
MYSQL_PORT: 3306
|
||||
MYSQL_USR: root
|
||||
MYSQL_PWD: root123
|
||||
MYSQL_DATABASE: registry
|
||||
SQLITE_FILE: /tmp/registry.db
|
||||
ADMIN_SERVER_URL: http://127.0.0.1:8888
|
||||
DOCKER_COMPOSE_VERSION: 1.7.1
|
||||
HARBOR_ADMIN: admin
|
||||
HARBOR_ADMIN_PASSWD: Harbor12345
|
||||
UI_SECRET: tempString
|
||||
MAX_JOB_WORKERS: 3
|
||||
SECRET_KEY: 1234567890123456
|
||||
AUTH_MODE: db_auth
|
||||
SELF_REGISTRATION: "on"
|
||||
SELF_REGISTRATION: on
|
||||
KEY_PATH: /data/secretkey
|
||||
|
||||
before_install:
|
||||
- sudo ./tests/hostcfg.sh
|
||||
- sudo ./tests/generateCerts.sh
|
||||
- sudo ./make/prepare
|
||||
|
||||
install:
|
||||
@ -70,28 +70,40 @@ install:
|
||||
before_script:
|
||||
# create tables and load data
|
||||
# - mysql < ./make/db/registry.sql -uroot --verbose
|
||||
- sudo sqlite3 /registry.db < make/common/db/registry_sqlite.sql
|
||||
- sudo sqlite3 /tmp/registry.db < make/common/db/registry_sqlite.sql
|
||||
- sudo chmod 777 /tmp/registry.db
|
||||
|
||||
script:
|
||||
- sudo mkdir -p /etc/ui/ca/
|
||||
- sudo mv ./tests/ca.crt /etc/ui/ca/
|
||||
- sudo mkdir -p /harbor
|
||||
- sudo mv ./VERSION /harbor/VERSION
|
||||
- sudo service mysql stop
|
||||
- sudo ./tests/testprepare.sh
|
||||
- docker-compose -f ./make/docker-compose.test.yml up -d
|
||||
- sudo docker-compose -f ./make/docker-compose.test.yml up -d
|
||||
- go list ./... | grep -v -E 'vendor|tests' | xargs -L1 fgt golint
|
||||
- go list ./... | grep -v -E 'vendor|tests' | xargs -L1 go vet
|
||||
- export MYSQL_HOST=$IP
|
||||
- export REGISTRY_URL=$IP:5000
|
||||
- echo $REGISTRY_URL
|
||||
- ./tests/pushimage.sh
|
||||
- ./tests/coverage4gotest.sh
|
||||
- ./tests/pushimage.sh
|
||||
- cd tests
|
||||
- sudo ./ldapprepare.sh
|
||||
- cd ..
|
||||
- go test -i ./src/ui ./src/adminserver ./src/jobservice
|
||||
- sudo -E env "PATH=$PATH" ./tests/coverage4gotest.sh
|
||||
- goveralls -coverprofile=profile.cov -service=travis-ci
|
||||
|
||||
- docker-compose -f make/docker-compose.test.yml down
|
||||
|
||||
- docker-compose -f make/dev/docker-compose.yml up -d
|
||||
- sudo rm -rf /data/config/*
|
||||
- ls /data/cert
|
||||
- sudo make install GOBUILDIMAGE=golang:1.7.3 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:0.8.4 NOTARYFLAG=true
|
||||
|
||||
- docker ps
|
||||
- go run tests/startuptest.go http://localhost/
|
||||
- go run tests/userlogintest.go -name ${HARBOR_ADMIN} -passwd ${HARBOR_ADMIN_PASSWD}
|
||||
- ./tests/notarytest.sh
|
||||
- ./tests/swaggerchecker.sh
|
||||
- ./tests/startuptest.sh
|
||||
- ./tests/userlogintest.sh ${HARBOR_ADMIN} ${HARBOR_ADMIN_PASSWD}
|
||||
|
||||
# - sudo ./tests/testprepare.sh
|
||||
# - go test -v ./tests/apitests
|
||||
|
4
AUTHORS
@ -5,6 +5,7 @@ Alexey Erkak <eryigin at mail.ru>
|
||||
Allen Heavey <xheavey at gmail.com>
|
||||
Amanda Zhang <amzhang at vmware.com>
|
||||
Andre Cruz <andre at brpx.com>
|
||||
Aron Parsons <aron at knackworks.com>
|
||||
Benniu Ji <benniuji at gmail.com>
|
||||
Bin Liu <liubin0329 at gmail.com>
|
||||
Bobby Zhang <junzhang at vmware.com>
|
||||
@ -12,6 +13,7 @@ Brian Christner <brian.christner at gmail.com>
|
||||
Chaofeng Wu <chaofengw at vmware.com>
|
||||
Daniel Jiang <jiangd at vmware.com>
|
||||
Deshi Xiao <xiaods at gmail.com>
|
||||
Feileng Cui <feilengcui008 at gmail.com>
|
||||
Guangping Fu <krystism at gmail.com>
|
||||
Haining Henry Zhang <henryzhang at vmware.com>
|
||||
Hao Xia <haox at vmware.com>
|
||||
@ -19,6 +21,7 @@ Haoyuan <harryge00 at gmail.com>
|
||||
Jack Liu <ljack at vmware.com>
|
||||
Jessy Zhang <jessyz at vmware.com>
|
||||
Jianye Li <li.jianye at gmail.com>
|
||||
Kira <me at imkira.com>
|
||||
Kun Wang <kunw at vmware.com>
|
||||
Mahesh Paolini-Subramanya <mahesh at dieswaytoofast.com>
|
||||
Maxwell <710028463 at qq.com>
|
||||
@ -29,6 +32,7 @@ Penghao Cen <scorpiocph at gmail.com>
|
||||
Phillip Gomez <gomez.phillip at gmail.com>
|
||||
Robin Naundorf <r.naundorf at fh-muenster.de>
|
||||
Shan Zhu <zhus at vmware.com>
|
||||
Steven Zou <szou at vmware.com>
|
||||
Robin Yue <jmyue at hotmail.com>
|
||||
Tobe Chen <tobeg3oogle at gmail.com>
|
||||
Victoria Zheng <vzheng at vmware.com>
|
||||
|
28
CHANGELOG.md
@ -1,5 +1,33 @@
|
||||
# Changelog
|
||||
|
||||
|
||||
## v1.1.0 (2017-4-18)
|
||||
|
||||
- Add in Notary support
|
||||
- User can update configuration through Harbor UI
|
||||
- Redesign of Harbor's UI using Clarity
|
||||
- Some changes to API
|
||||
- Fix some security issues in token service
|
||||
- Upgrade base image of nginx for latest openssl version
|
||||
- Various bug fixes.
|
||||
|
||||
## v0.5.0 (2016-12-6)
|
||||
|
||||
- Refactory for a new build process
|
||||
- Easier configuration for HTTPS in prepare script
|
||||
- Script to collect logs of a Harbor deployment
|
||||
- User can view the storage usage (default location) of Harbor.
|
||||
- Add an attribute to disable normal user to create project
|
||||
- Various bug fixes.
|
||||
|
||||
For Harbor virtual appliance:
|
||||
|
||||
- Improve the bootstrap process of ova installation.
|
||||
- Enable HTTPS by default for .ova deployment, users can download the default root cert from UI for docker client or VCH.
|
||||
- Preload a photon:1.0 image to Harbor for users who have no internet connection.
|
||||
|
||||
|
||||
|
||||
## v0.4.5 (2016-10-31)
|
||||
|
||||
- Virtual appliance of Harbor for vSphere.
|
||||
|
820
Makefile
@ -1,368 +1,452 @@
|
||||
# Makefile for Harbor project
|
||||
#
|
||||
# Targets:
|
||||
#
|
||||
# all: prepare env, compile binarys, build images and install images
|
||||
# prepare: prepare env
|
||||
# compile: compile ui and jobservice code
|
||||
# compile_buildgolangimage:
|
||||
# compile local building golang image
|
||||
# forexample : make compile_buildgolangimage -e \
|
||||
# GOBUILDIMAGE=harborgo:1.6.2
|
||||
# compile_golangimage:
|
||||
# compile from golang image
|
||||
# for example: make compile_golangimage -e GOBUILDIMAGE= \
|
||||
# harborgo:1.6.2
|
||||
# compile_ui, compile_jobservice: compile specific binary
|
||||
#
|
||||
# build: build Harbor docker images (defuault: build_photon)
|
||||
# for example: make build -e BASEIMAGE=photon
|
||||
# build_photon: build Harbor docker images from photon bsaeimage
|
||||
# build_ubuntu: build Harbor docker images from ubuntu baseimage
|
||||
#
|
||||
# install: include compile binarys, build images, prepare specific \
|
||||
# version composefile and startup Harbor instance
|
||||
#
|
||||
# start: startup Harbor instance
|
||||
#
|
||||
# down: shutdown Harbor instance
|
||||
#
|
||||
# package_online:
|
||||
# prepare online install package
|
||||
# for example: make package_online -e DEVFLAG=false\
|
||||
# REGISTRYSERVER=reg-bj.eng.vmware.com \
|
||||
# REGISTRYPROJECTNAME=harborrelease
|
||||
#
|
||||
# package_offline:
|
||||
# prepare offline install package
|
||||
#
|
||||
# pushimage: push Harbor images to specific registry server
|
||||
# for example: make pushimage -e DEVFLAG=false REGISTRYUSER=admin \
|
||||
# REGISTRYPASSWORD=***** \
|
||||
# REGISTRYSERVER=reg-bj.eng.vmware.com/ \
|
||||
# REGISTRYPROJECTNAME=harborrelease
|
||||
# note**: need add "/" on end of REGISTRYSERVER. If not setting \
|
||||
# this value will push images directly to dockerhub.
|
||||
# make pushimage -e DEVFLAG=false REGISTRYUSER=vmware \
|
||||
# REGISTRYPASSWORD=***** \
|
||||
# REGISTRYPROJECTNAME=vmware
|
||||
#
|
||||
# clean: remove binary, Harbor images, specific version docker-compose \
|
||||
# file, specific version tag and online/offline install package
|
||||
# cleanbinary: remove ui and jobservice binary
|
||||
# cleanimage: remove Harbor images
|
||||
# cleandockercomposefile:
|
||||
# remove specific version docker-compose
|
||||
# cleanversiontag:
|
||||
# cleanpackageremove specific version tag
|
||||
# cleanpackage: remove online/offline install package
|
||||
#
|
||||
# other example:
|
||||
# clean specific version binarys and images:
|
||||
# make clean -e VERSIONTAG=[TAG]
|
||||
# note**: If commit new code to github, the git commit TAG will \
|
||||
# change. Better use this commond clean previous images and \
|
||||
# files with specific TAG.
|
||||
# By default DEVFLAG=true, if you want to release new version of Harbor, \
|
||||
# should setting the flag to false.
|
||||
# make XXXX -e DEVFLAG=false
|
||||
|
||||
SHELL := /bin/bash
|
||||
BUILDPATH=$(CURDIR)
|
||||
MAKEPATH=$(BUILDPATH)/make
|
||||
MAKEDEVPATH=$(MAKEPATH)/dev
|
||||
SRCPATH=./src
|
||||
TOOLSPATH=$(BUILDPATH)/tools
|
||||
GOBASEPATH=/go/src/github.com/vmware
|
||||
CHECKENVCMD=checkenv.sh
|
||||
BASEIMAGE=photon
|
||||
COMPILETAG=compile_normal
|
||||
REGISTRYSERVER=
|
||||
REGISTRYPROJECTNAME=vmware
|
||||
DEVFLAG=true
|
||||
|
||||
# docker parameters
|
||||
DOCKERCMD=$(shell which docker)
|
||||
DOCKERBUILD=$(DOCKERCMD) build
|
||||
DOCKERRMIMAGE=$(DOCKERCMD) rmi
|
||||
DOCKERPULL=$(DOCKERCMD) pull
|
||||
DOCKERIMASES=$(DOCKERCMD) images
|
||||
DOCKERSAVE=$(DOCKERCMD) save
|
||||
DOCKERCOMPOSECMD=$(shell which docker-compose)
|
||||
DOCKERTAG=$(DOCKERCMD) tag
|
||||
|
||||
# go parameters
|
||||
GOCMD=$(shell which go)
|
||||
GOBUILD=$(GOCMD) build
|
||||
GOCLEAN=$(GOCMD) clean
|
||||
GOINSTALL=$(GOCMD) install
|
||||
GOTEST=$(GOCMD) test
|
||||
GODEP=$(GOTEST) -i
|
||||
GOFMT=gofmt -w
|
||||
GOBUILDIMAGE=reg.mydomain.com/library/harborgo[:tag]
|
||||
GOBUILDPATH=$(GOBASEPATH)/harbor
|
||||
GOIMAGEBUILDCMD=/usr/local/go/bin/go
|
||||
GOIMAGEBUILD=$(GOIMAGEBUILDCMD) build
|
||||
GOBUILDPATH_UI=$(GOBUILDPATH)/src/ui
|
||||
GOBUILDPATH_JOBSERVICE=$(GOBUILDPATH)/src/jobservice
|
||||
GOBUILDMAKEPATH=$(GOBUILDPATH)/make
|
||||
GOBUILDMAKEPATH_UI=$(GOBUILDMAKEPATH)/dev/ui
|
||||
GOBUILDMAKEPATH_JOBSERVICE=$(GOBUILDMAKEPATH)/dev/jobservice
|
||||
GOLANGDOCKERFILENAME=Dockerfile.golang
|
||||
|
||||
# binary
|
||||
UISOURCECODE=$(SRCPATH)/ui
|
||||
UIBINARYPATH=$(MAKEDEVPATH)/ui
|
||||
UIBINARYNAME=harbor_ui
|
||||
JOBSERVICESOURCECODE=$(SRCPATH)/jobservice
|
||||
JOBSERVICEBINARYPATH=$(MAKEDEVPATH)/jobservice
|
||||
JOBSERVICEBINARYNAME=harbor_jobservice
|
||||
|
||||
# prepare parameters
|
||||
PREPAREPATH=$(TOOLSPATH)
|
||||
PREPARECMD=prepare
|
||||
|
||||
# configfile
|
||||
CONFIGPATH=$(MAKEPATH)
|
||||
CONFIGFILE=harbor.cfg
|
||||
|
||||
# makefile
|
||||
MAKEFILEPATH_PHOTON=$(MAKEPATH)/photon
|
||||
MAKEFILEPATH_UBUNTU=$(MAKEPATH)/ubuntu
|
||||
|
||||
# common dockerfile
|
||||
DOCKERFILEPATH_COMMON=$(MAKEPATH)/common
|
||||
DOCKERFILEPATH_DB=$(DOCKERFILEPATH_COMMON)/db
|
||||
DOCKERFILENAME_DB=Dockerfile
|
||||
|
||||
# docker image name
|
||||
DOCKERIMAGENAME_UI=vmware/harbor-ui
|
||||
DOCKERIMAGENAME_JOBSERVICE=vmware/harbor-jobservice
|
||||
DOCKERIMAGENAME_LOG=vmware/harbor-log
|
||||
DOCKERIMAGENAME_DB=vmware/harbor-db
|
||||
|
||||
|
||||
# docker-compose files
|
||||
DOCKERCOMPOSEFILEPATH=$(MAKEPATH)
|
||||
DOCKERCOMPOSETPLFILENAME=docker-compose.tpl
|
||||
DOCKERCOMPOSEFILENAME=docker-compose.yml
|
||||
|
||||
# version prepare
|
||||
VERSIONFILEPATH=$(SRCPATH)/ui/views/sections
|
||||
VERSIONFILENAME=header-content.htm
|
||||
GITCMD=$(shell which git)
|
||||
GITTAG=$(GITCMD) describe --tags
|
||||
ifeq ($(DEVFLAG), true)
|
||||
VERSIONTAG=dev
|
||||
else
|
||||
VERSIONTAG=$(shell $(GITTAG))
|
||||
endif
|
||||
|
||||
SEDCMD=$(shell which sed)
|
||||
|
||||
# package
|
||||
TARCMD=$(shell which tar)
|
||||
ZIPCMD=$(shell which gzip)
|
||||
DOCKERIMGFILE=harbor
|
||||
HARBORPKG=harbor
|
||||
|
||||
# pushimage
|
||||
PUSHSCRIPTPATH=$(MAKEPATH)
|
||||
PUSHSCRIPTNAME=pushimage.sh
|
||||
REGISTRYUSER=user
|
||||
REGISTRYPASSWORD=default
|
||||
|
||||
version:
|
||||
@if [ "$(DEVFLAG)" = "false" ] ; then \
|
||||
$(SEDCMD) -i 's/version=\"{{.Version}}\"/version=\"$(VERSIONTAG)\"/' -i $(VERSIONFILEPATH)/$(VERSIONFILENAME) ; \
|
||||
fi
|
||||
|
||||
check_environment:
|
||||
@$(MAKEPATH)/$(CHECKENVCMD)
|
||||
|
||||
compile_ui:
|
||||
@echo "compiling binary for ui..."
|
||||
@$(GOBUILD) -o $(UIBINARYPATH)/$(UIBINARYNAME) $(UISOURCECODE)
|
||||
@echo "Done."
|
||||
|
||||
compile_jobservice:
|
||||
@echo "compiling binary for jobservice..."
|
||||
@$(GOBUILD) -o $(JOBSERVICEBINARYPATH)/$(JOBSERVICEBINARYNAME) $(JOBSERVICESOURCECODE)
|
||||
@echo "Done."
|
||||
|
||||
compile_normal: compile_ui compile_jobservice
|
||||
|
||||
compile_buildgolangimage:
|
||||
@echo "compiling golang image for harbor ..."
|
||||
@$(DOCKERBUILD) -t $(GOBUILDIMAGE) -f $(TOOLSPATH)/$(GOLANGDOCKERFILENAME) .
|
||||
@echo "Done."
|
||||
|
||||
compile_golangimage:
|
||||
@echo "compiling binary for ui (golang image)..."
|
||||
@echo $(GOBASEPATH)
|
||||
@echo $(GOBUILDPATH)
|
||||
@$(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_UI) $(GOBUILDIMAGE) $(GOIMAGEBUILD) -v -o $(GOBUILDMAKEPATH_UI)/$(UIBINARYNAME)
|
||||
@echo "Done."
|
||||
|
||||
@echo "compiling binary for jobservice (golang image)..."
|
||||
@$(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_JOBSERVICE) $(GOBUILDIMAGE) $(GOIMAGEBUILD) -v -o $(GOBUILDMAKEPATH_JOBSERVICE)/$(JOBSERVICEBINARYNAME)
|
||||
@echo "Done."
|
||||
|
||||
compile:check_environment $(COMPILETAG)
|
||||
|
||||
prepare:
|
||||
@echo "preparing..."
|
||||
@$(MAKEPATH)/$(PREPARECMD) -conf $(CONFIGPATH)/$(CONFIGFILE)
|
||||
|
||||
build_common: version
|
||||
@echo "buildging db container for photon..."
|
||||
@cd $(DOCKERFILEPATH_DB) && $(DOCKERBUILD) -f $(DOCKERFILENAME_DB) -t $(DOCKERIMAGENAME_DB):$(VERSIONTAG) .
|
||||
@echo "Done."
|
||||
|
||||
build_photon: build_common
|
||||
make -f $(MAKEFILEPATH_PHOTON)/Makefile build -e DEVFLAG=$(DEVFLAG)
|
||||
|
||||
build_ubuntu: build_common
|
||||
make -f $(MAKEFILEPATH_UBUNTU)/Makefile build -e DEVFLAG=$(DEVFLAG)
|
||||
|
||||
build: build_$(BASEIMAGE)
|
||||
|
||||
modify_composefile:
|
||||
@echo "preparing docker-compose file..."
|
||||
@cp $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSETPLFILENAME) $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSEFILENAME)
|
||||
@$(SEDCMD) -i 's/image\: vmware.*/&:$(VERSIONTAG)/g' $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSEFILENAME)
|
||||
|
||||
install: compile build prepare modify_composefile
|
||||
@echo "loading harbor images..."
|
||||
@$(DOCKERCOMPOSECMD) -f $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSEFILENAME) up -d
|
||||
@echo "Install complete. You can visit harbor now."
|
||||
|
||||
package_online: modify_composefile
|
||||
@echo "packing online package ..."
|
||||
@cp -r make $(HARBORPKG)
|
||||
@if [ -n "$(REGISTRYSERVER)" ] ; then \
|
||||
$(SEDCMD) -i 's/image\: vmware/image\: $(REGISTRYSERVER)\/$(REGISTRYPROJECTNAME)/' \
|
||||
$(HARBORPKG)/docker-compose.yml ; \
|
||||
fi
|
||||
@cp LICENSE $(HARBORPKG)/LICENSE
|
||||
@cp NOTICE $(HARBORPKG)/NOTICE
|
||||
@$(TARCMD) -zcvf harbor-online-installer-$(VERSIONTAG).tgz \
|
||||
--exclude=$(HARBORPKG)/common/db --exclude=$(HARBORPKG)/common/config\
|
||||
--exclude=$(HARBORPKG)/common/log --exclude=$(HARBORPKG)/ubuntu \
|
||||
--exclude=$(HARBORPKG)/photon --exclude=$(HARBORPKG)/kubernetes \
|
||||
--exclude=$(HARBORPKG)/dev --exclude=$(DOCKERCOMPOSETPLFILENAME) \
|
||||
--exclude=$(HARBORPKG)/checkenv.sh \
|
||||
--exclude=$(HARBORPKG)/jsminify.sh \
|
||||
--exclude=$(HARBORPKG)/pushimage.sh \
|
||||
$(HARBORPKG)
|
||||
|
||||
@rm -rf $(HARBORPKG)
|
||||
@echo "Done."
|
||||
|
||||
package_offline: compile build modify_composefile
|
||||
@echo "packing offline package ..."
|
||||
@cp -r make $(HARBORPKG)
|
||||
|
||||
@cp LICENSE $(HARBORPKG)/LICENSE
|
||||
@cp NOTICE $(HARBORPKG)/NOTICE
|
||||
|
||||
@echo "pulling nginx and registry..."
|
||||
@$(DOCKERPULL) registry:2.5.0
|
||||
@$(DOCKERPULL) nginx:1.11.5
|
||||
|
||||
@echo "saving harbor docker image"
|
||||
@$(DOCKERSAVE) -o $(HARBORPKG)/$(DOCKERIMGFILE).$(VERSIONTAG).tgz \
|
||||
$(DOCKERIMAGENAME_UI):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_LOG):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_DB):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) \
|
||||
nginx:1.11.5 registry:2.5.0 photon:1.0
|
||||
|
||||
@$(TARCMD) -zcvf harbor-offline-installer-$(VERSIONTAG).tgz \
|
||||
--exclude=$(HARBORPKG)/common/db --exclude=$(HARBORPKG)/common/config\
|
||||
--exclude=$(HARBORPKG)/common/log --exclude=$(HARBORPKG)/ubuntu \
|
||||
--exclude=$(HARBORPKG)/photon --exclude=$(HARBORPKG)/kubernetes \
|
||||
--exclude=$(HARBORPKG)/dev --exclude=$(DOCKERCOMPOSETPLFILENAME) \
|
||||
--exclude=$(HARBORPKG)/checkenv.sh \
|
||||
--exclude=$(HARBORPKG)/jsminify.sh \
|
||||
--exclude=$(HARBORPKG)/pushimage.sh \
|
||||
$(HARBORPKG)
|
||||
|
||||
@rm -rf $(HARBORPKG)
|
||||
@echo "Done."
|
||||
|
||||
pushimage:
|
||||
@echo "pushing harbor images ..."
|
||||
@$(DOCKERTAG) $(DOCKERIMAGENAME_UI):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG)
|
||||
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG) \
|
||||
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER)
|
||||
@$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG)
|
||||
|
||||
@$(DOCKERTAG) $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG)
|
||||
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) \
|
||||
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER)
|
||||
@$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG)
|
||||
|
||||
@$(DOCKERTAG) $(DOCKERIMAGENAME_LOG):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_LOG):$(VERSIONTAG)
|
||||
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_LOG):$(VERSIONTAG) \
|
||||
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER)
|
||||
@$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_LOG):$(VERSIONTAG)
|
||||
|
||||
@$(DOCKERTAG) $(DOCKERIMAGENAME_DB):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_DB):$(VERSIONTAG)
|
||||
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_DB):$(VERSIONTAG) \
|
||||
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER)
|
||||
@$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_DB):$(VERSIONTAG)
|
||||
|
||||
start:
|
||||
@echo "loading harbor images..."
|
||||
@$(DOCKERCOMPOSECMD) -f $(DOCKERCOMPOSEFILEPATH)/docker-compose.yml up -d
|
||||
@echo "Start complete. You can visit harbor now."
|
||||
|
||||
down:
|
||||
@echo "stoping harbor instance..."
|
||||
@$(DOCKERCOMPOSECMD) -f $(DOCKERCOMPOSEFILEPATH)/docker-compose.yml down
|
||||
@echo "Done."
|
||||
|
||||
cleanbinary:
|
||||
@echo "cleaning binary..."
|
||||
@if [ -f $(UIBINARYPATH)/$(UIBINARYNAME) ] ; then rm $(UIBINARYPATH)/$(UIBINARYNAME) ; fi
|
||||
@if [ -f $(JOBSERVICEBINARYPATH)/$(JOBSERVICEBINARYNAME) ] ; then rm $(JOBSERVICEBINARYPATH)/$(JOBSERVICEBINARYNAME) ; fi
|
||||
|
||||
cleanimage:
|
||||
@echo "cleaning image for photon..."
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_UI):$(VERSIONTAG)
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_DB):$(VERSIONTAG)
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG)
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_LOG):$(VERSIONTAG)
|
||||
# - $(DOCKERRMIMAGE) -f registry:2.5.0
|
||||
# - $(DOCKERRMIMAGE) -f nginx:1.11.5
|
||||
|
||||
cleandockercomposefile:
|
||||
@echo "cleaning $(DOCKERCOMPOSEFILEPATH)/docker-compose.yml"
|
||||
@if [ -f $(DOCKERCOMPOSEFILEPATH)/docker-compose.yml ] ; then rm $(DOCKERCOMPOSEFILEPATH)/docker-compose.yml ; fi
|
||||
|
||||
cleanversiontag:
|
||||
@echo "cleaning version TAG"
|
||||
@$(SEDCMD) -i 's/version=\"$(VERSIONTAG)\"/version=\"{{.Version}}\"/' -i $(VERSIONFILEPATH)/$(VERSIONFILENAME)
|
||||
|
||||
cleanpackage:
|
||||
@echo "cleaning harbor install package"
|
||||
@if [ -d $(BUILDPATH)/harbor ] ; then rm -rf $(BUILDPATH)/harbor ; fi
|
||||
@if [ -f $(BUILDPATH)/harbor-online-installer-$(VERSIONTAG).tgz ] ; \
|
||||
then rm $(BUILDPATH)/harbor-online-installer-$(VERSIONTAG).tgz ; fi
|
||||
@if [ -f $(BUILDPATH)/harbor-offline-installer-$(VERSIONTAG).tgz ] ; \
|
||||
then rm $(BUILDPATH)/harbor-offline-installer-$(VERSIONTAG).tgz ; fi
|
||||
|
||||
.PHONY: cleanall
|
||||
cleanall: cleanbinary cleanimage cleandockercomposefile cleanversiontag cleanpackage
|
||||
|
||||
clean:
|
||||
@echo " make cleanall: remove binary, Harbor images, specific version docker-compose"
|
||||
@echo " file, specific version tag, online and offline install package"
|
||||
@echo " make cleanbinary: remove ui and jobservice binary"
|
||||
@echo " make cleanimage: remove Harbor images"
|
||||
@echo " make cleandockercomposefile: remove specific version docker-compose"
|
||||
@echo " make cleanversiontag: cleanpackageremove specific version tag"
|
||||
@echo " make cleanpackage: remove online and offline install package"
|
||||
|
||||
all: install
|
||||
# Makefile for Harbor project
|
||||
#
|
||||
# Targets:
|
||||
#
|
||||
# all: prepare env, compile binarys, build images and install images
|
||||
# prepare: prepare env
|
||||
# compile: compile adminserver, ui and jobservice code
|
||||
#
|
||||
# compile_golangimage:
|
||||
# compile from golang image
|
||||
# for example: make compile_golangimage -e GOBUILDIMAGE= \
|
||||
# golang:1.7.3
|
||||
# compile_adminserver, compile_ui, compile_jobservice: compile specific binary
|
||||
#
|
||||
# build: build Harbor docker images (defuault: build_photon)
|
||||
# for example: make build -e BASEIMAGE=photon
|
||||
# build_photon: build Harbor docker images from photon baseimage
|
||||
#
|
||||
# install: include compile binarys, build images, prepare specific \
|
||||
# version composefile and startup Harbor instance
|
||||
#
|
||||
# start: startup Harbor instance
|
||||
#
|
||||
# down: shutdown Harbor instance
|
||||
#
|
||||
# package_online:
|
||||
# prepare online install package
|
||||
# for example: make package_online -e DEVFLAG=false\
|
||||
# REGISTRYSERVER=reg-bj.eng.vmware.com \
|
||||
# REGISTRYPROJECTNAME=harborrelease
|
||||
#
|
||||
# package_offline:
|
||||
# prepare offline install package
|
||||
#
|
||||
# pushimage: push Harbor images to specific registry server
|
||||
# for example: make pushimage -e DEVFLAG=false REGISTRYUSER=admin \
|
||||
# REGISTRYPASSWORD=***** \
|
||||
# REGISTRYSERVER=reg-bj.eng.vmware.com/ \
|
||||
# REGISTRYPROJECTNAME=harborrelease
|
||||
# note**: need add "/" on end of REGISTRYSERVER. If not setting \
|
||||
# this value will push images directly to dockerhub.
|
||||
# make pushimage -e DEVFLAG=false REGISTRYUSER=vmware \
|
||||
# REGISTRYPASSWORD=***** \
|
||||
# REGISTRYPROJECTNAME=vmware
|
||||
#
|
||||
# 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
|
||||
# cleanimage: remove Harbor images
|
||||
# cleandockercomposefile:
|
||||
# remove specific version docker-compose
|
||||
# cleanversiontag:
|
||||
# cleanpackageremove specific version tag
|
||||
# cleanpackage: remove online/offline install package
|
||||
#
|
||||
# other example:
|
||||
# clean specific version binarys and images:
|
||||
# make clean -e VERSIONTAG=[TAG]
|
||||
# note**: If commit new code to github, the git commit TAG will \
|
||||
# change. Better use this commond clean previous images and \
|
||||
# files with specific TAG.
|
||||
# By default DEVFLAG=true, if you want to release new version of Harbor, \
|
||||
# should setting the flag to false.
|
||||
# make XXXX -e DEVFLAG=false
|
||||
|
||||
SHELL := /bin/bash
|
||||
BUILDPATH=$(CURDIR)
|
||||
MAKEPATH=$(BUILDPATH)/make
|
||||
MAKEDEVPATH=$(MAKEPATH)/dev
|
||||
SRCPATH=./src
|
||||
TOOLSPATH=$(BUILDPATH)/tools
|
||||
UIPATH=$(BUILDPATH)/src/ui
|
||||
UINGPATH=$(BUILDPATH)/src/ui_ng
|
||||
GOBASEPATH=/go/src/github.com/vmware
|
||||
CHECKENVCMD=checkenv.sh
|
||||
BASEIMAGE=photon
|
||||
COMPILETAG=compile_normal
|
||||
REGISTRYSERVER=
|
||||
REGISTRYPROJECTNAME=vmware
|
||||
DEVFLAG=true
|
||||
NOTARYFLAG=false
|
||||
REGISTRYVERSION=photon-2.6.0
|
||||
NGINXVERSION=1.11.5-patched
|
||||
PHOTONVERSION=1.0
|
||||
NOTARYVERSION=server-0.5.0
|
||||
NOTARYSIGNERVERSION=signer-0.5.0
|
||||
MARIADBVERSION=mariadb-10.1.10
|
||||
HTTPPROXY=
|
||||
|
||||
#clarity parameters
|
||||
CLARITYIMAGE=vmware/harbor-clarity-ui-builder[:tag]
|
||||
CLARITYSEEDPATH=/clarity-seed
|
||||
CLARITYBUILDSCRIPT=/entrypoint.sh
|
||||
|
||||
# docker parameters
|
||||
DOCKERCMD=$(shell which docker)
|
||||
DOCKERBUILD=$(DOCKERCMD) build
|
||||
DOCKERRMIMAGE=$(DOCKERCMD) rmi
|
||||
DOCKERPULL=$(DOCKERCMD) pull
|
||||
DOCKERIMASES=$(DOCKERCMD) images
|
||||
DOCKERSAVE=$(DOCKERCMD) save
|
||||
DOCKERCOMPOSECMD=$(shell which docker-compose)
|
||||
DOCKERTAG=$(DOCKERCMD) tag
|
||||
|
||||
# go parameters
|
||||
GOCMD=$(shell which go)
|
||||
GOBUILD=$(GOCMD) build
|
||||
GOCLEAN=$(GOCMD) clean
|
||||
GOINSTALL=$(GOCMD) install
|
||||
GOTEST=$(GOCMD) test
|
||||
GODEP=$(GOTEST) -i
|
||||
GOFMT=gofmt -w
|
||||
GOBUILDIMAGE=reg.mydomain.com/library/harborgo[:tag]
|
||||
GOBUILDPATH=$(GOBASEPATH)/harbor
|
||||
GOIMAGEBUILDCMD=/usr/local/go/bin/go
|
||||
GOIMAGEBUILD=$(GOIMAGEBUILDCMD) build
|
||||
GOBUILDPATH_ADMINSERVER=$(GOBUILDPATH)/src/adminserver
|
||||
GOBUILDPATH_UI=$(GOBUILDPATH)/src/ui
|
||||
GOBUILDPATH_JOBSERVICE=$(GOBUILDPATH)/src/jobservice
|
||||
GOBUILDMAKEPATH=$(GOBUILDPATH)/make
|
||||
GOBUILDMAKEPATH_ADMINSERVER=$(GOBUILDMAKEPATH)/dev/adminserver
|
||||
GOBUILDMAKEPATH_UI=$(GOBUILDMAKEPATH)/dev/ui
|
||||
GOBUILDMAKEPATH_JOBSERVICE=$(GOBUILDMAKEPATH)/dev/jobservice
|
||||
GOLANGDOCKERFILENAME=Dockerfile.golang
|
||||
|
||||
# binary
|
||||
ADMINSERVERSOURCECODE=$(SRCPATH)/adminserver
|
||||
ADMINSERVERBINARYPATH=$(MAKEDEVPATH)/adminserver
|
||||
ADMINSERVERBINARYNAME=harbor_adminserver
|
||||
UISOURCECODE=$(SRCPATH)/ui
|
||||
UIBINARYPATH=$(MAKEDEVPATH)/ui
|
||||
UIBINARYNAME=harbor_ui
|
||||
JOBSERVICESOURCECODE=$(SRCPATH)/jobservice
|
||||
JOBSERVICEBINARYPATH=$(MAKEDEVPATH)/jobservice
|
||||
JOBSERVICEBINARYNAME=harbor_jobservice
|
||||
|
||||
# prepare parameters
|
||||
PREPAREPATH=$(TOOLSPATH)
|
||||
PREPARECMD=prepare
|
||||
|
||||
# configfile
|
||||
CONFIGPATH=$(MAKEPATH)
|
||||
CONFIGFILE=harbor.cfg
|
||||
|
||||
# makefile
|
||||
MAKEFILEPATH_PHOTON=$(MAKEPATH)/photon
|
||||
|
||||
# common dockerfile
|
||||
DOCKERFILEPATH_COMMON=$(MAKEPATH)/common
|
||||
DOCKERFILEPATH_DB=$(DOCKERFILEPATH_COMMON)/db
|
||||
DOCKERFILENAME_DB=Dockerfile
|
||||
|
||||
# docker image name
|
||||
DOCKERIMAGENAME_ADMINSERVER=vmware/harbor-adminserver
|
||||
DOCKERIMAGENAME_UI=vmware/harbor-ui
|
||||
DOCKERIMAGENAME_JOBSERVICE=vmware/harbor-jobservice
|
||||
DOCKERIMAGENAME_LOG=vmware/harbor-log
|
||||
DOCKERIMAGENAME_DB=vmware/harbor-db
|
||||
|
||||
# docker-compose files
|
||||
DOCKERCOMPOSEFILEPATH=$(MAKEPATH)
|
||||
DOCKERCOMPOSETPLFILENAME=docker-compose.tpl
|
||||
DOCKERCOMPOSEFILENAME=docker-compose.yml
|
||||
DOCKERCOMPOSENOTARYFILENAME=docker-compose.notary.yml
|
||||
|
||||
# version prepare
|
||||
VERSIONFILEPATH=$(CURDIR)
|
||||
VERSIONFILENAME=VERSION
|
||||
GITCMD=$(shell which git)
|
||||
GITTAG=$(GITCMD) describe --tags
|
||||
GITTAGVERSION=$(shell git describe --tags || echo UNKNOWN)
|
||||
ifeq ($(DEVFLAG), true)
|
||||
VERSIONTAG=dev
|
||||
else
|
||||
VERSIONTAG=$(GITTAGVERSION)
|
||||
endif
|
||||
|
||||
SEDCMD=$(shell which sed)
|
||||
|
||||
# package
|
||||
TARCMD=$(shell which tar)
|
||||
ZIPCMD=$(shell which gzip)
|
||||
DOCKERIMGFILE=harbor
|
||||
HARBORPKG=harbor
|
||||
|
||||
# pushimage
|
||||
PUSHSCRIPTPATH=$(MAKEPATH)
|
||||
PUSHSCRIPTNAME=pushimage.sh
|
||||
REGISTRYUSER=user
|
||||
REGISTRYPASSWORD=default
|
||||
|
||||
version:
|
||||
@printf $(GITTAGVERSION) > $(VERSIONFILEPATH)/$(VERSIONFILENAME);
|
||||
|
||||
check_environment:
|
||||
@$(MAKEPATH)/$(CHECKENVCMD)
|
||||
|
||||
compile_adminserver:
|
||||
@echo "compiling binary for adminserver..."
|
||||
@$(GOBUILD) -o $(ADMINSERVERBINARYPATH)/$(ADMINSERVERBINARYNAME) $(ADMINSERVERSOURCECODE)
|
||||
@echo "Done."
|
||||
|
||||
compile_ui:
|
||||
@echo "compiling binary for ui..."
|
||||
@$(GOBUILD) -o $(UIBINARYPATH)/$(UIBINARYNAME) $(UISOURCECODE)
|
||||
@echo "Done."
|
||||
|
||||
compile_jobservice:
|
||||
@echo "compiling binary for jobservice..."
|
||||
@$(GOBUILD) -o $(JOBSERVICEBINARYPATH)/$(JOBSERVICEBINARYNAME) $(JOBSERVICESOURCECODE)
|
||||
@echo "Done."
|
||||
|
||||
compile_clarity:
|
||||
@echo "compiling binary for clarity ui..."
|
||||
@if [ "$(HTTPPROXY)" != "" ] ; then \
|
||||
$(DOCKERCMD) run --rm -v $(UIPATH)/static:$(CLARITYSEEDPATH)/dist -v $(UINGPATH)/src:$(CLARITYSEEDPATH)/src $(CLARITYIMAGE) $(SHELL) $(CLARITYBUILDSCRIPT) -p $(HTTPPROXY); \
|
||||
else \
|
||||
$(DOCKERCMD) run --rm -v $(UIPATH)/static:$(CLARITYSEEDPATH)/dist -v $(UINGPATH)/src:$(CLARITYSEEDPATH)/src $(CLARITYIMAGE) $(SHELL) $(CLARITYBUILDSCRIPT); \
|
||||
fi
|
||||
@echo "Done."
|
||||
|
||||
compile_normal: compile_clarity compile_adminserver compile_ui compile_jobservice
|
||||
|
||||
compile_golangimage: compile_clarity
|
||||
@echo "compiling binary for adminserver (golang image)..."
|
||||
@echo $(GOBASEPATH)
|
||||
@echo $(GOBUILDPATH)
|
||||
@$(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_ADMINSERVER) $(GOBUILDIMAGE) $(GOIMAGEBUILD) -v -o $(GOBUILDMAKEPATH_ADMINSERVER)/$(ADMINSERVERBINARYNAME)
|
||||
@echo "Done."
|
||||
|
||||
@echo "compiling binary for ui (golang image)..."
|
||||
@echo $(GOBASEPATH)
|
||||
@echo $(GOBUILDPATH)
|
||||
@$(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_UI) $(GOBUILDIMAGE) $(GOIMAGEBUILD) -v -o $(GOBUILDMAKEPATH_UI)/$(UIBINARYNAME)
|
||||
@echo "Done."
|
||||
|
||||
@echo "compiling binary for jobservice (golang image)..."
|
||||
@$(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_JOBSERVICE) $(GOBUILDIMAGE) $(GOIMAGEBUILD) -v -o $(GOBUILDMAKEPATH_JOBSERVICE)/$(JOBSERVICEBINARYNAME)
|
||||
@echo "Done."
|
||||
|
||||
compile:check_environment $(COMPILETAG)
|
||||
|
||||
prepare:
|
||||
@echo "preparing..."
|
||||
@if [ "$(NOTARYFLAG)" = "true" ] ; then \
|
||||
$(MAKEPATH)/$(PREPARECMD) --conf $(CONFIGPATH)/$(CONFIGFILE) --with-notary; \
|
||||
else \
|
||||
$(MAKEPATH)/$(PREPARECMD) --conf $(CONFIGPATH)/$(CONFIGFILE) ; \
|
||||
fi
|
||||
|
||||
build_common: version
|
||||
@echo "buildging db container for photon..."
|
||||
@cd $(DOCKERFILEPATH_DB) && $(DOCKERBUILD) -f $(DOCKERFILENAME_DB) -t $(DOCKERIMAGENAME_DB):$(VERSIONTAG) .
|
||||
@echo "Done."
|
||||
|
||||
build_photon: build_common
|
||||
make -f $(MAKEFILEPATH_PHOTON)/Makefile build -e DEVFLAG=$(DEVFLAG)
|
||||
|
||||
build: build_$(BASEIMAGE)
|
||||
|
||||
modify_composefile:
|
||||
@echo "preparing docker-compose file..."
|
||||
@cp $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSETPLFILENAME) $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSEFILENAME)
|
||||
@$(SEDCMD) -i 's/__version__/$(VERSIONTAG)/g' $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSEFILENAME)
|
||||
|
||||
modify_sourcefiles:
|
||||
@echo "change mode of source files."
|
||||
@chmod 600 $(MAKEPATH)/common/templates/notary/notary-signer.key
|
||||
@chmod 600 $(MAKEPATH)/common/templates/notary/notary-signer.crt
|
||||
@chmod 600 $(MAKEPATH)/common/templates/notary/notary-signer-ca.crt
|
||||
@chmod 600 $(MAKEPATH)/common/templates/ui/private_key.pem
|
||||
@chmod 600 $(MAKEPATH)/common/templates/registry/root.crt
|
||||
|
||||
install: compile build modify_sourcefiles prepare modify_composefile start
|
||||
|
||||
package_online: modify_composefile
|
||||
@echo "packing online package ..."
|
||||
@cp -r make $(HARBORPKG)
|
||||
@if [ -n "$(REGISTRYSERVER)" ] ; then \
|
||||
$(SEDCMD) -i 's/image\: vmware/image\: $(REGISTRYSERVER)\/$(REGISTRYPROJECTNAME)/' \
|
||||
$(HARBORPKG)/docker-compose.yml ; \
|
||||
fi
|
||||
@cp LICENSE $(HARBORPKG)/LICENSE
|
||||
@cp NOTICE $(HARBORPKG)/NOTICE
|
||||
|
||||
@if [ "$(NOTARYFLAG)" = "true" ] ; then \
|
||||
$(TARCMD) -zcvf harbor-online-installer-$(GITTAGVERSION).tgz \
|
||||
$(HARBORPKG)/common/templates $(HARBORPKG)/prepare \
|
||||
$(HARBORPKG)/LICENSE $(HARBORPKG)/NOTICE \
|
||||
$(HARBORPKG)/install.sh $(HARBORPKG)/$(DOCKERCOMPOSEFILENAME) \
|
||||
$(HARBORPKG)/harbor.cfg $(HARBORPKG)/$(DOCKERCOMPOSENOTARYFILENAME); \
|
||||
else \
|
||||
$(TARCMD) -zcvf harbor-online-installer-$(GITTAGVERSION).tgz \
|
||||
$(HARBORPKG)/common/templates $(HARBORPKG)/prepare \
|
||||
$(HARBORPKG)/LICENSE $(HARBORPKG)/NOTICE \
|
||||
$(HARBORPKG)/install.sh $(HARBORPKG)/$(DOCKERCOMPOSEFILENAME) \
|
||||
$(HARBORPKG)/harbor.cfg ; \
|
||||
fi
|
||||
|
||||
@rm -rf $(HARBORPKG)
|
||||
@echo "Done."
|
||||
|
||||
package_offline: compile build modify_sourcefiles modify_composefile
|
||||
@echo "packing offline package ..."
|
||||
@cp -r make $(HARBORPKG)
|
||||
|
||||
@cp LICENSE $(HARBORPKG)/LICENSE
|
||||
@cp NOTICE $(HARBORPKG)/NOTICE
|
||||
|
||||
@echo "pulling nginx and registry..."
|
||||
@$(DOCKERPULL) vmware/registry:$(REGISTRYVERSION)
|
||||
@$(DOCKERPULL) vmware/nginx:$(NGINXVERSION)
|
||||
@if [ "$(NOTARYFLAG)" = "true" ] ; then \
|
||||
echo "pulling notary and harbor-notary-db..."; \
|
||||
$(DOCKERPULL) vmware/notary-photon:$(NOTARYVERSION); \
|
||||
$(DOCKERPULL) vmware/notary-photon:$(NOTARYSIGNERVERSION); \
|
||||
$(DOCKERPULL) vmware/harbor-notary-db:$(MARIADBVERSION); \
|
||||
fi
|
||||
|
||||
@echo "saving harbor docker image"
|
||||
@if [ "$(NOTARYFLAG)" = "true" ] ; then \
|
||||
$(DOCKERSAVE) $(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_UI):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_LOG):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_DB):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) \
|
||||
vmware/nginx:$(NGINXVERSION) vmware/registry:$(REGISTRYVERSION) photon:$(PHOTONVERSION) \
|
||||
vmware/notary-photon:$(NOTARYVERSION) vmware/notary-photon:$(NOTARYSIGNERVERSION) \
|
||||
vmware/harbor-notary-db:$(MARIADBVERSION) | gzip > $(HARBORPKG)/$(DOCKERIMGFILE).$(VERSIONTAG).tar.gz; \
|
||||
else \
|
||||
$(DOCKERSAVE) $(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_UI):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_LOG):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_DB):$(VERSIONTAG) \
|
||||
$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) \
|
||||
vmware/nginx:$(NGINXVERSION) vmware/registry:$(REGISTRYVERSION) \
|
||||
photon:$(PHOTONVERSION) | gzip > $(HARBORPKG)/$(DOCKERIMGFILE).$(VERSIONTAG).tar.gz; \
|
||||
fi
|
||||
|
||||
@if [ "$(NOTARYFLAG)" = "true" ] ; then \
|
||||
$(TARCMD) -zcvf harbor-offline-installer-$(GITTAGVERSION).tgz \
|
||||
$(HARBORPKG)/common/templates $(HARBORPKG)/$(DOCKERIMGFILE).$(VERSIONTAG).tar.gz \
|
||||
$(HARBORPKG)/prepare $(HARBORPKG)/NOTICE \
|
||||
$(HARBORPKG)/LICENSE $(HARBORPKG)/install.sh \
|
||||
$(HARBORPKG)/harbor.cfg $(HARBORPKG)/$(DOCKERCOMPOSEFILENAME) \
|
||||
$(HARBORPKG)/$(DOCKERCOMPOSENOTARYFILENAME) ; \
|
||||
else \
|
||||
$(TARCMD) -zcvf harbor-offline-installer-$(GITTAGVERSION).tgz \
|
||||
$(HARBORPKG)/common/templates $(HARBORPKG)/$(DOCKERIMGFILE).$(VERSIONTAG).tar.gz \
|
||||
$(HARBORPKG)/prepare $(HARBORPKG)/NOTICE \
|
||||
$(HARBORPKG)/LICENSE $(HARBORPKG)/install.sh \
|
||||
$(HARBORPKG)/harbor.cfg $(HARBORPKG)/$(DOCKERCOMPOSEFILENAME) ; \
|
||||
fi
|
||||
|
||||
@rm -rf $(HARBORPKG)
|
||||
@echo "Done."
|
||||
|
||||
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_UI):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG)
|
||||
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG) \
|
||||
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER)
|
||||
@$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG)
|
||||
|
||||
@$(DOCKERTAG) $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG)
|
||||
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) \
|
||||
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER)
|
||||
@$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG)
|
||||
|
||||
@$(DOCKERTAG) $(DOCKERIMAGENAME_LOG):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_LOG):$(VERSIONTAG)
|
||||
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_LOG):$(VERSIONTAG) \
|
||||
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER)
|
||||
@$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_LOG):$(VERSIONTAG)
|
||||
|
||||
@$(DOCKERTAG) $(DOCKERIMAGENAME_DB):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_DB):$(VERSIONTAG)
|
||||
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_DB):$(VERSIONTAG) \
|
||||
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER)
|
||||
@$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_DB):$(VERSIONTAG)
|
||||
|
||||
start:
|
||||
@echo "loading harbor images..."
|
||||
@if [ "$(NOTARYFLAG)" = "true" ] ; then \
|
||||
$(DOCKERCOMPOSECMD) -f $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSEFILENAME) -f $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSENOTARYFILENAME) up -d ; \
|
||||
else \
|
||||
$(DOCKERCOMPOSECMD) -f $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSEFILENAME) up -d ; \
|
||||
fi
|
||||
@echo "Start complete. You can visit harbor now."
|
||||
|
||||
down:
|
||||
@echo "Please make sure to set -e NOTARYFLAG=true if you are using Notary in Harbor, otherwise the Notary containers cannot be stop automaticlly."
|
||||
@while [ -z "$$CONTINUE" ]; do \
|
||||
read -r -p "Type anything but Y or y to exit. [Y/N]: " CONTINUE; \
|
||||
done ; \
|
||||
[ $$CONTINUE = "y" ] || [ $$CONTINUE = "Y" ] || (echo "Exiting."; exit 1;)
|
||||
@echo "stoping harbor instance..."
|
||||
@if [ "$(NOTARYFLAG)" = "true" ] ; then \
|
||||
$(DOCKERCOMPOSECMD) -f $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSEFILENAME) -f $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSENOTARYFILENAME) down -v ; \
|
||||
else \
|
||||
$(DOCKERCOMPOSECMD) -f $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSEFILENAME) down -v ; \
|
||||
fi
|
||||
@echo "Done."
|
||||
|
||||
cleanbinary:
|
||||
@echo "cleaning binary..."
|
||||
@if [ -f $(ADMINSERVERBINARYPATH)/$(ADMINSERVERBINARYNAME) ] ; then rm $(ADMINSERVERBINARYPATH)/$(ADMINSERVERBINARYNAME) ; fi
|
||||
@if [ -f $(UIBINARYPATH)/$(UIBINARYNAME) ] ; then rm $(UIBINARYPATH)/$(UIBINARYNAME) ; fi
|
||||
@if [ -f $(JOBSERVICEBINARYPATH)/$(JOBSERVICEBINARYNAME) ] ; then rm $(JOBSERVICEBINARYPATH)/$(JOBSERVICEBINARYNAME) ; fi
|
||||
|
||||
cleanimage:
|
||||
@echo "cleaning image for photon..."
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG)
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_UI):$(VERSIONTAG)
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_DB):$(VERSIONTAG)
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG)
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_LOG):$(VERSIONTAG)
|
||||
# - $(DOCKERRMIMAGE) -f registry:$(REGISTRYVERSION)
|
||||
# - $(DOCKERRMIMAGE) -f nginx:1.11.5
|
||||
|
||||
cleandockercomposefile:
|
||||
@echo "cleaning $(DOCKERCOMPOSEFILEPATH)/docker-compose.yml"
|
||||
@if [ -f $(DOCKERCOMPOSEFILEPATH)/docker-compose.yml ] ; then rm $(DOCKERCOMPOSEFILEPATH)/docker-compose.yml ; fi
|
||||
|
||||
cleanversiontag:
|
||||
@echo "cleaning version TAG"
|
||||
@rm -rf $(VERSIONFILEPATH)/$(VERSIONFILENAME)
|
||||
|
||||
cleanpackage:
|
||||
@echo "cleaning harbor install package"
|
||||
@if [ -d $(BUILDPATH)/harbor ] ; then rm -rf $(BUILDPATH)/harbor ; fi
|
||||
@if [ -f $(BUILDPATH)/harbor-online-installer-$(GITTAGVERSION).tgz ] ; \
|
||||
then rm $(BUILDPATH)/harbor-online-installer-$(GITTAGVERSION).tgz ; fi
|
||||
@if [ -f $(BUILDPATH)/harbor-offline-installer-$(GITTAGVERSION).tgz ] ; \
|
||||
then rm $(BUILDPATH)/harbor-offline-installer-$(GITTAGVERSION).tgz ; fi
|
||||
|
||||
.PHONY: cleanall
|
||||
cleanall: cleanbinary cleanimage cleandockercomposefile cleanversiontag cleanpackage
|
||||
|
||||
clean:
|
||||
@echo " make cleanall: remove binary, Harbor images, specific version docker-compose"
|
||||
@echo " file, specific version tag, online and offline install package"
|
||||
@echo " make cleanbinary: remove ui and jobservice binary"
|
||||
@echo " make cleanimage: remove Harbor images"
|
||||
@echo " make cleandockercomposefile: remove specific version docker-compose"
|
||||
@echo " make cleanversiontag: cleanpackageremove specific version tag"
|
||||
@echo " make cleanpackage: remove online and offline install package"
|
||||
|
||||
all: install
|
||||
|
4
NOTICE
@ -1,8 +1,8 @@
|
||||
NOTICE
|
||||
|
||||
Harbor version 0.5.0 GA
|
||||
Harbor 1.1.0
|
||||
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License"). You may not use this product except in compliance with the License.
|
||||
|
||||
|
10
README.md
@ -3,6 +3,9 @@
|
||||
[![Build Status](https://travis-ci.org/vmware/harbor.svg?branch=master)](https://travis-ci.org/vmware/harbor)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/vmware/harbor/badge.svg?branch=dev)](https://coveralls.io/github/vmware/harbor?branch=dev)
|
||||
|
||||
**Note**: The `master` branch may be in an *unstable or even broken state* during development.
|
||||
Please use [releases] instead of the `master` branch in order to get stable binaries.
|
||||
|
||||
<img alt="Harbor" src="docs/img/harbor_logo.png">
|
||||
|
||||
Project Harbor is an enterprise-class registry server that stores and distributes Docker images. Harbor extends the open source Docker Distribution by adding the functionalities usually required by an enterprise, such as security, identity and management. As an enterprise private registry, Harbor offers better performance and security. Having a registry closer to the build and run environment improves the image transfer efficiency. Harbor supports the setup of multiple registries and has images replicated between them. In addition, Harbor offers advanced security features, such as user management, access control and activity auditing.
|
||||
@ -12,10 +15,11 @@ Project Harbor is an enterprise-class registry server that stores and distribute
|
||||
* **Policy based image replication**: Images can be replicated (synchronized) between multiple registry instances. Great for load balancing, high availability, multi-datacenter, hybrid and multi-cloud scenarios.
|
||||
* **LDAP/AD support**: Harbor integrates with existing enterprise LDAP/AD for user authentication and management.
|
||||
* **Image deletion & garbage collection**: Images can be deleted and their space can be recycled.
|
||||
* **Notary**: Image authenticity can be ensured.
|
||||
* **Graphical user portal**: User can easily browse, search repositories and manage projects.
|
||||
* **Auditing**: All the operations to the repositories are tracked.
|
||||
* **RESTful API**: RESTful APIs for most administrative operations, easy to integrate with external systems.
|
||||
* **Easy deployment**: Provide both an online and offline installer. Besides, a virtual appliance for vSphere platform (OVA) is available.
|
||||
* **Easy deployment**: Provide both an online and offline installer.
|
||||
|
||||
### Install & Run
|
||||
|
||||
@ -23,8 +27,6 @@ Project Harbor is an enterprise-class registry server that stores and distribute
|
||||
|
||||
**On a Linux host:** docker 1.10.0+ and docker-compose 1.6.0+ .
|
||||
|
||||
**On vSphere:** vCenter 5.5+ for deployment of Harbor's virtual appliance.
|
||||
|
||||
Download binaries of **[Harbor release ](https://github.com/vmware/harbor/releases)** and follow **[Installation & Configuration Guide](docs/installation_guide.md)** to install Harbor.
|
||||
|
||||
Refer to **[User Guide](docs/user_guide.md)** for more details on how to use Harbor.
|
||||
@ -44,6 +46,6 @@ Harbor is available under the [Apache 2 license](LICENSE).
|
||||
This project uses open source components which have additional licensing terms. The official docker images and licensing terms for these open source components can be found at the following locations:
|
||||
|
||||
* Photon OS 1.0: [docker image](https://hub.docker.com/_/photon/), [license](https://github.com/vmware/photon/blob/master/COPYING)
|
||||
* Docker Registry 2.5: [docker image](https://hub.docker.com/_/registry/), [license](https://github.com/docker/distribution/blob/master/LICENSE)
|
||||
* Docker Registry 2.6: [docker image](https://hub.docker.com/_/registry/), [license](https://github.com/docker/distribution/blob/master/LICENSE)
|
||||
* MySQL 5.6: [docker image](https://hub.docker.com/_/mysql/), [license](https://github.com/docker-library/mysql/blob/master/LICENSE)
|
||||
* NGINX 1.11.5: [docker image](https://hub.docker.com/_/nginx/), [license](https://github.com/nginxinc/docker-nginx/blob/master/LICENSE)
|
||||
|
28
ROADMAP.md
@ -20,28 +20,22 @@ The notary feature allows publishers to sign their images offline and to push th
|
||||
### 2. Vulnerability Scanning
|
||||
The capability to scan images for vulnerability.
|
||||
|
||||
### 3. Image replication between Harbor instances (Completed)
|
||||
Enable images to be replicated between two or more Harbor instances. This is useful to have multiple registry servers servicing a large cluster of nodes, or have distributed registry instances with identical images.
|
||||
### 3. Image replication enhancement
|
||||
To provide more sophisticated rule for image replication.
|
||||
- Image filtering by tags
|
||||
- Replication can be scheduled at a certain time using a rule like: one time only, daily, weekly, etc.
|
||||
- Image deletion can have the option not to be replicated to a remote instance.
|
||||
- Global replication rule: Instead of setting the rule of individual project, system admin can set a global rule for all projects.
|
||||
- Project admin can set replication policy of the project.
|
||||
|
||||
### 4. Image deletion and garbage collection (Completed)
|
||||
a) Images can be deleted from UI. The files of deleted images are not removed immediately.
|
||||
|
||||
b) The files of deleted images are recycled by an administrator during system maintenance(Garbage collection). The registry service must be shut down during the process of garbage collection.
|
||||
|
||||
|
||||
### 5. Authentication (OAuth2)
|
||||
### 4. Authentication (OAuth2)
|
||||
In addition to LDAP/AD and local users, OAuth 2.0 can be used to authenticate a user.
|
||||
|
||||
### 6. High Availability (in progress)
|
||||
### 5. High Availability
|
||||
Support multi-node deployment of Harbor for high availability, scalability and load-balancing purposes.
|
||||
|
||||
### 7. Statistics and description for repositories
|
||||
### 6. Statistics and description for repositories
|
||||
User can add a description to a repository. The access count of a repo can be aggregated and displayed.
|
||||
|
||||
|
||||
### 8. Audit all operations in the system
|
||||
Currently only image related operations are logged. Other operations in Harbor, such as user creation/deletion, role changes, password reset, should be tracked as well.
|
||||
|
||||
|
||||
### 9. Migration tool to move from an existing registry to Harbor
|
||||
### 7. Migration tool to move from an existing registry to Harbor
|
||||
A tool to migrate images from a vanilla registry server to Harbor, without the need to export/import a large amount of data.
|
||||
|
@ -6,9 +6,6 @@
|
||||
Read this first!**
|
||||
Guide for Harbor online installer and offline installer.
|
||||
|
||||
**[Installation and Configuration Guide for Virtual Appliance](installation_guide_ova.md)**
|
||||
Guide for installing Harbor on vSphere, either standalone or as part of vSphere Integrated Containers (VIC).
|
||||
|
||||
**[Harbor User Guide](user_guide.md)**
|
||||
How to use Harbor to manage images, projects, replications and users.
|
||||
|
||||
@ -57,11 +54,18 @@ How to add your local language to Harbor.
|
||||
|
||||
[Working with Harbor Registry REST API via Swagger](http://www.think-foundry.com/working-with-harbor-registry-rest-api-via-swagger/)
|
||||
|
||||
[How to use Harbor with Minio](https://blog.minio.io/how-to-use-vmware-harbor-with-minio-c07a5c4ae31b)
|
||||
|
||||
[Harbor, an enterprise class registry server](https://vorcunus.blog/2017/03/11/harbor-an-enterprise-class-registry-server/)
|
||||
|
||||
[Hybrid Container Management for vCloud Director with Harbor](https://blogs.vmware.com/vcat/2017/03/hybrid-container-management-vcloud-director-vmware-harbor.html)
|
||||
|
||||
[Project Harbor Reached Milestone of 2000 Stars](http://www.think-foundry.com/project-harbor-reaches-milestone-2000-stars-github/)
|
||||
|
||||
[Project Harbor in action](http://cormachogan.com/2016/08/05/project-harbor-action/)
|
||||
|
||||
[Using vSphere docker volume driver to run Project Harbor on VSAN](http://cormachogan.com/2016/07/29/using-vsphere-docker-volume-driver-run-project-harbor-vsan/)
|
||||
|
||||
|
||||
[Overall Architecture of Harbor Registry](http://www.compare-review-information.com/overall-architecture-of-harbor-registry/)
|
||||
|
||||
[Making a Private Secured Docker Registry in 15 Minutes](http://alexanderzeitler.com/articles/deploying-a-private-secured-docker-registry-within-15-minutes/)
|
||||
|
@ -1,21 +1,21 @@
|
||||
## Introduction
|
||||
|
||||
This guide provides instructions for developers to build and run Harbor from source code.
|
||||
This guide provides instructions for developers to build and run Harbor from source code.
|
||||
|
||||
## Step 1: Prepare for a build environment for Harbor
|
||||
|
||||
Harbor is deployed as several Docker containers and most of the code is written in Go language. The build host requires Python, Docker, Docker Compose and golang development environment. Please install the below prerequisites:
|
||||
Harbor is deployed as several Docker containers and most of the code is written in Go language. The build environment requires Python, Docker, Docker Compose and golang development environment. Please install the below prerequisites:
|
||||
|
||||
|
||||
Software | Required Version
|
||||
----------------------|--------------------------
|
||||
docker | 1.10.0 +
|
||||
docker-compose | 1.7.1 +
|
||||
docker | 1.12.0 +
|
||||
docker-compose | 1.11.0 +
|
||||
python | 2.7 +
|
||||
git | 1.9.1 +
|
||||
make | 3.81 +
|
||||
golang* | 1.6.0 +
|
||||
*optional
|
||||
golang* | 1.7.3 +
|
||||
*optional, required only if you use your own Golang environment.
|
||||
|
||||
|
||||
## Step 2: Getting the source code
|
||||
@ -24,52 +24,39 @@ golang* | 1.6.0 +
|
||||
$ git clone https://github.com/vmware/harbor
|
||||
```
|
||||
|
||||
## Step 3: Resolving dependencies of Go language
|
||||
You can compile the source code by using a Golang dev image. In this case, you can skip this step.
|
||||
|
||||
If you are building Harbor using your own Go compiling environment. You need to install LDAP packages manually.
|
||||
|
||||
For PhotonOS:
|
||||
|
||||
```sh
|
||||
$ tdnf install -y sed apr-util-ldap
|
||||
```
|
||||
|
||||
For Ubuntu:
|
||||
|
||||
```sh
|
||||
$ apt-get update && apt-get install -y libldap2-dev
|
||||
```
|
||||
|
||||
For other platforms, please consult the relevant documentation of installing LDAP package.
|
||||
|
||||
## Step 4: Building and installing Harbor
|
||||
## Step 3: Building and installing Harbor
|
||||
|
||||
### Configuration
|
||||
|
||||
Edit the file **make/harbor.cfg** and make necessary configuration changes such as hostname, admin password and mail server. Refer to **[Installation and Configuration Guide](installation_guide.md#configuring-harbor)** for more info.
|
||||
Edit the file **make/harbor.cfg** and make necessary configuration changes such as hostname, admin password and mail server. Refer to **[Installation and Configuration Guide](installation_guide.md#configuring-harbor)** for more info.
|
||||
|
||||
```sh
|
||||
$ cd harbor
|
||||
$ vi make/harbor.cfg
|
||||
```
|
||||
|
||||
|
||||
### Compiling and Running
|
||||
|
||||
You can compile the code by one of the three approaches:
|
||||
|
||||
#### I. Create a Golang dev image, then build Harbor
|
||||
#### I. Build with offical Golang image
|
||||
|
||||
* Build Golang dev image:
|
||||
* Get offcial Golang image from docker hub:
|
||||
|
||||
```sh
|
||||
$ make compile_buildgolangimage -e GOBUILDIMAGE=harborgo:1.6.2
|
||||
$ docker pull golang:1.7.3
|
||||
```
|
||||
|
||||
* Build, install and bring up Harbor:
|
||||
* Build, install and bring up Harbor without Notary:
|
||||
|
||||
```sh
|
||||
$ make install -e GOBUILDIMAGE=harborgo:1.6.2 COMPILETAG=compile_golangimage
|
||||
$ make install GOBUILDIMAGE=golang:1.7.3 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:0.8.4
|
||||
```
|
||||
|
||||
* Build, install and bring up Harbor with Notary:
|
||||
|
||||
```sh
|
||||
$ make install GOBUILDIMAGE=golang:1.7.3 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:0.8.4 NOTARYFLAG=true
|
||||
```
|
||||
|
||||
#### II. Compile code with your own Golang environment, then build Harbor
|
||||
@ -82,40 +69,27 @@ You can compile the code by one of the three approaches:
|
||||
$ mv harbor $GOPATH/src/github.com/vmware/.
|
||||
```
|
||||
|
||||
* Build, install and run Harbor
|
||||
* Build, install and run Harbor without Notary:
|
||||
|
||||
```sh
|
||||
$ cd $GOPATH/src/github.com/vmware/harbor
|
||||
$ make install
|
||||
```
|
||||
|
||||
#### III. Manual build process (compatible with previous versions)
|
||||
|
||||
* Build, install and run Harbor with Notary:
|
||||
|
||||
```sh
|
||||
$ cd make
|
||||
|
||||
$ ./prepare
|
||||
Generated configuration file: ./config/ui/env
|
||||
Generated configuration file: ./config/ui/app.conf
|
||||
Generated configuration file: ./config/registry/config.yml
|
||||
Generated configuration file: ./config/db/env
|
||||
...
|
||||
|
||||
$ cd dev
|
||||
|
||||
$ docker-compose up -d
|
||||
```
|
||||
$ cd $GOPATH/src/github.com/vmware/harbor
|
||||
$ make install -e NOTARYFLAG=true
|
||||
```
|
||||
|
||||
### Verify your installation
|
||||
|
||||
If everyting worked properly, you can get the below message:
|
||||
If everything worked properly, you can get the below message:
|
||||
|
||||
```sh
|
||||
...
|
||||
----Harbor has been installed and started successfully.----
|
||||
|
||||
Now you should be able to visit the admin portal at http://$YOURIP.
|
||||
For more details, please visit https://github.com/vmware/harbor .
|
||||
Start complete. You can visit harbor now.
|
||||
```
|
||||
|
||||
Refer to [Installation and Configuration Guide](installation_guide.md#managing-harbors-lifecycle) for more information about managing your Harbor instance.
|
||||
@ -128,8 +102,11 @@ The `Makefile` contains these configurable parameters:
|
||||
Variable | Description
|
||||
-------------------|-------------
|
||||
BASEIMAGE | Container base image, default: photon
|
||||
CLARITYIMAGE | Clarity UI builder image, default: harbor-clarity-ui-builder
|
||||
DEVFLAG | Build model flag, default: dev
|
||||
COMPILETAG | Compile model flag, default: compile_normal (local golang build)
|
||||
NOTARYFLAG | Notary mode flag, default: false
|
||||
HTTPPROXY | NPM http proxy for Clarity UI builder
|
||||
REGISTRYSERVER | Remote registry server IP address
|
||||
REGISTRYUSER | Remote registry server user name
|
||||
REGISTRYPASSWORD | Remote registry server user password
|
||||
@ -139,44 +116,29 @@ REGISTRYPROJECTNAME| Project name on remote registry server
|
||||
|
||||
Target | Description
|
||||
--------------------|-------------
|
||||
all | prepare env, compile binaries, build images and install images
|
||||
all | prepare env, compile binaries, build images and install images
|
||||
prepare | prepare env
|
||||
compile | compile ui and jobservice code
|
||||
compile_golangimage | compile local golang image
|
||||
compile_ui | compile ui binary
|
||||
compile_jobservice | compile jobservice binary
|
||||
compile_clarity | compile Clarity binary
|
||||
build | build Harbor docker images (default: using build_photon)
|
||||
build_photon | build Harbor docker images from Photon OS base image
|
||||
build_ubuntu | build Harbor docker images from Ubuntu base image
|
||||
install | compile binaries, build images, prepare specific version of compose file and startup Harbor instance
|
||||
start | startup Harbor instance
|
||||
down | shutdown Harbor instance
|
||||
start | startup Harbor instance (set NOTARYFLAG=true when with Notary)
|
||||
down | shutdown Harbor instance (set NOTARYFLAG=true when with Notary)
|
||||
package_online | prepare online install package
|
||||
package_offline | prepare offline install package
|
||||
pushimage | push Harbor images to specific registry server
|
||||
clean all | remove binary, Harbor images, specific version docker-compose file, specific version tag and online/offline install package
|
||||
cleanbinary | remove ui and jobservice binary
|
||||
cleanimage | remove Harbor images
|
||||
cleandockercomposefile | remove specific version docker-compose
|
||||
cleanimage | remove Harbor images
|
||||
cleandockercomposefile | remove specific version docker-compose
|
||||
cleanversiontag | remove specific version tag
|
||||
cleanpackage | remove online/offline install package
|
||||
|
||||
#### EXAMPLE:
|
||||
|
||||
#### Build a golang dev image (for building Harbor):
|
||||
|
||||
```sh
|
||||
$ make compile_golangimage -e GOBUILDIMAGE= [$YOURIMAGE]
|
||||
|
||||
```
|
||||
|
||||
#### Build Harbor images based on Ubuntu
|
||||
|
||||
```sh
|
||||
$ make build -e BASEIMAGE=ubuntu
|
||||
|
||||
```
|
||||
|
||||
#### Push Harbor images to specific registry server
|
||||
|
||||
```sh
|
||||
@ -198,7 +160,7 @@ cleanpackage | remove online/offline install package
|
||||
$ make clean -e VERSIONTAG=[TAG]
|
||||
|
||||
```
|
||||
**Note**: If new code had been added to Github, the git commit TAG will change. Better use this command to clean up images and files of previous TAG.
|
||||
**Note**: If new code had been added to Github, the git commit TAG will change. Better use this command to clean up images and files of previous TAG.
|
||||
|
||||
#### By default, the make process create a development build. To create a release build of Harbor, set the below flag to false.
|
||||
|
||||
@ -206,4 +168,3 @@ cleanpackage | remove online/offline install package
|
||||
$ make XXXX -e DEVFLAG=false
|
||||
|
||||
```
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
#Configuring Harbor with HTTPS Access
|
||||
# Configuring Harbor with HTTPS Access
|
||||
|
||||
Because Harbor does not ship with any certificates, it uses HTTP by default to serve registry requests. However, it is highly recommended that security be enabled for any production environment. Harbor has an Nginx instance as a reverse proxy for all services, you can use the prepare script to configure Nginx to enable https.
|
||||
|
||||
##Getting a certificate
|
||||
## Getting a certificate
|
||||
|
||||
Assuming that your registry's **hostname** is **reg.yourdomain.com**, and that its DNS record points to the host where you are running Harbor. You first should get a certificate from a CA. The certificate usually contains a .crt file and a .key file, for example, **yourdomain.com.crt** and **yourdomain.com.key**.
|
||||
|
||||
@ -40,7 +40,7 @@ If you're using **IP**, say **192.168.1.101** to connect your registry host, you
|
||||
openssl x509 -req -days 365 -in yourdomain.com.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extfile extfile.cnf -out yourdomain.com
|
||||
.crt
|
||||
```
|
||||
##Configuration and Installation
|
||||
## Configuration and Installation
|
||||
After obtaining the **yourdomain.com.crt** and **yourdomain.com.key** files,
|
||||
you can put them into directory such as ```/root/cert/```:
|
||||
|
||||
@ -95,7 +95,7 @@ If you've mapped nginx 443 port to another, you need to add the port to login, l
|
||||
docker login reg.yourdomain.com:port
|
||||
```
|
||||
|
||||
##Troubleshooting
|
||||
## Troubleshooting
|
||||
1. You may get an intermediate certificate from a certificate issuer. In this case, you should merge the intermediate certificate with your own certificate to create a certificate bundle. You can achieve this by the below command:
|
||||
|
||||
```
|
||||
|
@ -1,4 +1,4 @@
|
||||
#Customize Harbor token service with your key and certificate
|
||||
# Customize Harbor token service with your key and certificate
|
||||
|
||||
Harbor requires Docker client to access the Harbor registry with a token. The procedure to generate a token is like [Docker Registry v2 authentication](https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md). Firstly, you should make a request to the token service for a token. The token is signed by the private key. After that, you make a new request with the token to the Harbor registry, Harbor registry will verify the token with the public key in the rootcert bundle. Then Harbor registry will authorize the Docker client to push/pull images.
|
||||
|
||||
|
@ -4,57 +4,55 @@
|
||||
|
||||
### Steps to localize the UI in your language
|
||||
|
||||
1. Copy the file `static/resources/js/services/i18n/locale_messages_en-US.js` to a new file in the same directory named `locale_messages_<language>_<locale>.js` .
|
||||
1. In the folder `src/ui_ng/src/i18n/lang`, copy json file `en-us-lang.json` to a new file and rename it to `<language>-<locale>-lang.json` .
|
||||
|
||||
The file contains a JSON object named `locale_messages`, which consists of key-value pairs of UI strings:
|
||||
The file contains a JSON object including all the key-value pairs of UI strings:
|
||||
```
|
||||
var local_messages = {
|
||||
'sign_in': 'Sign In',
|
||||
'sign_up': 'Sign Up',
|
||||
...
|
||||
};
|
||||
{
|
||||
"APP_TITLE": {
|
||||
"VMW_HARBOR": "VMware Harbor",
|
||||
"HARBOR": "Harbor",
|
||||
...
|
||||
},
|
||||
...
|
||||
}
|
||||
```
|
||||
In the file `locale_messages_<language>_<locale>.js`, translate all the values into your language. Do not change any keys.
|
||||
In the file `<language>-<locale>-lang.json`, translate all the values into your language. Do not change any keys.
|
||||
|
||||
2. After creating your locale file, you should include it from the HTML page header template.
|
||||
2. After creating your language file, you should add it to the language supporting list.
|
||||
|
||||
In the file `views/sections/header-include.htm`, look for a `if` statement which switch langauges based on the current language (`.Lang`) value. Add in a `else if` statement for your language:
|
||||
Locate the file `src/ui_ng/src/app/shared/shared.const.ts`.
|
||||
Append `<language>-<locale>` to the language supporting list:
|
||||
```
|
||||
{{ if eq .Lang "zh-CN" }}
|
||||
<script src="/static/resources/js/services/i18n/locale_messages_zh-CN.js"></script>
|
||||
{{ else if eq .Lang "en-US"}}
|
||||
<script src="/static/resources/js/services/i18n/locale_messages_en-US.js"></script>
|
||||
{{ else if eq .Lang "<language>-<locale>"}}
|
||||
<script src="/static/resources/js/services/i18n/locale_messages_<language>-<locale>.js"></script>
|
||||
{{ end }}
|
||||
export const supportedLangs = ['en-us', 'zh-cn', '<language>-<locale>'];
|
||||
```
|
||||
Define the language display name and append it to the name list:
|
||||
```
|
||||
export const languageNames = {
|
||||
"en-us": "English",
|
||||
"zh-cn": "中文简体",
|
||||
"<language>-<locale>": "<DISPLAY_NAME>"
|
||||
};
|
||||
```
|
||||
3. Add the new language to the `I18nService` module.
|
||||
|
||||
In the file `static/resources/js/services/i18n/services.i18n.js`, append a new key-value item to the `supportLanguages` object. This value will be displayed in the language dropdown list in the UI.
|
||||
```
|
||||
var supportLanguages = {
|
||||
'en-US': 'English',
|
||||
'zh-CN': '中文',
|
||||
'<language>-<locale>': '<language_name>'
|
||||
};
|
||||
```
|
||||
**NOTE: Don't miss the comma before the new key-value item you've added.**
|
||||
|
||||
3. Enable the new language in the view.
|
||||
|
||||
4. In the directory `static/i18n/`, copy the file `locale_en-US.ini` to a new file named `locale_<language>-<locale>.ini`. In this file, translate all the values on the right hand side into your language. Do not change any keys.
|
||||
|
||||
5. Add the new language to the `app.conf` file.
|
||||
|
||||
In the file `make/common/templates/ui/app.conf`, append a new item to the configuration section.
|
||||
Locate the file `src/ui_ng/src/app/base/navigator/navigator.component.html` and then find the following code piece:
|
||||
```
|
||||
[lang]
|
||||
types = en-US|zh-CN|<language>-<locale>
|
||||
names = en-US|zh-CN|<language>-<locale>
|
||||
<div class="dropdown-menu">
|
||||
<a href="javascript:void(0)" clrDropdownItem (click)='switchLanguage("en-us")' [class.lang-selected]='matchLang("en-us")'>English</a>
|
||||
<a href="javascript:void(0)" clrDropdownItem (click)='switchLanguage("zh-cn")' [class.lang-selected]='matchLang("zh-cn")'>中文简体</a>
|
||||
</div>
|
||||
```
|
||||
Add new menu item for your language:
|
||||
```
|
||||
<div class="dropdown-menu">
|
||||
<a href="javascript:void(0)" clrDropdownItem (click)='switchLanguage("en-us")' [class.lang-selected]='matchLang("en-us")'>English</a>
|
||||
<a href="javascript:void(0)" clrDropdownItem (click)='switchLanguage("zh-cn")' [class.lang-selected]='matchLang("zh-cn")'>中文简体</a>
|
||||
<a href="javascript:void(0)" clrDropdownItem (click)='switchLanguage("<language>-<locale>")' [class.lang-selected]='matchLang("<language>-<locale>")'>DISPLAY_NAME</a>
|
||||
</div>
|
||||
```
|
||||
|
||||
6. Next, change to `make/` directory, rebuild and restart the Harbor by the below command:
|
||||
```
|
||||
docker-compose down
|
||||
docker-compose up --build -d
|
||||
```
|
||||
|
||||
4. Next, please refer [compile guideline](compile_guide.md) to rebuild and restart Harbor.
|
||||
|
@ -1,102 +0,0 @@
|
||||
# Expand the Hard Disk of Virtual Appliance
|
||||
|
||||
If you install Harbor with OVA, the persistent data(such as images and database) is stored in a hard disk which is mounted on directory "/data", and the default size is 50GB. As more and more images are pushed into it, the capacity may not meet your requirements.
|
||||
|
||||
You can check the space on Harbor web UI by clicking on the admin's name at the upper left corner and selecting "About" from the drop-down menu if you log in with an admin user:
|
||||
|
||||
![lvm](img/lvm/check_on_ui_01.png)
|
||||
|
||||
If your free space is running out, you can expand the size of the hard disk by the following steps:
|
||||
|
||||
1. Add New Hard Disk to VM
|
||||
|
||||
(1) Log in vSphere web client. Power off Harbor's virtual appliance.
|
||||
(2) Right click on the VM and select "Edit Settings".
|
||||
(3) Select "New Hard Disk", and click "OK".
|
||||
|
||||
![lvm](img/lvm/add_new_hard_disk.png)
|
||||
|
||||
We add a 10GB new hard disk to show the operations.
|
||||
|
||||
(4) Power on the VM.
|
||||
|
||||
2. Expand Hard Disk using LVM
|
||||
|
||||
Login from the console of the virtual appliance and run the following commands:
|
||||
|
||||
(1) Check the current size of "/data":
|
||||
```sh
|
||||
df -h /data
|
||||
```
|
||||
|
||||
![lvm](img/lvm/size_of_data_01.png)
|
||||
|
||||
(2) Find the new hard disk, e.g. "/dev/sdc". Replace all "/dev/sdc" with your disk in the following commands.
|
||||
```sh
|
||||
fdisk -l
|
||||
```
|
||||
|
||||
![lvm](img/lvm/find_the_new_harddisk.png)
|
||||
|
||||
(3) Create new physical volume:
|
||||
```sh
|
||||
pvcreate /dev/sdc
|
||||
```
|
||||
|
||||
(4) Check the volume group:
|
||||
```sh
|
||||
vgdisplay
|
||||
```
|
||||
|
||||
![lvm](img/lvm/vg_01.png)
|
||||
|
||||
(5) Expand the volume group:
|
||||
```sh
|
||||
vgextend data1_vg /dev/sdc
|
||||
```
|
||||
|
||||
(6) Check the volume group again:
|
||||
```sh
|
||||
vgdisplay
|
||||
```
|
||||
|
||||
![lvm](img/lvm/vg_02.png)
|
||||
|
||||
(7) Check the logical volume:
|
||||
```sh
|
||||
lvdisplay
|
||||
```
|
||||
|
||||
![lvm](img/lvm/lv_01.png)
|
||||
|
||||
(8) Resize the logical volume:
|
||||
```sh
|
||||
lvresize -l +100%FREE /dev/data1_vg/data
|
||||
```
|
||||
|
||||
![lvm](img/lvm/resize_lv.png)
|
||||
|
||||
(9) Check the logical volume again, note the change of "LV Size":
|
||||
```sh
|
||||
lvdisplay
|
||||
```
|
||||
|
||||
![lvm](img/lvm/lv_02.png)
|
||||
|
||||
(10) Resize the file system:
|
||||
```sh
|
||||
resize2fs /dev/data1_vg/data
|
||||
```
|
||||
|
||||
(11) Check the size "/data" again:
|
||||
```sh
|
||||
df -h /data
|
||||
```
|
||||
|
||||
![lvm](img/lvm/size_of_data_02.png)
|
||||
|
||||
You can also check the size on Harbor web UI:
|
||||
|
||||
![lvm](img/lvm/check_on_ui.png)
|
||||
|
||||
After that, your disk should be expanded successfully. If you want to add more hard disks, do the steps again.
|
BIN
docs/img/content_trust.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
docs/img/ldap_auth.png
Normal file
After Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 57 KiB |
BIN
docs/img/new_auth.png
Normal file
After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 51 KiB |
BIN
docs/img/new_config_email.png
Normal file
After Width: | Height: | Size: 61 KiB |
BIN
docs/img/new_config_token.png
Normal file
After Width: | Height: | Size: 47 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 74 KiB |
BIN
docs/img/new_create_rule.png
Normal file
After Width: | Height: | Size: 70 KiB |
BIN
docs/img/new_delete_repo.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
docs/img/new_delete_tag.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
docs/img/new_manage_endpoint.png
Normal file
After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 50 KiB |
BIN
docs/img/new_proj_create.png
Normal file
After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 67 KiB |
BIN
docs/img/new_remote_cert.png
Normal file
After Width: | Height: | Size: 54 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 52 KiB |
BIN
docs/img/new_rule_list.png
Normal file
After Width: | Height: | Size: 85 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 46 KiB |
BIN
docs/img/new_self_reg.png
Normal file
After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 54 KiB |
@ -1,21 +1,18 @@
|
||||
# Installation and Configuration Guide
|
||||
Harbor can be installed by one of three approaches:
|
||||
Harbor can be installed by one of two approaches:
|
||||
|
||||
- **Online installer:** The installer downloads Harbor's images from Docker hub. For this reason, the installer is very small in size.
|
||||
|
||||
- **Offline installer:** Use this installer when the host does not have an Internet connection. The installer contains pre-built images so its size is larger.
|
||||
|
||||
- **Virtual Appliance:** If you are installing Harbor as the registry component of vSphere Integrated Containers (VIC), or using Harbor as a standalone registry on vSphere platform, download the OVA version of Harbor.
|
||||
|
||||
All installers can be downloaded from the **[official release](https://github.com/vmware/harbor/releases)** page.
|
||||
|
||||
To install Harbor's virtual appliance, refer to the **[Harbor Installation Guide for Virtual Appliance](installation_guide_ova.md)**.
|
||||
|
||||
This guide describes the steps to install and configure Harbor by using the online or offline installer. The installation processes are almost the same.
|
||||
|
||||
If you run a previous version of Harbor, you may need to migrate the data to fit the new database schema. For more details, please refer to **[Data Migration Guide](migration_guide.md)**.
|
||||
|
||||
In addition, the deployment instructions on Kubernetes has been created by the community. Refer to set up [Harbor on Kubernetes](kubernetes_deployment.md) for details.
|
||||
In addition, the deployment instructions on Kubernetes has been created by the community. Refer to [Harbor on Kubernetes](kubernetes_deployment.md) for details.
|
||||
|
||||
## Prerequisites for the target host
|
||||
Harbor is deployed as several Docker containers, and, therefore, can be deployed on any Linux distribution that supports Docker. The target host requires Python, Docker, and Docker Compose to be installed.
|
||||
@ -47,17 +44,32 @@ Offline installer:
|
||||
|
||||
#### Configuring Harbor
|
||||
Configuration parameters are located in the file **harbor.cfg**.
|
||||
|
||||
There are two categories of parameters in harbor.cfg, **required parameters** and **optional parameters**.
|
||||
* **required parameters**: These parameters are required to be set in the configuration file, and they will take effect if a user updates them in harbor.cfg, rerun the ```install.sh``` script to reinstall Harbor.
|
||||
* **optional parameters**: These parameters are optional, and only take effect in the initial installation. The user can leave them blank and update them on Web UI after Harbor is started. Subsequent update to these parameters in ```harbor.cfg``` will be ignored.
|
||||
|
||||
The parameters are described below - note that at the very least, you will need to change the **hostname** attribute.
|
||||
|
||||
##### Required parameters:
|
||||
|
||||
* **hostname**: The target host's hostname, which is used to access the UI and the registry service. It should be the IP address or the fully qualified domain name (FQDN) of your target machine, e.g., `192.168.1.10` or `reg.yourdomain.com`. _Do NOT use `localhost` or `127.0.0.1` for the hostname - the registry service needs to be accessible by external clients!_
|
||||
* **ui_url_protocol**: (**http** or **https**. Default is **http**) The protocol used to access the UI and the token/notification service. By default, this is _http_. To set up the https protocol, refer to **[Configuring Harbor with HTTPS Access](configure_https.md)**.
|
||||
* **ui_url_protocol**: (**http** or **https**. Default is **http**) The protocol used to access the UI and the token/notification service. If Notary is enabled, this parameter has to be _https_. By default, this is _http_. To set up the https protocol, refer to **[Configuring Harbor with HTTPS Access](configure_https.md)**.
|
||||
* **db_password**: The root password for the MySQL database used for **db_auth**. _Change this password for any production use!_
|
||||
* **max_job_workers**: (default value is **3**) The maximum number of replication workers in job service. For each image replication job, a worker synchronizes all tags of a repository to the remote destination. Increasing this number allows more concurrent replication jobs in the system. However, since each worker consumes a certain amount of network/CPU/IO resources, please carefully pick the value of this attribute based on the hardware resource of the host.
|
||||
* **customize_crt**: (**on** or **off**. Default is **on**) When this attribute is **on**, the prepare script creates private key and root certificate for the generation/verification of the registry's token. Set this attribute to **off** when the key and root certificate are supplied by external sources. Refer to [Customize Key and Certificate of Harbor Token Service](customize_token_service.md) for more info.
|
||||
* **ssl_cert**: The path of SSL certificate, it's applied only when the protocol is set to https
|
||||
* **ssl_cert_key**: The path of SSL key, it's applied only when the protocol is set to https
|
||||
* **secretkey_path**: The path of key for encrypt or decrypt the password of a remote registry in a replication policy.
|
||||
|
||||
##### Optional parameters
|
||||
* **Email settings**: These parameters are needed for Harbor to be able to send a user a "password reset" email, and are only necessary if that functionality is needed. Also, do note that by default SSL connectivity is _not_ enabled - if your SMTP server requires SSL, but does _not_ support STARTTLS, then you should enable SSL by setting **email_ssl = true**.
|
||||
* email_server = smtp.mydomain.com
|
||||
* email_server_port = 25
|
||||
* email_username = sample_admin@mydomain.com
|
||||
* email_password = abc
|
||||
* email_from = `admin \<sample_admin@mydomain.com\>`
|
||||
* email_ssl = false
|
||||
* email_server = smtp.mydomain.com
|
||||
* email_server_port = 25
|
||||
* email_username = sample_admin@mydomain.com
|
||||
* email_password = abc
|
||||
* email_from = admin <sample_admin@mydomain.com>
|
||||
* email_ssl = false
|
||||
|
||||
* **harbor_admin_password**: The administrator's initial password. This password only takes effect for the first time Harbor launches. After that, this setting is ignored and the administrator's password should be set in the UI. _Note that the default username/password are **admin/Harbor12345** ._
|
||||
* **auth_mode**: The type of authentication that is used. By default, it is **db_auth**, i.e. the credentials are stored in a database. For LDAP authentication, set this to **ldap_auth**.
|
||||
@ -68,15 +80,10 @@ The parameters are described below - note that at the very least, you will need
|
||||
* **ldap_filter**:The search filter for looking up a user, e.g. `(objectClass=person)`.
|
||||
* **ldap_uid**: The attribute used to match a user during a LDAP search, it could be uid, cn, email or other attributes.
|
||||
* **ldap_scope**: The scope to search for a user, 1-LDAP_SCOPE_BASE, 2-LDAP_SCOPE_ONELEVEL, 3-LDAP_SCOPE_SUBTREE. Default is 3.
|
||||
* **db_password**: The root password for the MySQL database used for **db_auth**. _Change this password for any production use!_
|
||||
* **self_registration**: (**on** or **off**. Default is **on**) Enable / Disable the ability for a user to register themselves. When disabled, new users can only be created by the Admin user, only an admin user can create new users in Harbor. _NOTE: When **auth_mode** is set to **ldap_auth**, self-registration feature is **always** disabled, and this flag is ignored._
|
||||
* **use_compressed_js**: (**on** or **off**. Default is **on**) For production use, turn this flag to **on**. In development mode, set it to **off** so that js files can be modified separately.
|
||||
* **max_job_workers**: (default value is **3**) The maximum number of replication workers in job service. For each image replication job, a worker synchronizes all tags of a repository to the remote destination. Increasing this number allows more concurrent replication jobs in the system. However, since each worker consumes a certain amount of network/CPU/IO resources, please carefully pick the value of this attribute based on the hardware resource of the host.
|
||||
|
||||
* **self_registration**: (**on** or **off**. Default is **on**) Enable / Disable the ability for a user to register himself/herself. When disabled, new users can only be created by the Admin user, only an admin user can create new users in Harbor. _NOTE: When **auth_mode** is set to **ldap_auth**, self-registration feature is **always** disabled, and this flag is ignored._
|
||||
* **token_expiration**: The expiration time (in minutes) of a token created by token service, default is 30 minutes.
|
||||
|
||||
* **project_creation_restriction**: The flag to control what users have permission to create projects. By default everyone can create a project, set to "adminonly" such that only admin can create project.
|
||||
* **verify_remote_cert**: (**on** or **off**. Default is **on**) This flag determines whether or not to verify SSL/TLS certificate when Harbor communicates with a remote registry instance. Setting this attribute to **off** bypasses the SSL/TLS verification, which is often used when the remote instance has a self-signed or untrusted certificate.
|
||||
* **customize_crt**: (**on** or **off**. Default is **on**) When this attribute is **on**, the prepare script creates private key and root certificate for the generation/verification of the registry's token. The following attributes:**crt_country**, **crt_state**, **crt_location**, **crt_organization**, **crt_organizationalunit**, **crt_commonname**, **crt_email** are used as parameters for generating the keys. Set this attribute to **off** when the key and root certificate are supplied by external sources. Refer to [Customize Key and Certificate of Harbor Token Service](customize_token_service.md) for more info.
|
||||
|
||||
#### Configuring storage backend (optional)
|
||||
|
||||
@ -103,6 +110,9 @@ _NOTE: For detailed information on storage backend of a registry, refer to [Regi
|
||||
#### Finishing installation and starting Harbor
|
||||
Once **harbor.cfg** and storage backend (optional) are configured, install and start Harbor using the ```install.sh``` script. Note that it may take some time for the online installer to download Harbor images from Docker hub.
|
||||
|
||||
##### Default installation
|
||||
After version 1.1.0, Harbor has integrated with Notary, but by default the installation does not include notary support.
|
||||
|
||||
```sh
|
||||
$ sudo ./install.sh
|
||||
```
|
||||
@ -116,6 +126,16 @@ $ docker push reg.yourdomain.com/myproject/myrepo:mytag
|
||||
```
|
||||
**IMPORTANT:** The default installation of Harbor uses _HTTP_ - as such, you will need to add the option `--insecure-registry` to your client's Docker daemon and restart the Docker service.
|
||||
|
||||
##### Installation with Notary
|
||||
To install Harbor with Notary support, add a parameter when you run ```install.sh```
|
||||
```sh
|
||||
$ sudo ./install.sh --with-notary
|
||||
```
|
||||
**Note**: For installation with Notary the parameter "ui_url_protocol" must be set to "https", for configuring HTTPS certificate please refer to the following sections.
|
||||
|
||||
More information about Notary and Docker Content Trust, please refer to docker's documentation:
|
||||
https://docs.docker.com/engine/security/trust/content_trust/
|
||||
|
||||
For information on how to use Harbor, please refer to **[User Guide of Harbor](user_guide.md)** .
|
||||
|
||||
#### Configuring Harbor with HTTPS access
|
||||
@ -146,18 +166,17 @@ Starting registry ... done
|
||||
Starting proxy ... done
|
||||
```
|
||||
|
||||
To change Harbor's configuration, first stop existing Harbor instance, update harbor.cfg, and then run install.sh again:
|
||||
To change Harbor's configuration, first stop existing Harbor instance, update harbor.cfg, and then run prepare script to populate the configuration, and then re-create and start Harbor's instance:
|
||||
```
|
||||
$ sudo docker-compose down
|
||||
|
||||
$ sudo docker-compose down -v
|
||||
$ vim harbor.cfg
|
||||
|
||||
$ sudo install.sh
|
||||
$ sudo prepare
|
||||
$ sudo docker-compose up -d
|
||||
```
|
||||
|
||||
Removing Harbor's containers while keeping the image data and Harbor's database files on the file system:
|
||||
```
|
||||
$ sudo docker-compose down
|
||||
$ sudo docker-compose down -v
|
||||
```
|
||||
|
||||
Removing Harbor's database and image data (for a clean re-installation):
|
||||
@ -166,6 +185,20 @@ $ rm -r /data/database
|
||||
$ rm -r /data/registry
|
||||
```
|
||||
|
||||
#### _Managing lifecycle of Harbor when it's installed with Notary_
|
||||
|
||||
When Harbor is installed with Notary, user needs to add extra template file ```docker-compose.notary.yml``` to docker-compose command, so the docker-compose commands to manage the lifecycle of Harbor will be:
|
||||
```
|
||||
$ sudo docker-compose -f ./docker-compose.yml -f ./docker-compose.notary.yml [ up|down|ps|stop|start ]
|
||||
```
|
||||
For example, if user want's to change ```harbor.cfg``` and re-deploy Harbor when it's installed with Notary, the following commands should be used:
|
||||
```sh
|
||||
$ sudo docker-compose -f ./docker-compose.yml -f ./docker-compose.notary.yml down -v
|
||||
$ vim harbor.cfg
|
||||
$ sudo prepare --with-notary
|
||||
$ sudo docker-compose -f ./docker-compose.yml -f ./docker-compose.notary.yml up -d
|
||||
```
|
||||
|
||||
Please check the [Docker Compose command-line reference](https://docs.docker.com/compose/reference/) for more on docker-compose.
|
||||
|
||||
### Persistent data and log files
|
||||
@ -202,27 +235,17 @@ proxy:
|
||||
tag: "proxy"
|
||||
```
|
||||
|
||||
2.Modify templates/registry/config.yml
|
||||
Add the customized port, e.g. ":8888", after "$ui_url".
|
||||
2.Modify harbor.cfg, add the port to the parameter "hostname"
|
||||
|
||||
```
|
||||
auth:
|
||||
token:
|
||||
issuer: registry-token-issuer
|
||||
realm: $ui_url:8888/service/token
|
||||
rootcertbundle: /etc/registry/root.crt
|
||||
service: token-service
|
||||
hostname = 192.168.0.2:8888
|
||||
```
|
||||
|
||||
3.Run install.sh to update and start Harbor.
|
||||
```sh
|
||||
$ sudo docker-compose down
|
||||
$ sudo install.sh
|
||||
```
|
||||
3.Re-deploy Harbor refering to previous section "Managing Harbor's lifecycle".
|
||||
### For HTTPS protocol
|
||||
1.Enable HTTPS in Harbor by following this [guide](https://github.com/vmware/harbor/blob/master/docs/configure_https.md).
|
||||
2.Modify docker-compose.yml
|
||||
Replace the first "443" to a customized port, e.g. 4443:443.
|
||||
Replace the first "443" to a customized port, e.g. 8888:443.
|
||||
|
||||
```
|
||||
proxy:
|
||||
@ -232,7 +255,7 @@ proxy:
|
||||
- ./config/nginx:/etc/nginx
|
||||
ports:
|
||||
- 80:80
|
||||
- 4443:443
|
||||
- 8888:443
|
||||
depends_on:
|
||||
- mysql
|
||||
- registry
|
||||
@ -245,23 +268,14 @@ proxy:
|
||||
tag: "proxy"
|
||||
```
|
||||
|
||||
3.Modify templates/registry/config.yml
|
||||
Add the customized port, e.g. ":4443", after "$ui_url".
|
||||
3.Modify harbor.cfg, add the port to the parameter "hostname"
|
||||
|
||||
```
|
||||
auth:
|
||||
token:
|
||||
issuer: registry-token-issuer
|
||||
realm: $ui_url:4443/service/token
|
||||
rootcertbundle: /etc/registry/root.crt
|
||||
service: token-service
|
||||
hostname = 192.168.0.2:8888
|
||||
```
|
||||
|
||||
4.Run install.sh to update and start Harbor.
|
||||
```sh
|
||||
$ sudo docker-compose down
|
||||
$ sudo install.sh
|
||||
```
|
||||
4.Re-deploy Harbor refering to previous section "Managing Harbor's lifecycle".
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
1. When Harbor does not work properly, run the below commands to find out if all containers of Harbor are in **UP** status:
|
||||
@ -271,7 +285,7 @@ $ sudo install.sh
|
||||
-----------------------------------------------------------------------------------------------------
|
||||
harbor-db docker-entrypoint.sh mysqld Up 3306/tcp
|
||||
harbor-jobservice /harbor/harbor_jobservice Up
|
||||
harbor-log /bin/sh -c crond && rsyslo ... Up 0.0.0.0:1514->514/tcp
|
||||
harbor-log /bin/sh -c crond && rsyslo ... Up 127.0.0.1:1514->514/tcp
|
||||
harbor-ui /harbor/harbor_ui Up
|
||||
nginx nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
|
||||
registry /entrypoint.sh serve /etc/ ... Up 5000/tcp
|
||||
@ -283,9 +297,4 @@ If a container is not in **UP** state, check the log file of that container in d
|
||||
```
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
```
|
||||
And run the following commands to restart Harbor:
|
||||
```sh
|
||||
$ sudo docker-compose down
|
||||
$ sudo ./prepare
|
||||
$ sudo docker-compose up -d
|
||||
```
|
||||
and re-deploy Harbor refer to the previous section "Managing Harbor's lifecycle".
|
||||
|
@ -1,199 +0,0 @@
|
||||
# Installing and Configuring Harbor on vSphere as Virtual Appliance
|
||||
|
||||
* [Prerequisites](#prerequisites)
|
||||
* [Planning for installation](#planning-for-installation)
|
||||
* [Installation](#installation)
|
||||
* [Getting Certificate of Harbor's CA](#getting-certificate-of-harbors-ca)
|
||||
* [Reconfiguration](#reconfiguration)
|
||||
* [Troubleshooting](#troubleshooting)
|
||||
|
||||
This guide walks you through the steps about installing and configuring Harbor on vSphere as a virtual appliance. If you are installing Harbor on a Linux host, refer to this **[Installation Guide](installation_guide.md)**.
|
||||
|
||||
## Prerequisites
|
||||
* vCenter 5.5+ and at least an ESX host.
|
||||
* 2 vCPUs, 4GB memory and 80GB free disk space in datastore.
|
||||
* A network with DHCP capability, or a static IP address for the virtual appliance.
|
||||
|
||||
## Planning for installation
|
||||
|
||||
### User management
|
||||
By default, Harbor stores user information in an internal database. Harbor can also be configured to authenticate against an external LDAP or AD server. For LDAP/AD authentication, the **Authentication Mode** property must be set to *ldap_auth* at the deployment time.
|
||||
|
||||
**NOTE:** This mode cannot be changed after the first boot of Harbor.
|
||||
|
||||
### Security
|
||||
|
||||
Harbor uses HTTPS for secure communication by default. A self-signed certificate is generated at first boot based on its FQDN (Fully Qualified Domain Name) or IP address. A Docker client or a VCH (Virtual Container Host) needs to trust the certificate of Harbor's CA (Certificate Authority) in order to interact with Harbor.
|
||||
|
||||
Harbor always tries to generate a self-signed certificate based on its FQDN. Therefore, its IP address must have a FQDN associated with it in the DNS server. If Harbor cannot resolve its IP address to a FQDN, it generates the self-signed certificate using its IP address. In this case, Harbor can only be accessed by IP address. When Harbor's IP address or FQDN is changed, the self-signed certificate will be re-generated after a reboot.
|
||||
|
||||
Harbor's self-generated certificate can be replaced by supplying a certificate signed by other CAs in OVA's settings.
|
||||
|
||||
Harbor can be configured to use plain HTTP for some environments such as testing and continuous integration (CI). However, it is **NOT** recommended to use HTTP for production because the communication is never secure.
|
||||
|
||||
### Networking
|
||||
|
||||
Harbor can obtain IP address by DHCP. This is convenient for testing purpose. For a production system, it is recommended that static IP address and FQDN be used.
|
||||
|
||||
For the purpose of generating a self-signed certificate, it is recommended that a DNS record be added to associate Harbor's IP address with a FQDN. This is necessary for both static IP address and dynamic IP address acquired from DHCP. If a DNS record is missing for Harbor's IP address, Harbor can only be accessed by its IP address.
|
||||
|
||||
|
||||
## Installation
|
||||
1. Download the OVA file to your local disk from the **[official release page](https://github.com/vmware/harbor/releases)**.
|
||||
|
||||
2. Log in vSphere web client. Right click on the datacenter, cluster or host which Harbor will be deployed on. Select "Deploy OVF Template" and open the import wizard.
|
||||
|
||||
![ova](img/ova/ova01.png)
|
||||
|
||||
3. Select the OVA file from your local disk and click "Next".
|
||||
|
||||
![ova](img/ova/ova02.png)
|
||||
|
||||
4. Review the OVF template details and click "Next".
|
||||
|
||||
![ova](img/ova/ova03.png)
|
||||
|
||||
5. Accept the end user license agreements and click "Next".
|
||||
|
||||
![ova](img/ova/ova04.png)
|
||||
|
||||
6. Specify a name and a location for the virtual appliance.
|
||||
|
||||
![ova](img/ova/ova05.png)
|
||||
|
||||
7. Select the datastore and virtual disk format, click "Next".
|
||||
|
||||
![ova](img/ova/ova06.png)
|
||||
|
||||
8. Configure the network(s) that the virtual appliance should be connected to.
|
||||
|
||||
![ova](img/ova/ova07.png)
|
||||
|
||||
9. Customize the properties of Harbor. The properties are described below. Note that at the very least, you just need to set four properties: **Root Password**, **Harbor Admin Password**, **Database Password** and **Authentication Mode**.
|
||||
|
||||
![ova](img/ova/ova08.png)
|
||||
|
||||
* System
|
||||
* **Root Password**: The initial password of the root user. Subsequent changes of password should be performed in operating system. (8-128 characters)
|
||||
* **Harbor Admin Password**: The initial password of Harbor admin. It only works for the first time when Harbor starts. It has no effect after the first launch of Harbor. Change the admin password from UI after launching Harbor. (8-20 characters)
|
||||
* **Database Password**: The initial password of the root user of MySQL database. Subsequent changes of password should be performed in operating system. (8-128 characters)
|
||||
* **Permit Root Login**: Specifies whether root user can log in using SSH.
|
||||
* **Garbage Collection**: When setting this to true, Harbor performs garbage collection everytime it boots up. The first time setting this flag to true needs to power off the VM and power it on again.
|
||||
|
||||
* Authentication
|
||||
|
||||
The **Authentication Mode** must be set before the first boot of Harbor. Subsequent changes to **Authentication Mode** do not have any effect. When **ldap_auth** mode is enabled, properties related to LDAP/AD must be set.
|
||||
|
||||
* **Authentication Mode**: The default authentication mode is **db_auth**. Set it to **ldap_auth** when users' credentials are stored in an LDAP or AD server. Note: this option can only be set once.
|
||||
* **Self Registration**: Determine whether the self-registration is allowed or not. Set this to off to disable a user's self-registration in Harbor. This flag has no effect when users are stored in LDAP or AD.
|
||||
* **LDAP URL**: The URL of an LDAP/AD server.
|
||||
* **LDAP Search DN**: A user's DN who has the permission to search the LDAP/AD server. Leave blank if your LDAP/AD server supports anonymous search, otherwise you should configure this DN and **LDAP Search Password**.
|
||||
* **LDAP Search Password**: The password of the user for LDAP search. Leave blank if your LDAP/AD server supports anonymous search.
|
||||
* **LDAP Base DN**: The base DN of a node from which to look up a user for authentication. The search scope includes subtree of the node.
|
||||
* **LDAP UID**: The attribute used in a search to match a user, it could be uid, cn, email, sAMAccountName or other attributes depending on your LDAP/AD server.
|
||||
|
||||
* Security
|
||||
|
||||
If HTTPS is enabled, a self-signed certificate is generated by default. To supply your own certificate, fill in two properties: **SSL Cert** and **SSL Cert Key**. Do not use HTTP in any production system. **Notes:** If you want to enable HTTPS with your own self-signed certificate, refer to the "Getting a certificate" section of this **[guide](https://github.com/vmware/harbor/blob/master/docs/configure_https.md#getting-a-certificate)** for more details.
|
||||
|
||||
* **Protocol**: The protocol for accessing Harbor. Warning: setting it to http makes the communication insecure.
|
||||
* **SSL Cert**: Paste in the content of a certificate file. Leave blank for a generated self-signed certificate.
|
||||
* **SSL Cert Key**: Paste in the content of a certificate key file. Leave blank for a generated key.
|
||||
* **Verify Remote Cert**: Determine whether the image replication should verify the certificate of a remote Harbor registry. Set this flag to off when the remote registry uses a self-signed or untrusted certificate.
|
||||
|
||||
* Email Settings
|
||||
|
||||
To allow a user to reset his/her own password through email, configure the below email settings:
|
||||
|
||||
* **Email Server**: The mail server to send out emails to reset password.
|
||||
* **Email Server Port**: The port of mail server.
|
||||
* **Email Username**: The user from whom the password reset email is sent. Usually this is a system email address.
|
||||
* **Email Password**: The password of the user from whom the password reset email is sent.
|
||||
* **Email From**: The name of the email sender.
|
||||
* **Email SSL**: Whether to enable secure mail transmission.
|
||||
|
||||
* Networking properties
|
||||
* **Default Gateway**: The default gateway address for this VM. Leave blank if DHCP is desired.
|
||||
* **Domain Name**: The domain name of this VM. Run command `man resolv.conf` for more explanation. Leave blank if DHCP is desired or the domain name is not needed for static IP.
|
||||
* **Domain Search Path**: The domain search path(comma or space separated domain names) for this VM. Leave blank if DHCP is desired.
|
||||
* **Domain Name Servers**: The domain name server IP Address for this VM(comma separated). Leave blank if DHCP is desired.
|
||||
* **Network 1 IP Address**: The IP address of this interface. Leave blank if DHCP is desired.
|
||||
* **Network 1 Netmask**: The netmask or prefix for this interface. Leave blank if DHCP is desired.
|
||||
|
||||
After you complete the properties, click "Next".
|
||||
|
||||
10. Review your settings and click "Finish" to complete the deployment.
|
||||
|
||||
![ova](img/ova/ova09.png)
|
||||
|
||||
11. Power on the virtual appliance. It may take a few minutes for the first bootup. The virtual appliance needs to initialize itself for configuration like network address and password.
|
||||
|
||||
12. When the appliance is ready, check from vSphere Web Client for its IP address. Open a browser and type in the URL `http(s)://harbor_ip_address` or `http(s)://harbor_host_name`. Log in as the admin user and verify Harbor has been successfully installed.
|
||||
|
||||
13. For information on how to use Harbor, please refer to [User Guide of Harbor Virtual Appliance](user_guide_ova.md).
|
||||
|
||||
## Getting Certificate of Harbor's CA
|
||||
|
||||
By default, Harbor uses a self-signed certificate in HTTPS. A Docker client or a VCH needs to trust the self-signed certificate of Harbor's CA in order to interact with Harbor.
|
||||
To download the certificate of Harbor's CA and import into a Docker client, follow the below steps. If a certificate issued by a public known CA is used, the below steps are not needed.
|
||||
|
||||
1. Log in Harbor's UI as an admin user.
|
||||
2. Click on the admin's name at the upper left corner and select **"About"** from the drop-down menu.
|
||||
3. Click on the **Download** link to save the certificate file as `ca.crt`.
|
||||
|
||||
![ova](img/ova/downloadcert.png)
|
||||
|
||||
4. Copy the certificate file `ca.crt` to a Docker host. To access Harbor using its FQDN, run the below commands, replace `<Harbor_FQDN>` with the actual FQDN of the Harbor instance:
|
||||
```
|
||||
mkdir -p /etc/docker/certs.d/<Harbor_FQDN>
|
||||
cp ca.crt /etc/docker/certs.d/<Harbor_FQDN>/
|
||||
```
|
||||
To access Harbor using its IP address, run the below commands, replace `<Harbor_IP>` with the actual IP address of the Harbor instance:
|
||||
```
|
||||
mkdir -p /etc/docker/certs.d/<Harbor_IP>
|
||||
cp ca.crt /etc/docker/certs.d/<Harbor_IP>/
|
||||
```
|
||||
|
||||
**Note:** If you run both of the above two sets of commands, Harbor can be accessed by either FQDN or IP address.
|
||||
|
||||
5. Run `docker login` command to verify that HTTPS is working.
|
||||
|
||||
To import the CA's certificate into VCH, complete Step 1-3 and refer to VCH's document for instructions.
|
||||
|
||||
## Reconfiguration
|
||||
If you want to change the properties of Harbor, follow the below steps:
|
||||
|
||||
1. **Power off** Harbor's virtual appliance.
|
||||
2. Right click on the VM and select "Edit Settings".
|
||||
|
||||
![ova](img/ova/edit_settings.png)
|
||||
|
||||
3. Click the "vApp Options" tab, update the properties and click "OK".
|
||||
|
||||
![ova](img/ova/vapp_options.png)
|
||||
|
||||
4. **Power on** the VM and Harbor will reconfigure itself based on the new settings.
|
||||
|
||||
**Note:**
|
||||
1. The **Authentication Mode** can only be set once before the first boot. Subsequent modification of this option does not have any effect.
|
||||
2. The initial admin password, root password of the virtual appliance, MySQL root password, and all networking properties can not be modified using this method after Harbor's first launch. Modify them by the following approach:
|
||||
* **Harbor Admin Password**: Change it in Harbor admin portal.
|
||||
* **Root Password of Virtual Appliance**: Change it by logging in the virtual appliance and doing it in the Linux operating system.
|
||||
* **MySQL Root Password**: Change it by logging in the virtual appliance and doing it in the Linux operating system.
|
||||
* **Networking Properties**: Visit `https://harbor_ip_address:5480`, log in with root/password of your virtual appliance and modify networking properties. Reboot the system after modification to ensure Harbor's self-signed certificate gets updated.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Log collection
|
||||
For diagnosis purpose, logs can be collected by the following steps:
|
||||
|
||||
1. Log in the operating system of Harbor virtual appliance and run the below command:
|
||||
```sh
|
||||
/harbor/script/collect.sh
|
||||
```
|
||||
A "harbor_logs.tar.gz" file is generated in the current directory.
|
||||
|
||||
2. Copy the log file to other host and send to your administrator, replace the `<USERNAME>` , `<HOST_IP>` and `<DIRECTORY>` with proper values:
|
||||
```sh
|
||||
scp ./harbor_logs.tar.gz <USERNAME>@<HOST_IP>:<DIRECTORY>
|
||||
```
|
@ -1,5 +1,3 @@
|
||||
# this is an example of the Uber API
|
||||
# as a demonstration of an API spec in YAML
|
||||
swagger: '2.0'
|
||||
info:
|
||||
title: Harbor API
|
||||
@ -517,7 +515,6 @@ paths:
|
||||
responses:
|
||||
200:
|
||||
description: Get current user information successfully.
|
||||
in: body
|
||||
schema:
|
||||
$ref: '#/definitions/User'
|
||||
401:
|
||||
@ -659,6 +656,11 @@ paths:
|
||||
format: int32
|
||||
required: true
|
||||
description: Relevant project ID.
|
||||
- name: detail
|
||||
in: query
|
||||
type: boolean
|
||||
required: false
|
||||
description: Get detail info or not.
|
||||
- name: q
|
||||
in: query
|
||||
type: string
|
||||
@ -680,11 +682,11 @@ paths:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Searched for respositories successfully.
|
||||
description: If detail is false, the response body is a string array which contains the names of repositories, or the response body contains an object array as described in schema.
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
$ref: '#/definitions/Repository'
|
||||
headers:
|
||||
X-Total-Count:
|
||||
description: The total count of repositories
|
||||
@ -700,26 +702,27 @@ paths:
|
||||
description: Project ID does not exist.
|
||||
500:
|
||||
description: Unexpected internal errors.
|
||||
/repositories/{repo_name}/tags/{tag}:
|
||||
delete:
|
||||
summary: Delete a repository or a tag in a repository.
|
||||
summary: Delete a tag in a repository.
|
||||
description: |
|
||||
This endpoint let user delete repositories and tags with repo name and tag.
|
||||
This endpoint let user delete tags with repo name and tag.
|
||||
parameters:
|
||||
- name: repo_name
|
||||
in: query
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: The name of repository which will be deleted.
|
||||
- name: tag
|
||||
in: query
|
||||
in: path
|
||||
type: string
|
||||
required: false
|
||||
required: true
|
||||
description: Tag of a repository.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Delete repository or tag successfully.
|
||||
description: Delete tag successfully.
|
||||
400:
|
||||
description: Invalid repo_name.
|
||||
401:
|
||||
@ -728,41 +731,69 @@ paths:
|
||||
description: Repository or tag not found.
|
||||
403:
|
||||
description: Forbidden.
|
||||
/repositories/tags:
|
||||
/repositories/{repo_name}/tags:
|
||||
get:
|
||||
summary: Get tags of a relevant repository.
|
||||
description: |
|
||||
This endpoint aims to retrieve tags from a relevant repository.
|
||||
parameters:
|
||||
- name: repo_name
|
||||
in: query
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: Relevant repository name.
|
||||
- name: detail
|
||||
in: query
|
||||
type: boolean
|
||||
required: false
|
||||
description: If detail is true, the manifests is returned too.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Retrieved tags from a relevant repository successfully.
|
||||
description: If detail is false, the response body is a string array, or the response body contains the manifest informations as described in schema.
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
$ref: '#/definitions/DetailedTag'
|
||||
500:
|
||||
description: Unexpected internal errors.
|
||||
/repositories/manifests:
|
||||
delete:
|
||||
summary: Delete all tags of a repository.
|
||||
description: |
|
||||
This endpoint let user delete all tags with repo name.
|
||||
parameters:
|
||||
- name: repo_name
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: The name of repository which will be deleted.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Delete successfully.
|
||||
400:
|
||||
description: Invalid repo_name.
|
||||
401:
|
||||
description: Unauthorized.
|
||||
404:
|
||||
description: Repository not found.
|
||||
403:
|
||||
description: Forbidden.
|
||||
/repositories/{repo_name}/tags/{tag}/manifest:
|
||||
get:
|
||||
summary: Get manifests of a relevant repository.
|
||||
description: |
|
||||
This endpoint aims to retreive manifests from a relevant repository.
|
||||
parameters:
|
||||
- name: repo_name
|
||||
in: query
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: Repository name
|
||||
- name: tag
|
||||
in: query
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: Tag name
|
||||
@ -777,11 +808,37 @@ paths:
|
||||
200:
|
||||
description: Retrieved manifests from a relevant repository successfully.
|
||||
schema:
|
||||
$ref: '#/definitions/Repository'
|
||||
$ref: '#/definitions/Manifest'
|
||||
404:
|
||||
description: Retrieved manifests from a relevant repository not found.
|
||||
500:
|
||||
description: Unexpected internal errors.
|
||||
/repositories/{repo_name}/signatures:
|
||||
get:
|
||||
summary: Get signature information of a repository
|
||||
description: |
|
||||
This endpoint aims to retrieve signature information of a repository, the data is
|
||||
from the nested notary instance of Harbor.
|
||||
If the repository does not have any signature information in notary, this API will
|
||||
return an empty list with response code 200, instead of 404
|
||||
parameters:
|
||||
- name: repo_name
|
||||
in: path
|
||||
type: string
|
||||
required: true
|
||||
description: repository name.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Retrieved signatures.
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/RepoSignature'
|
||||
500:
|
||||
description: Server side error.
|
||||
|
||||
/repositories/top:
|
||||
get:
|
||||
summary: Get public repositories which are accessed most.
|
||||
@ -794,15 +851,20 @@ paths:
|
||||
format: int32
|
||||
required: false
|
||||
description: The number of the requested public repositories, default is 10 if not provided.
|
||||
- name: detail
|
||||
in: query
|
||||
type: boolean
|
||||
required: false
|
||||
description: Get detail info or not.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Retrieved top repositories successfully.
|
||||
description: If detail is true, the response is described as the schema, or the response contains a TopRepo array.
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/TopRepo'
|
||||
$ref: '#/definitions/Repository'
|
||||
400:
|
||||
description: Bad request because of invalid count.
|
||||
500:
|
||||
@ -1168,12 +1230,12 @@ paths:
|
||||
description: |
|
||||
This endpoint is for ping validates whether the target is reachable and whether the credential is valid.
|
||||
parameters:
|
||||
- name: id
|
||||
in: query
|
||||
type: integer
|
||||
format: int64
|
||||
required: false
|
||||
description: The replication's policy ID.
|
||||
- name: target
|
||||
in: body
|
||||
description: The target object.
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/PingTarget'
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
@ -1187,6 +1249,31 @@ paths:
|
||||
description: Target not found.
|
||||
500:
|
||||
description: Unexpected internal errors.
|
||||
/targets/{id}/ping:
|
||||
post:
|
||||
summary: Ping target.
|
||||
description: |
|
||||
This endpoint is for ping target.
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
description: The replication's target ID.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Ping replication's target successfully.
|
||||
400:
|
||||
description: Can not ping target.
|
||||
401:
|
||||
description: User need to log in first.
|
||||
404:
|
||||
description: Target ID does not exist.
|
||||
500:
|
||||
description: Unexpected internal errors.
|
||||
/targets/{id}:
|
||||
put:
|
||||
summary: Update replication's target.
|
||||
@ -1203,7 +1290,7 @@ paths:
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/RepTargetPost'
|
||||
$ref: '#/definitions/PutTarget'
|
||||
description: Updates of replication's target.
|
||||
tags:
|
||||
- Products
|
||||
@ -1309,7 +1396,229 @@ paths:
|
||||
403:
|
||||
description: User does not have permission of admin role.
|
||||
500:
|
||||
description: Unexpected internal errors.
|
||||
description: Unexpected internal errors.
|
||||
/systeminfo:
|
||||
get:
|
||||
summary: Get general system info
|
||||
description: |
|
||||
This API is for retrieving general system info, this can be called by anonymous request.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Get general info successfully.
|
||||
schema:
|
||||
type: object
|
||||
items:
|
||||
$ref: "#/definitions/GeneralInfo"
|
||||
500:
|
||||
description: Unexpected internal error.
|
||||
/systeminfo/volumes:
|
||||
get:
|
||||
summary: Get system volume info (total/free size).
|
||||
description: |
|
||||
This endpoint is for retrieving system volume info that only provides for admin user.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Get system volumes successfully.
|
||||
schema:
|
||||
type: object
|
||||
items:
|
||||
$ref: '#/definitions/SystemInfo'
|
||||
401:
|
||||
description: User need to log in first.
|
||||
403:
|
||||
description: User does not have permission of admin role.
|
||||
500:
|
||||
description: Unexpected internal errors.
|
||||
/systeminfo/getcert:
|
||||
get:
|
||||
summary: Get default root certificate under OVA deployment.
|
||||
description: |
|
||||
This endpoint is for downloading a default root certificate that only provides for admin user under OVA deployment.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Get default root certificate successfully.
|
||||
401:
|
||||
description: User need to log in first.
|
||||
403:
|
||||
description: User does not have permission of admin role.
|
||||
404:
|
||||
description: Not found the default root certificate.
|
||||
500:
|
||||
description: Unexpected internal errors.
|
||||
/ldap/ping:
|
||||
post:
|
||||
summary: Ping available ldap service.
|
||||
description: |
|
||||
This endpoint ping the available ldap service for test related configuration parameters.
|
||||
parameters:
|
||||
- name: ldapconf
|
||||
in: body
|
||||
description: ldap configuration. support input ldap service configuration. If it's a empty request, will load current configuration from the system.
|
||||
required: false
|
||||
schema:
|
||||
$ref: '#/definitions/LdapConf'
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Ping ldap service successfully.
|
||||
400:
|
||||
description: Inviald ldap configuration parameters.
|
||||
401:
|
||||
description: User need to login first.
|
||||
403:
|
||||
description: Only admin has this authority.
|
||||
500:
|
||||
description: Unexpected internal errors.
|
||||
/ldap/users/search:
|
||||
post:
|
||||
summary: Search available ldap users.
|
||||
description: |
|
||||
This endpoint searches the available ldap users based on related configuration parameters. Support searched by input ladp configuration, load configuration from the system and specific filter.
|
||||
parameters:
|
||||
- name: username
|
||||
in: query
|
||||
type: string
|
||||
required: false
|
||||
description: Registered user ID
|
||||
- name: ldap_conf
|
||||
in: body
|
||||
description: ldap search configuration. ldapconf field can input ldap service configuration. If this item are blank, will load default configuration will load current configuration from the system.
|
||||
required: false
|
||||
schema:
|
||||
$ref: '#/definitions/LdapConf'
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Search ldap users successfully.
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/LdapUsers'
|
||||
400:
|
||||
description: Inviald ldap configuration parameters.
|
||||
401:
|
||||
description: User need to login first.
|
||||
403:
|
||||
description: Only admin has this authority.
|
||||
500:
|
||||
description: Unexpected internal errors.
|
||||
/ldap/users/import:
|
||||
post:
|
||||
summary: Import selected available ldap users.
|
||||
description: |
|
||||
This endpoint adds the selected available ldap users to harbor based on related configuration parameters from the system. System will try to guess the user email address and realname, add to harbor user information.
|
||||
If have errors when import user, will return the list of importing failed uid and the failed reason.
|
||||
parameters:
|
||||
- name: uid_list
|
||||
in: body
|
||||
description: The uid listed for importing. This list will check users validity of ldap service based on configuration from the system.
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/LdapImportUsers'
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Add ldap users successfully.
|
||||
401:
|
||||
description: User need to login first.
|
||||
403:
|
||||
description: Only admin has this authority.
|
||||
500:
|
||||
description: Failed import some users.
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/LdapFailedImportUsers'
|
||||
/configurations:
|
||||
get:
|
||||
summary: Get system configurations.
|
||||
description: |
|
||||
This endpoint is for retrieving system configurations that only provides for admin user.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Get system configurations successfully. The response body is a map.
|
||||
schema:
|
||||
type: object
|
||||
401:
|
||||
description: User need to log in first.
|
||||
403:
|
||||
description: User does not have permission of admin role.
|
||||
500:
|
||||
description: Unexpected internal errors.
|
||||
put:
|
||||
summary: Modify system configurations.
|
||||
description: |
|
||||
This endpoint is for modifying system configurations that only provides for admin user.
|
||||
tags:
|
||||
- Products
|
||||
parameters:
|
||||
- name: configurations
|
||||
in: body
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
description: The configurations map need to be modified, the following are keys "auth_mode", "email_from", "email_host", "email_identity", "email_password", "email_port", "email_ssl", "email_username", "ldap_base_dn", "ldap_filter", "ldap_scope", "ldap_search_dn", "ldap_search_password", "ldap_timeout", "ldap_uid", "ldap_url", "project_creation_restriction", "self_registration", "verify_remote_cert".
|
||||
responses:
|
||||
200:
|
||||
description: Modify system configurations successfully.
|
||||
401:
|
||||
description: User need to log in first.
|
||||
403:
|
||||
description: User does not have permission of admin role.
|
||||
500:
|
||||
description: Unexpected internal errors.
|
||||
/configurations/reset:
|
||||
post:
|
||||
summary: Reset system configurations.
|
||||
description: |
|
||||
Reset system configurations from environment variables. Can only be accessed by admin user.
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Reset system configurations successfully.
|
||||
401:
|
||||
description: User need to log in first.
|
||||
403:
|
||||
description: User does not have permission of admin role.
|
||||
500:
|
||||
description: Unexpected internal errors.
|
||||
/email/ping:
|
||||
post:
|
||||
summary: Test connection and authentication with email server.
|
||||
description: |
|
||||
Test connection and authentication with email server.
|
||||
parameters:
|
||||
- name: settings
|
||||
in: body
|
||||
description: Email server settings, if some of the settings are not assigned, they will be read from system configuration.
|
||||
required: false
|
||||
schema:
|
||||
$ref: '#/definitions/EmailServerSetting'
|
||||
tags:
|
||||
- Products
|
||||
responses:
|
||||
200:
|
||||
description: Ping email server successfully.
|
||||
400:
|
||||
description: Inviald email server settings.
|
||||
401:
|
||||
description: User need to login first.
|
||||
403:
|
||||
description: Only admin has this authority.
|
||||
500:
|
||||
description: Unexpected internal errors.
|
||||
definitions:
|
||||
Search:
|
||||
type: object
|
||||
@ -1318,26 +1627,12 @@ definitions:
|
||||
description: Search results of the projects that matched the filter keywords.
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/SearchProject'
|
||||
$ref: '#/definitions/Project'
|
||||
repositories:
|
||||
description: Search results of the repositories that matched the filter keywords.
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/SearchRepository'
|
||||
SearchProject:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
format: int64
|
||||
description: The ID of project
|
||||
name:
|
||||
type: string
|
||||
description: The name of the project
|
||||
public:
|
||||
type: integer
|
||||
format: int
|
||||
description: The flag to indicate the publicity of the project (1 is public, 0 is non-public)
|
||||
SearchRepository:
|
||||
type: object
|
||||
properties:
|
||||
@ -1353,6 +1648,12 @@ definitions:
|
||||
repository_name:
|
||||
type: string
|
||||
description: The name of the repository
|
||||
pull_count:
|
||||
type: integer
|
||||
description: The count how many times the repository is pulled
|
||||
tags_count:
|
||||
type: integer
|
||||
description: The count of tags in the repository
|
||||
ProjectReq:
|
||||
type: object
|
||||
properties:
|
||||
@ -1403,7 +1704,7 @@ definitions:
|
||||
repo_count:
|
||||
type: integer
|
||||
description: The number of the repositories under this project.
|
||||
Repository:
|
||||
Manifest:
|
||||
type: object
|
||||
properties:
|
||||
manifest:
|
||||
@ -1522,7 +1823,7 @@ definitions:
|
||||
TopRepo:
|
||||
type: object
|
||||
properties:
|
||||
repo_name:
|
||||
name:
|
||||
type: string
|
||||
description: The name of the repo
|
||||
count:
|
||||
@ -1723,6 +2024,33 @@ definitions:
|
||||
password:
|
||||
type: string
|
||||
description: The target server password.
|
||||
PingTarget:
|
||||
type: object
|
||||
properties:
|
||||
endpoint:
|
||||
type: string
|
||||
description: The target address URL string.
|
||||
username:
|
||||
type: string
|
||||
description: The target server username.
|
||||
password:
|
||||
type: string
|
||||
description: The target server password.
|
||||
PutTarget:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: The target name.
|
||||
endpoint:
|
||||
type: string
|
||||
description: The target address URL string.
|
||||
username:
|
||||
type: string
|
||||
description: The target server username.
|
||||
password:
|
||||
type: string
|
||||
description: The target server password.
|
||||
HasAdminRole:
|
||||
type: object
|
||||
properties:
|
||||
@ -1741,3 +2069,179 @@ definitions:
|
||||
comment:
|
||||
type: string
|
||||
description: The new comment.
|
||||
Storage:
|
||||
type: object
|
||||
properties:
|
||||
total:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Total volume size.
|
||||
free:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Free volume size.
|
||||
GeneralInfo:
|
||||
type: object
|
||||
properties:
|
||||
with_notary:
|
||||
type: boolean
|
||||
description: If the Harbor instance is deployed with nested notary.
|
||||
with_admiral:
|
||||
type: boolean
|
||||
description: If the Harbor instance is deployed with Admiral.
|
||||
admiral_endpoint:
|
||||
type: string
|
||||
description: The url of the endpoint of admiral instance.
|
||||
auth_mode:
|
||||
type: string
|
||||
description: The auth mode of current Harbor instance.
|
||||
project_creation_restriction:
|
||||
type: string
|
||||
description: Indicate who can create projects, it could be 'adminonly' or 'everyone'.
|
||||
self_registration:
|
||||
type: boolean
|
||||
description: Indicate whether the Harbor instance enable user to register himself.
|
||||
has_ca_root:
|
||||
type: boolean
|
||||
description: Indicate whether there is a ca root cert file ready for download in the file system.
|
||||
harbor_version:
|
||||
type: string
|
||||
description: The build version of Harbor.
|
||||
SystemInfo:
|
||||
type: object
|
||||
properties:
|
||||
storage:
|
||||
type: array
|
||||
description: The storage of system.
|
||||
items:
|
||||
$ref: '#/definitions/Storage'
|
||||
LdapConf:
|
||||
type: object
|
||||
properties:
|
||||
ldap_url:
|
||||
type: string
|
||||
description: The url of ldap service.
|
||||
ldap_search_dn:
|
||||
type: string
|
||||
description: The search dn of ldap service.
|
||||
ldap_search_password:
|
||||
type: string
|
||||
description: The search password of ldap service.
|
||||
ldap_base_dn:
|
||||
type: string
|
||||
description: The base dn of ldap service.
|
||||
ldap_filter:
|
||||
type: string
|
||||
description: The serach filter of ldap service.
|
||||
ldap_uid:
|
||||
type: string
|
||||
description: The serach uid from ldap service attributes.
|
||||
ldap_scope:
|
||||
type: integer
|
||||
format: int64
|
||||
description: The serach scope of ldap service.
|
||||
ldap_connection_timeout:
|
||||
type: integer
|
||||
format: int64
|
||||
description: The connect timeout of ldap service(second).
|
||||
LdapUsers:
|
||||
type: object
|
||||
properties:
|
||||
ldap_username:
|
||||
type: string
|
||||
description: search ldap user name based on ldapconf.
|
||||
ldap_realname:
|
||||
type: string
|
||||
description: system will try to guess the user realname form "uid" or "cn" attribute.
|
||||
ldap_email:
|
||||
type: string
|
||||
description: system will try to guess the user email address form "mail" or "email" attribute.
|
||||
LdapImportUsers:
|
||||
type: object
|
||||
properties:
|
||||
ldap_uid_list:
|
||||
type: array
|
||||
description: selected uid list
|
||||
items:
|
||||
type: string
|
||||
LdapFailedImportUsers:
|
||||
type: object
|
||||
properties:
|
||||
ldap_uid:
|
||||
type: string
|
||||
description: the uid can't add to system.
|
||||
error:
|
||||
type: string
|
||||
description: fail reason.
|
||||
EmailServerSetting:
|
||||
type: object
|
||||
properties:
|
||||
email_host:
|
||||
type: string
|
||||
description: The host of email server.
|
||||
email_port:
|
||||
type: integer
|
||||
description: The port of email server.
|
||||
email_username:
|
||||
type: string
|
||||
description: The username of email server.
|
||||
email_password:
|
||||
type: string
|
||||
description: The password of email server.
|
||||
email_ssl:
|
||||
type: boolean
|
||||
description: Use ssl/tls or not.
|
||||
email_identity:
|
||||
type: string
|
||||
description: The dentity of email server.
|
||||
RepoSignature:
|
||||
type: object
|
||||
properties:
|
||||
tag:
|
||||
type: string
|
||||
description: The tag of image.
|
||||
hashes:
|
||||
type: object
|
||||
description: The JSON object of the hash of the image.
|
||||
DetailedTag:
|
||||
type: object
|
||||
properties:
|
||||
tag:
|
||||
type: string
|
||||
description: The tag of image.
|
||||
manifest:
|
||||
type: object
|
||||
description: The detail of manifest.
|
||||
Repository:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
description: The ID of repository.
|
||||
name:
|
||||
type: string
|
||||
description: The name of repository.
|
||||
owner_id:
|
||||
type: integer
|
||||
description: The owner ID of repository.
|
||||
project_id:
|
||||
type: integer
|
||||
description: The project ID of repository.
|
||||
description:
|
||||
type: string
|
||||
description: The description of repository.
|
||||
pull_count:
|
||||
type: integer
|
||||
description: The pull count of repository.
|
||||
star_count:
|
||||
type: integer
|
||||
description: The star count of repository.
|
||||
tags_count:
|
||||
type: integer
|
||||
description: The tags count of repository.
|
||||
creation_time:
|
||||
type: string
|
||||
description: The creation time of repository.
|
||||
update_time:
|
||||
type: string
|
||||
description: The update time of repository.
|
||||
|
51
docs/use_make.md
Normal file
@ -0,0 +1,51 @@
|
||||
### Variables
|
||||
Variable | Description
|
||||
-------------------|-------------
|
||||
BASEIMAGE | Container base image, default: photon
|
||||
DEVFLAG | Build model flag, default: dev
|
||||
COMPILETAG | Compile model flag, default: compile_normal (local golang build)
|
||||
GOBUILDIMAGE | Golang image to compile harbor go source code.
|
||||
CLARITYIMAGE | Clarity image that based on Node to compile UI.
|
||||
NOTARYFLAG | Whether to enable notary in harbor, default:false
|
||||
HTTPPROXY | Clarity proxy to build UI.
|
||||
|
||||
|
||||
### Targets
|
||||
Target | Description
|
||||
--------------------|-------------
|
||||
all | prepare env, compile binaries, build images and install images
|
||||
prepare | prepare env
|
||||
compile | compile ui and jobservice code
|
||||
compile_ui | compile ui binary
|
||||
compile_jobservice | compile jobservice binary
|
||||
compile_clarity | compile clarity ui 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
|
||||
start | startup Harbor instance
|
||||
down | shutdown Harbor instance
|
||||
package_online | prepare online install package
|
||||
package_offline | prepare offline install package
|
||||
pushimage | push Harbor images to specific registry server
|
||||
clean all | remove binary, Harbor images, specific version docker-compose file, specific version tag and online/offline install package
|
||||
cleanbinary | remove ui and jobservice binary
|
||||
cleanimage | remove Harbor images
|
||||
cleandockercomposefile | remove specific version docker-compose
|
||||
cleanversiontag | remove specific version tag
|
||||
cleanpackage | remove online/offline install package
|
||||
version | set harbor version
|
||||
|
||||
#### EXAMPLE:
|
||||
|
||||
#### Build and run harbor from source code.
|
||||
make install GOBUILDIMAGE=golang:1.7.3 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:0.8.4 NOTARYFLAG=true HTTPPROXY=
|
||||
|
||||
### Package offline installer
|
||||
make package_offline GOBUILDIMAGE=golang:1.7.3 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:0.8.4 NOTARYFLAG=true HTTPPROXY=
|
||||
|
||||
### Start harbor with notary
|
||||
make -e NOTARYFLAG=true start
|
||||
|
||||
### Stop harbor with notary
|
||||
make -e NOTARYFLAG=true down
|
22
docs/use_notary.md
Normal file
@ -0,0 +1,22 @@
|
||||
### Setup
|
||||
In harbor.cfg, make sure the attribute ```ui_url_protocol``` is set to ```https```, and the attributes ```ssl_cert``` and ```ssl_cert_key``` are pointed to valid certificates. For more information about generating https certificate please refer to: [Configuring HTTPS for Harbor](configure_https.md)
|
||||
|
||||
### Copy Root Certificate
|
||||
Suppose the Harbor instance is hosted on a machine ```192.168.0.5```
|
||||
If you are using a self-signed cetificate, make sure to copy the CA root cert to ```/etc/docker/certs.d/192.168.0.5/``` and ```~/.docker/tls/192.168.0.5:4443/```
|
||||
|
||||
### Enable Docker Content Trust
|
||||
It can be done via setting envrironment variables:
|
||||
|
||||
```
|
||||
export DOCKER_CONTENT_TRUST=1
|
||||
export DOCKER_CONTENT_TRUST_SERVER=https://192.168.0.5:4443
|
||||
```
|
||||
|
||||
### Set alias for notary (optional)
|
||||
Because by default the local directory for storing meta files for notary client is different from docker client. If you want to use notary client to manipulate the keys/meta files generated by Docker Content Trust, please set the alias to reduce the effort:
|
||||
|
||||
```
|
||||
alias notary="notary -s https//192.168.0.5:4443 -d ~/.docker/trust --tlscacert /etc/docker/certs.d/192.168.0.5/ca.crt"
|
||||
|
||||
```
|
@ -1,5 +1,5 @@
|
||||
#User Guide
|
||||
##Overview
|
||||
# User Guide
|
||||
## Overview
|
||||
This guide walks you through the fundamentals of using Harbor. You'll learn how to use Harbor to:
|
||||
|
||||
* Manage your projects.
|
||||
@ -7,14 +7,15 @@ This guide walks you through the fundamentals of using Harbor. You'll learn how
|
||||
* Replicate projects to a remote registry.
|
||||
* Search projects and repositories.
|
||||
* Manage Harbor system if you are the system administrator:
|
||||
+ Manage users.
|
||||
+ Manage destinations.
|
||||
+ Manage replication policies.
|
||||
* Manage users.
|
||||
* Manage destinations.
|
||||
* Manage replication policies.
|
||||
* Manage configuration.
|
||||
* Pull and push images using Docker client.
|
||||
* Delete repositories and images.
|
||||
* Content trust.
|
||||
|
||||
|
||||
##Role Based Access Control
|
||||
## Role Based Access Control(RBAC)
|
||||
|
||||
![rbac](img/rbac.png)
|
||||
|
||||
@ -27,16 +28,16 @@ Harbor manages images through projects. Users can be added into one project as a
|
||||
Besides the above three roles, there are two system-wide roles:
|
||||
|
||||
* **SysAdmin**: "SysAdmin" has the most privileges. In addition to the privileges mentioned above, "SysAdmin" can also list all projects, set an ordinary user as administrator and delete users. The public project "library" is also owned by the administrator.
|
||||
* **Anonymous**: When a user is not logged in, the user is considered as an "anonymous" user. An anonymous user has no access to private projects and has read-only access to public projects.
|
||||
* **Anonymous**: When a user is not logged in, the user is considered as an "Anonymous" user. An anonymous user has no access to private projects and has read-only access to public projects.
|
||||
|
||||
##User account
|
||||
## User account
|
||||
Harbor supports two authentication modes:
|
||||
|
||||
* **Database(db_auth)**
|
||||
|
||||
Users are stored in the local database.
|
||||
|
||||
A user can self register himself/herself in Harbor in this mode. To disable user self-registration, refer to the [installation guide](installation_guide_ova.md). When self-registration is disabled, the system administrator can add users in Harbor.
|
||||
A user can register himself/herself in Harbor in this mode. To disable user self-registration, refer to the [installation guide](installation_guide.md) for initial configuration, or disable this feature in [Administrator Options](#administrator-options). When self-registration is disabled, the system administrator can add users into Harbor.
|
||||
|
||||
When registering or adding a new user, the username and email must be unique in the Harbor system. The password must contain at least 8 characters with 1 lowercase letter, 1 uppercase letter and 1 numeric character.
|
||||
|
||||
@ -51,11 +52,11 @@ Harbor supports two authentication modes:
|
||||
|
||||
Under this authentication mode, users whose credentials are stored in an external LDAP or AD server can log in to Harbor directly.
|
||||
|
||||
When an LDAP/AD user logs in by *username* and *password*, Harbor binds to the LDAP/AD server with the **"LDAP Search DN"** and **"LDAP Search Password"** described in [installation guide](installation_guide_ova.md). If it successes, Harbor looks up the user under the LDAP entry **"LDAP Base DN"** including substree. The attribute (such as uid, cn) specified by **"LDAP UID"** is used to match a user with the *username*. If a match is found, the user's *password* is verified by a bind request to the LDAP/AD server.
|
||||
When an LDAP/AD user logs in by *username* and *password*, Harbor binds to the LDAP/AD server with the **"LDAP Search DN"** and **"LDAP Search Password"** described in [installation guide](installation_guide.md). If it succeeded, Harbor looks up the user under the LDAP entry **"LDAP Base DN"** including substree. The attribute (such as uid, cn) specified by **"LDAP UID"** is used to match a user with the *username*. If a match is found, the user's *password* is verified by a bind request to the LDAP/AD server.
|
||||
|
||||
Self-registration, changing password and resetting password are not supported anymore under LDAP/AD authentication mode because the users are managed by LDAP or AD.
|
||||
Self-registration, changing password and resetting password are not supported under LDAP/AD authentication mode because the users are managed by LDAP or AD.
|
||||
|
||||
##Managing projects
|
||||
## Managing projects
|
||||
A project in Harbor contains all repositories of an application. No images can be pushed to Harbor before the project is created. RBAC is applied to a project. There are two types of projects in Harbor:
|
||||
|
||||
* **Public**: All users have the read privilege to a public project, it's convenient for you to share some repositories with others in this way.
|
||||
@ -73,70 +74,96 @@ All logs can be listed by clicking "Logs". You can apply a filter by username, o
|
||||
|
||||
![browse project](img/new_project_log.png)
|
||||
|
||||
##Managing members of a project
|
||||
###Adding members
|
||||
## Managing members of a project
|
||||
### Adding members
|
||||
You can add members with different roles to an existing project.
|
||||
|
||||
![browse project](img/new_add_member.png)
|
||||
|
||||
###Updating and removing members
|
||||
You can update or remove a member by clicking the icon on the right.
|
||||
### Updating and removing members
|
||||
You can update or remove a member by clicking the icon on the left.
|
||||
|
||||
![browse project](img/new_remove_update_member.png)
|
||||
|
||||
##Replicating images
|
||||
## Replicating images
|
||||
Images replication is used to replicate repositories from one Harbor instance to another.
|
||||
|
||||
The function is project-oriented, and once the system administrator set a policy to one project, all repositories under the project will be replicated to the remote registry. Each repository will start a job to run. If the project does not exist on the remote registry, a new project will be created automatically, but if it already exists and the user configured in policy has no write privilege to it, the process will fail. When a new repository is pushed to this project or an existing repository is deleted from this project, the same operation will also be replicated to the destination. The member information will not be replicated.
|
||||
The function is project-oriented, and once the system administrator set a rule to one project, all repositories under the project will be replicated to the remote registry. Each repository will start a job to run. If the project does not exist on the remote registry, a new project will be created automatically, but if it already exists and the user configured in policy has no write privilege to it, the process will fail. When a new repository is pushed to this project or an existing repository is deleted from this project, the same operation will also be replicated to the destination. The member information will not be replicated.
|
||||
|
||||
There may be a bit of delay during replication according to the situation of the network. If replication job fails due to the network issue, the job will be re-scheduled a few minutes later.
|
||||
|
||||
**Note:** The replication feature is incompatible between Harbor instance before version 0.3.5(included) and after version 0.3.5.
|
||||
|
||||
Start replication by creating a policy. Click "Add New Policy" on the "Replication" tab, fill the necessary fields, if there is no destination in the list, you need to create one, and then click "OK", a policy for this project will be created. If "Enable" is chosen, the project will be replicated to the remote immediately.
|
||||
Start replication by creating a rule. Click "Add Replication Rule" on the "Replication" tab, fill in the necessary fields, if there is no endpoint in the list, you need to create one, and then click "OK", a rule for this project will be created. If "Enable" is chosen, the project will be replicated to the remote immediately.
|
||||
|
||||
![browse project](img/new_create_policy.png)
|
||||
![browse project](img/new_create_rule.png)
|
||||
|
||||
You can enable, disable or delete a policy in the policy list view. Only policies which are disabled can be edited and only policies which are disabled and have no running jobs can be deleted. If a policy is disabled, the running jobs under it will be stopped.
|
||||
You can enable, disable or delete a rule in the rule list view. Only rules which are disabled can be edited and only rules which are disabled and have no running jobs can be deleted. If a rule is disabled, the running jobs under it will be stopped.
|
||||
|
||||
Click a policy, jobs which belong to this policy will be listed. A job represents the progress which will replicate a repository of one project to the remote.
|
||||
Click a rule, jobs which belong to this rule will be listed. A job represents the progress of replicating the repository to the remote instance.
|
||||
|
||||
![browse project](img/new_policy_list.png)
|
||||
![browse project](img/new_rule_list.png)
|
||||
|
||||
##Searching projects and repositories
|
||||
Entering a keyword in the search field at the top lists all matching projects and repositories. The search result includes both public and private repositories you have access privilege to.
|
||||
## Searching projects and repositories
|
||||
Entering a keyword in the search field at the top lists all matching projects and repositories. The search result includes both public and private repositories you have access to.
|
||||
|
||||
![browse project](img/new_search.png)
|
||||
|
||||
##Administrator options
|
||||
###Managing user
|
||||
Administrator can add "administrator" role to an ordinary user by toggling the switch under "Administrator". To delete a user, click on the recycle bin icon.
|
||||
## Administrator options
|
||||
### Managing user
|
||||
Administrator can add "Administrator" role to an ordinary user by click button on the left and select "Set as Administrator". To delete a user, select "Delete".
|
||||
|
||||
![browse project](img/new_set_admin_remove_user.png)
|
||||
|
||||
###Managing destination
|
||||
You can list, add, edit and delete destinations in the "Destination" tab. Only destinations which are not referenced by any policies can be edited.
|
||||
### Managing endpoint
|
||||
You can list, add, edit and delete endpoints in the "Endpoints" tab. Only endpoints which are not referenced by any enabled rules can be edited.
|
||||
|
||||
![browse project](img/new_manage_destination.png)
|
||||
![browse project](img/new_manage_endpoint.png)
|
||||
|
||||
###Managing replication
|
||||
You can list, edit, enable and disable policies in the "Replication" tab. Make sure the policy is disabled before you edit it.
|
||||
### Managing replication
|
||||
You can list, edit, enable and disable rules in the "Replication" tab. Make sure the policy is disabled before you edit it.
|
||||
|
||||
![browse project](img/new_manage_replication.png)
|
||||
|
||||
##Pulling and pushing images using Docker client
|
||||
### Managing authentication
|
||||
You can change authentication mode between **Database**(default) and **LDAP** before any user is added, when there is at least one user(besides admin) in Harbor, you cannot change the authentication mode.
|
||||
![browse project](img/new_auth.png)
|
||||
When using LDAP mode, user's self-registration is disabled. The parameters of LDAP server must be filled in. For more information, refer to [User account](#user-account).
|
||||
![browse project](img/ldap_auth.png)
|
||||
|
||||
### Managing project creation
|
||||
Use the **Project Creation** drop-down menu to set which users can create projects. Select **Everyone** to allow all users to create projects. Select **Admin Only** to allow only users with the Administrator role to create projects.
|
||||
![browse project](img/new_proj_create.png)
|
||||
|
||||
### Managing self-registration
|
||||
You can manage whether a user can sign up for a new account. This option is not available if you use LDAP authentication.
|
||||
![browse project](img/new_self_reg.png)
|
||||
|
||||
### Managing verification of remote certificate
|
||||
You can choose whether to verify remote endpoint's certification. You may need to disable certificate verification if the remote registry uses a self-signed or an untrusted certificate.
|
||||
![browse project](img/new_remote_cert.png)
|
||||
|
||||
### Managing email settings
|
||||
You can change Harbor's email settings, the mail server is used to send out responses to users who request to reset their password.
|
||||
![browse project](img/new_config_email.png)
|
||||
|
||||
## Pulling and pushing images using Docker client
|
||||
|
||||
**NOTE: Harbor only supports Registry V2 API. You need to use Docker client 1.6.0 or higher.**
|
||||
|
||||
Harbor supports HTTP by default and Docker client tries to connect to Harbor using HTTPS first, so if you encounter an error as below when you pull or push images, you need to add '--insecure-registry' option to /etc/default/docker (ubuntu) or /etc/sysconfig/docker (centos) and restart Docker:
|
||||
*FATA[0000] Error response from daemon: v1 ping attempt failed with error:
|
||||
Get https://myregistrydomain.com:5000/v1/_ping: tls: oversized record received with length 20527.
|
||||
If this private registry supports only HTTP or HTTPS with an unknown CA certificate,please add
|
||||
`--insecure-registry myregistrydomain.com:5000` to the daemon's arguments.
|
||||
In the case of HTTPS, if you have access to the registry's CA certificate, no need for the flag;
|
||||
simply place the CA certificate at /etc/docker/certs.d/myregistrydomain.com:5000/ca.crt*
|
||||
Harbor supports HTTP by default and Docker client tries to connect to Harbor using HTTPS first, so if you encounter an error as below when you pull or push images, you need to add '--insecure-registry' option to ```/etc/default/docker``` (ubuntu) or ```/etc/sysconfig/docker``` (centos) and restart Docker:
|
||||
|
||||
|
||||
###Pulling images
|
||||
```Error response from daemon: Get https://myregistrydomain.com/v1/users/: dial tcp myregistrydomain.com:443 getsockopt: connection refused.```
|
||||
|
||||
|
||||
If this private registry supports only HTTP or HTTPS with an unknown CA certificate, please add
|
||||
`--insecure-registry myregistrydomain.com` to the daemon's start up arguments.
|
||||
|
||||
|
||||
In the case of HTTPS, if you have access to the registry's CA certificate, simply place the CA certificate at /etc/docker/certs.d/myregistrydomain.com/ca.crt .
|
||||
|
||||
### Pulling images
|
||||
If the project that the image belongs to is private, you should sign in first:
|
||||
|
||||
```sh
|
||||
@ -149,9 +176,9 @@ You can now pull the image:
|
||||
$ docker pull 10.117.169.182/library/ubuntu:14.04
|
||||
```
|
||||
|
||||
**Note: Replace "10.117.169.182" with the IP address or domain name of your Harbor node.**
|
||||
**Note: Replace "10.117.169.182" with the IP address or domain name of your Harbor node. You cannot pull a unsigned image if you enabled content trust.**
|
||||
|
||||
###Pushing images
|
||||
### Pushing images
|
||||
Before pushing an image, you must create a corresponding project on Harbor web UI.
|
||||
|
||||
First, log in from Docker client:
|
||||
@ -174,16 +201,17 @@ $ docker push 10.117.169.182/demo/ubuntu:14.04
|
||||
|
||||
**Note: Replace "10.117.169.182" with the IP address or domain name of your Harbor node.**
|
||||
|
||||
##Deleting repositories
|
||||
### Deleting repositories
|
||||
|
||||
Repository deletion runs in two steps.
|
||||
|
||||
First, delete a repository in Harbor's UI. This is soft deletion. You can delete the entire repository or just a tag of it. After the soft deletion,
|
||||
the repository is no longer managed in Harbor, however, the files of the repository still remain in Harbor's storage.
|
||||
|
||||
![browse project](img/new_delete_repository.png)
|
||||
![browse project](img/new_delete_repo.png)
|
||||
![browse project](img/new_delete_tag.png)
|
||||
|
||||
**CAUTION: If both tag A and tag B refer to the same image, after deleting tag A, B will also get deleted.**
|
||||
**CAUTION: If both tag A and tag B refer to the same image, after deleting tag A, B will also get deleted. if you enabled content trust, you need to use notary command line tool to delete the tag's signature before you delete an image.**
|
||||
|
||||
Next, delete the actual files of the repository using the registry's garbage collection(GC). Make sure that no one is pushing images or Harbor is not running at all before you perform a GC. If someone were pushing an image while GC is running, there is a risk that the image's layers will be mistakenly deleted which results in a corrupted image. So before running GC, a preferred approach is to stop Harbor first.
|
||||
|
||||
@ -191,15 +219,32 @@ Run the below commands on the host which Harbor is deployed on to preview what f
|
||||
|
||||
```sh
|
||||
$ docker-compose stop
|
||||
$ docker run -it --name gc --rm --volumes-from registry registry:2.5.0 garbage-collect --dry-run /etc/registry/config.yml
|
||||
|
||||
$ docker run -it --name gc --rm --volumes-from registry vmware/registry:photon-2.6.0 garbage-collect --dry-run /etc/registry/config.yml
|
||||
|
||||
```
|
||||
**NOTE:** The above option "--dry-run" will print the progress without removing any data.
|
||||
|
||||
Verify the result of the above test, then use the below commands to perform garbage collection and restart Harbor.
|
||||
|
||||
```sh
|
||||
$ docker run -it --name gc --rm --volumes-from registry registry:2.5.0 garbage-collect /etc/registry/config.yml
|
||||
|
||||
$ docker run -it --name gc --rm --volumes-from registry vmware/registry:photon-2.6.0 garbage-collect /etc/registry/config.yml
|
||||
|
||||
$ docker-compose start
|
||||
```
|
||||
|
||||
For more information about GC, please see [GC](https://github.com/docker/docker.github.io/blob/master/registry/garbage-collection.md).
|
||||
|
||||
### Content trust
|
||||
If you want to enable content trust to ensure that images are signed, please set two environment variables in the command line before pushing or pulling any image:
|
||||
```sh
|
||||
export DOCKER_CONTENT_TRUST=1
|
||||
export DOCKER_CONTENT_TRUST_SERVER=https://10.117.169.182:4443
|
||||
```
|
||||
If you are using a self-signed cert, make sure to copy the CA cert into ```/etc/docker/certs.d/10.117.169.182``` and ```$HOME/.docker/tls/10.117.169.182:4443/```. When an image is signed, it is indicated in the Web UI.
|
||||
**Note: Replace "10.117.169.182" with the IP address or domain name of your Harbor node. In order to use content trust, HTTPS must be enabled in Harbor.**
|
||||
|
||||
|
||||
When an image is signed, it has a tick shown in UI; otherwise, a cross sign(X) is displayed instead.
|
||||
![browse project](img/content_trust.png)
|
||||
|
@ -1,207 +0,0 @@
|
||||
#User Guide of Harbor Virtual Appliance
|
||||
##Overview
|
||||
This guide walks you through the fundamentals of using Harbor virtual appliance. You'll learn how to use Harbor to:
|
||||
|
||||
* Manage your projects.
|
||||
* Manage members of a project.
|
||||
* Replicate projects to a remote registry.
|
||||
* Search projects and repositories.
|
||||
* Manage Harbor system if you are the system administrator:
|
||||
+ Manage users.
|
||||
+ Manage destinations.
|
||||
+ Manage replication policies.
|
||||
* Pull and push images using Docker client.
|
||||
* Delete repositories and images.
|
||||
|
||||
|
||||
##Role Based Access Control
|
||||
|
||||
![rbac](img/rbac.png)
|
||||
|
||||
In Harbor, images are grouped under projects. To access an image, a user should be added as a member into the project of the image. A member can have one of the three roles:
|
||||
|
||||
* **Guest**: Guest has read-only privilege for a specified project.
|
||||
* **Developer**: Developer has read and write privileges for a project.
|
||||
* **ProjectAdmin**: When creating a new project, you will be assigned the "ProjectAdmin" role to the project. Besides read-write privileges, the "ProjectAdmin" also has some management privileges, such as adding and removing members.
|
||||
|
||||
Besides the above three roles, there are two system-wide roles:
|
||||
|
||||
* **SysAdmin**: "SysAdmin" has the most privileges. In addition to the privileges mentioned above, "SysAdmin" can also list all projects, set an ordinary user as administrator and delete users. The public project "library" is also owned by the administrator.
|
||||
* **Anonymous**: When a user is not logged in, the user is considered as an "anonymous" user. An anonymous user has no access to private projects and has read-only access to public projects.
|
||||
|
||||
##User account
|
||||
Harbor supports two authentication modes:
|
||||
|
||||
* **Database(db_auth)**
|
||||
|
||||
Users are stored in the local database.
|
||||
|
||||
A user can register himself/herself in Harbor in this mode. To disable user self-registration, refer to the **[installation guide](installation_guide_ova.md)**. When self-registration is disabled, the system administrator can add users in Harbor.
|
||||
|
||||
When registering or adding a new user, the username and email must be unique in the Harbor system. The password must contain at least 8 characters, less than 20 characters with 1 lowercase letter, 1 uppercase letter and 1 numeric character.
|
||||
|
||||
When you forgot your password, you can follow the below steps to reset the password:
|
||||
|
||||
1. Click the link "Forgot Password" in the sign in page.
|
||||
2. Input the email address entered when you signed up, an email will be sent out to you for password reset.
|
||||
3. After receiving the email, click on the link in the email which directs you to a password reset web page.
|
||||
4. Input your new password and click "Save".
|
||||
|
||||
* **LDAP/Active Directory (ldap_auth)**
|
||||
|
||||
Under this authentication mode, users whose credentials are stored in an external LDAP or AD server can log in to Harbor directly.
|
||||
|
||||
When an LDAP/AD user logs in by *username* and *password*, Harbor binds to the LDAP/AD server with the **"LDAP Search DN"** and **"LDAP Search Password"** described in [installation guide](installation_guide_ova.md). If it successes, Harbor looks up the user under the LDAP entry **"LDAP Base DN"** including substree. The attribute (such as uid, cn) specified by **"LDAP UID"** is used to match a user with the *username*. If a match is found, the user's *password* is verified by a bind request to the LDAP/AD server.
|
||||
|
||||
Self-registration, changing password and resetting password are not supported anymore under LDAP/AD authentication mode because the users are managed by LDAP or AD.
|
||||
|
||||
##Managing projects
|
||||
A project in Harbor contains all repositories of an application. No images can be pushed to Harbor before the project is created. RBAC is applied to a project. There are two types of projects in Harbor:
|
||||
|
||||
* **Public**: All users have the read privilege to a public project, it's convenient for you to share some repositories with others in this way.
|
||||
* **Private**: A private project can only be accessed by users with proper privileges.
|
||||
|
||||
You can create a project after you signed in. Enabling the "Public" checkbox makes the project public.
|
||||
|
||||
![create project](img/new_create_project.png)
|
||||
|
||||
After the project is created, you can browse repositories, users and logs using the navigation tab.
|
||||
|
||||
![browse project](img/new_browse_project.png)
|
||||
|
||||
All logs can be listed by clicking "Logs". You can apply a filter by username, or operations and dates under "Advanced Search".
|
||||
|
||||
![browse project](img/new_project_log.png)
|
||||
|
||||
##Managing members of a project
|
||||
###Adding members
|
||||
You can add members with different roles to an existing project.
|
||||
|
||||
![browse project](img/new_add_member.png)
|
||||
|
||||
###Updating and removing members
|
||||
You can update or remove a member by clicking the icon on the right.
|
||||
|
||||
![browse project](img/new_remove_update_member.png)
|
||||
|
||||
##Replicating images
|
||||
Images can be replicated between Harbor instances. It can be used to transfer images from one data center to another, or from an on-prem registry to an instance in the cloud.
|
||||
|
||||
A replication policy needs to be set up on the source instance to govern the replication process.
|
||||
One key fact about the replication is that only images are replicated between Harbor instances.
|
||||
Users, roles and other information are not replicated. As such, always keep in mind that the user, roles and policy information is individually managed by each Harbor instance.
|
||||
|
||||
The replication is project-based. When a system administrator sets a policy to a project, all repositories under the project will be replicated to the remote registry. A replication job will be scheduled for each repository.
|
||||
If the project does not exist on the remote registry, a new project is created automatically.
|
||||
If the project already exists and the replication user configured in the policy has no write privilege to it,
|
||||
the process will fail.
|
||||
|
||||
When the policy is first enabled, all images of the project are replicated to the remote registry. Images subsequently pushed to the project on the source registry
|
||||
will be incrementally replicated to the remote instance. When an image is deleted from the source registry, the policy ensures that the remote registry deletes the same image as well.
|
||||
Please note, the user and member information will not be replicated.
|
||||
|
||||
Depending on the size of the images and the network condition, the replication requires some time to complete. On the remote registry, an image is not available until
|
||||
all its layers have been synchronized from the source. If a replication job fails due to some network issue, the job will be scheduled for a retry after a few minutes.
|
||||
Always checks the log to see if there is any error of the replication. When a policy is disabled (stopped), Harbor tries to stop all existing jobs. It may take a while
|
||||
before all jobs finish. A policy can be restarted by disabling and then enabling it again.
|
||||
|
||||
To enable image replication, a policy must first be created. Click "Add New Policy" on the "Replication" tab, fill the necessary fields, if there is no destination in the list, you need to create one, and then click "OK", a policy for this project will be created. If "Enable" is chosen, the project will be replicated to the remote immediately.
|
||||
|
||||
**Note:** Set **"Verify Remote Cert"** to off according to the [installation guide](installation_guide_ova.md) if the destination uses a self-signed or untrusted certificate.
|
||||
|
||||
![browse project](img/new_create_policy.png)
|
||||
|
||||
You can enable, disable or delete a policy in the policy list view. Only policies which are disabled can be edited. Only policies which are disabled and have no running jobs can be deleted. If a policy is disabled, the running jobs under it will be stopped.
|
||||
|
||||
Click on a policy, jobs belonging to this policy will be listed. A job represents the progress of replicating a repository to the remote instance.
|
||||
|
||||
![browse project](img/new_policy_list.png)
|
||||
|
||||
##Searching projects and repositories
|
||||
Entering a keyword in the search field at the top lists all matching projects and repositories. The search result includes both public and private repositories you have access privilege to.
|
||||
|
||||
![browse project](img/new_search.png)
|
||||
|
||||
##Administrator options
|
||||
###Managing user
|
||||
Administrator can add "administrator" role to an ordinary user by toggling the switch under "Administrator". To delete a user, click on the recycle bin icon.
|
||||
|
||||
![browse project](img/new_set_admin_remove_user.png)
|
||||
|
||||
###Managing destination
|
||||
You can list, add, edit and delete destinations in the "Destination" tab. Only destinations which are not referenced by any policies can be edited.
|
||||
|
||||
![browse project](img/new_manage_destination.png)
|
||||
|
||||
###Managing replication
|
||||
You can list, edit, enable and disable policies in the "Replication" tab. Make sure the policy is disabled before you edit it.
|
||||
|
||||
![browse project](img/new_manage_replication.png)
|
||||
|
||||
##Pulling and pushing images using Docker client
|
||||
|
||||
**NOTE: Harbor only supports Registry V2 API. You need to use Docker client 1.6.0 or higher.**
|
||||
|
||||
Harbor uses HTTPS for secure communication by default. A self-signed certificate is generated at first boot based on its FQDN (Fully Qualified Domain Name) or IP address. If you use Docker client to interact with it, there are two options you can choose:
|
||||
|
||||
1. Trust the certificate of Harbor's CA
|
||||
Refer to the "Getting Certificate of Harbor's CA" part of [installation guide](installation_guide_ova.md).
|
||||
2. Set "--insecure-registry" option
|
||||
Add "--insecure-registry" option to /etc/default/docker (ubuntu) or /etc/sysconfig/docker (centos) and restart Docker service.
|
||||
|
||||
If Harbor is configured as using HTTP, just set the "--insecure-registry" option.
|
||||
|
||||
If the certificate used by Harbor is signed by a trusted authority, Docker should work without any additional configuration.
|
||||
|
||||
###Pulling images
|
||||
If the project that the image belongs to is private, you should sign in first:
|
||||
|
||||
```sh
|
||||
$ docker login 10.117.169.182
|
||||
```
|
||||
|
||||
You can now pull the image:
|
||||
|
||||
```sh
|
||||
$ docker pull 10.117.169.182/library/ubuntu:14.04
|
||||
```
|
||||
|
||||
**Note: Replace "10.117.169.182" with the IP address or domain name of your Harbor node.**
|
||||
|
||||
###Pushing images
|
||||
Before pushing an image, you must create a corresponding project on Harbor web UI.
|
||||
|
||||
First, log in from Docker client:
|
||||
|
||||
```sh
|
||||
$ docker login 10.117.169.182
|
||||
```
|
||||
|
||||
Tag the image:
|
||||
|
||||
```sh
|
||||
$ docker tag ubuntu:14.04 10.117.169.182/demo/ubuntu:14.04
|
||||
```
|
||||
|
||||
Push the image:
|
||||
|
||||
```sh
|
||||
$ docker push 10.117.169.182/demo/ubuntu:14.04
|
||||
```
|
||||
|
||||
**Note: Replace "10.117.169.182" with the IP address or domain name of your Harbor node.**
|
||||
|
||||
##Deleting repositories
|
||||
|
||||
Repository deletion runs in two steps.
|
||||
|
||||
First, delete a repository in Harbor's UI. This is soft deletion. You can delete the entire repository or just a tag of it. After the soft deletion,
|
||||
the repository is no longer managed in Harbor, however, the files of the repository still remain in Harbor's storage.
|
||||
|
||||
![browse project](img/new_delete_repository.png)
|
||||
|
||||
**CAUTION: If both tag A and tag B refer to the same image, after deleting tag A, B will also get deleted.**
|
||||
|
||||
Next, set **"Garbage Collection"** to true according to the [installation guide](installation_guide_ova.md)(skip this step if this flag has already been set) and reboot the VM, Harbor will perform garbage collection when it boots up.
|
||||
|
||||
For more information about garbage collection, please see Docker's document on [GC](https://github.com/docker/docker.github.io/blob/master/registry/garbage-collection.md).
|
@ -1,4 +1,4 @@
|
||||
FROM mysql:5.6
|
||||
FROM mysql:5.6.35
|
||||
|
||||
WORKDIR /tmp
|
||||
|
||||
|
@ -13,6 +13,7 @@ if [ ! -d '/var/lib/mysql/mysql' -a "${1%_safe}" = 'mysqld' ]; then
|
||||
# These statements _must_ be on individual lines, and _must_ end with
|
||||
# semicolons (no line breaks or comments are permitted).
|
||||
# TODO proper SQL escaping on ALL the things D:
|
||||
printf -v MYSQL_ROOT_PASSWORD "%q" ${MYSQL_ROOT_PASSWORD}
|
||||
TEMP_FILE='/tmp/mysql-first-time.sql'
|
||||
cat > "$TEMP_FILE" <<-EOSQL
|
||||
DELETE FROM mysql.user ;
|
||||
|
39
make/common/templates/adminserver/env
Normal file
@ -0,0 +1,39 @@
|
||||
LOG_LEVEL=debug
|
||||
EXT_ENDPOINT=$ui_url
|
||||
AUTH_MODE=$auth_mode
|
||||
SELF_REGISTRATION=$self_registration
|
||||
LDAP_URL=$ldap_url
|
||||
LDAP_SEARCH_DN=$ldap_searchdn
|
||||
LDAP_SEARCH_PWD=$ldap_search_pwd
|
||||
LDAP_BASE_DN=$ldap_basedn
|
||||
LDAP_FILTER=$ldap_filter
|
||||
LDAP_UID=$ldap_uid
|
||||
LDAP_SCOPE=$ldap_scope
|
||||
LDAP_TIMEOUT=$ldap_timeout
|
||||
DATABASE_TYPE=mysql
|
||||
MYSQL_HOST=mysql
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_USR=root
|
||||
MYSQL_PWD=$db_password
|
||||
MYSQL_DATABASE=registry
|
||||
REGISTRY_URL=http://registry:5000
|
||||
TOKEN_SERVICE_URL=http://ui/service/token
|
||||
EMAIL_HOST=$email_host
|
||||
EMAIL_PORT=$email_port
|
||||
EMAIL_USR=$email_usr
|
||||
EMAIL_PWD=$email_pwd
|
||||
EMAIL_SSL=$email_ssl
|
||||
EMAIL_FROM=$email_from
|
||||
EMAIL_IDENTITY=$email_identity
|
||||
HARBOR_ADMIN_PASSWORD=$harbor_admin_password
|
||||
PROJECT_CREATION_RESTRICTION=$project_creation_restriction
|
||||
VERIFY_REMOTE_CERT=$verify_remote_cert
|
||||
MAX_JOB_WORKERS=$max_job_workers
|
||||
UI_SECRET=$ui_secret
|
||||
JOBSERVICE_SECRET=$jobservice_secret
|
||||
TOKEN_EXPIRATION=$token_expiration
|
||||
CFG_EXPIRATION=5
|
||||
GODEBUG=netdns=cgo
|
||||
ADMIRAL_URL=$admiral_url
|
||||
WITH_NOTARY=$with_notary
|
||||
RESET=false
|
@ -1,15 +1,5 @@
|
||||
MYSQL_HOST=mysql
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_USR=root
|
||||
MYSQL_PWD=$db_password
|
||||
UI_SECRET=$ui_secret
|
||||
SECRET_KEY=$secret_key
|
||||
CONFIG_PATH=/etc/jobservice/app.conf
|
||||
REGISTRY_URL=http://registry:5000
|
||||
VERIFY_REMOTE_CERT=$verify_remote_cert
|
||||
MAX_JOB_WORKERS=$max_job_workers
|
||||
LOG_LEVEL=debug
|
||||
LOG_DIR=/var/log/jobs
|
||||
CONFIG_PATH=/etc/jobservice/app.conf
|
||||
UI_SECRET=$ui_secret
|
||||
JOBSERVICE_SECRET=$jobservice_secret
|
||||
GODEBUG=netdns=cgo
|
||||
EXT_ENDPOINT=$ui_url
|
||||
TOKEN_ENDPOINT=http://ui
|
||||
|
@ -21,6 +21,12 @@ http {
|
||||
server ui:80;
|
||||
}
|
||||
|
||||
log_format timed_combined '$$remote_addr - '
|
||||
'"$$request" $$status $$body_bytes_sent '
|
||||
'"$$http_referer" "$$http_user_agent" '
|
||||
'$$request_time $$upstream_response_time $$pipe';
|
||||
|
||||
access_log /dev/stdout timed_combined;
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
|
@ -8,11 +8,11 @@ events {
|
||||
|
||||
http {
|
||||
tcp_nodelay on;
|
||||
include /etc/nginx/conf.d/*.upstream.conf;
|
||||
|
||||
# this is necessary for us to be able to disable request buffering in all cases
|
||||
proxy_http_version 1.1;
|
||||
|
||||
|
||||
upstream registry {
|
||||
server registry:5000;
|
||||
}
|
||||
@ -20,7 +20,15 @@ http {
|
||||
upstream ui {
|
||||
server ui:80;
|
||||
}
|
||||
|
||||
log_format timed_combined '$$remote_addr - '
|
||||
'"$$request" $$status $$body_bytes_sent '
|
||||
'"$$http_referer" "$$http_user_agent" '
|
||||
'$$request_time $$upstream_response_time $$pipe';
|
||||
|
||||
access_log /dev/stdout timed_combined;
|
||||
|
||||
include /etc/nginx/conf.d/*.server.conf;
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
|
33
make/common/templates/nginx/notary.server.conf
Normal file
@ -0,0 +1,33 @@
|
||||
server {
|
||||
listen 4443 ssl;
|
||||
|
||||
# ssl
|
||||
ssl_certificate $ssl_cert;
|
||||
ssl_certificate_key $ssl_cert_key;
|
||||
|
||||
# recommendations from https://raymii.org/s/tutorials/strong_ssl_security_on_nginx.html
|
||||
ssl_protocols tlsv1.1 tlsv1.2;
|
||||
ssl_ciphers '!aNULL:kECDH+AESGCM:ECDH+AESGCM:RSA+AESGCM:kECDH+AES:ECDH+AES:RSA+AES:';
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_session_cache shared:ssl:10m;
|
||||
|
||||
# disable any limits to avoid http 413 for large image uploads
|
||||
client_max_body_size 0;
|
||||
|
||||
# required to avoid http 411: see issue #1486 (https://github.com/docker/docker/issues/1486)
|
||||
chunked_transfer_encoding on;
|
||||
|
||||
location /v2/ {
|
||||
proxy_pass http://notary-server/v2/;
|
||||
proxy_set_header Host $$http_host;
|
||||
proxy_set_header X-Real-IP $$remote_addr;
|
||||
proxy_set_header X-Forwarded-For $$proxy_add_x_forwarded_for;
|
||||
|
||||
# When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
|
||||
proxy_set_header X-Forwarded-Proto $$scheme;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
}
|
||||
}
|
||||
|
4
make/common/templates/nginx/notary.upstream.conf
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
upstream notary-server {
|
||||
server notary-server:4443;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
CREATE DATABASE IF NOT EXISTS `notaryserver`;
|
||||
|
||||
CREATE USER "server"@"notary-server.%" IDENTIFIED BY "";
|
||||
|
||||
GRANT
|
||||
ALL PRIVILEGES ON `notaryserver`.*
|
||||
TO "server"@"notary-server.%"
|
@ -0,0 +1,7 @@
|
||||
CREATE DATABASE IF NOT EXISTS `notarysigner`;
|
||||
|
||||
CREATE USER "signer"@"notary-signer.%" IDENTIFIED BY "";
|
||||
|
||||
GRANT
|
||||
ALL PRIVILEGES ON `notarysigner`.*
|
||||
TO "signer"@"notary-signer.%";
|
32
make/common/templates/notary/notary-signer-ca.crt
Normal file
@ -0,0 +1,32 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFhjCCA26gAwIBAgIJALJdsE+BUxypMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV
|
||||
BAYTAlVTMQswCQYDVQQIDAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEPMA0G
|
||||
A1UECgwGRG9ja2VyMRowGAYDVQQDDBFOb3RhcnkgVGVzdGluZyBDQTAeFw0xNzAx
|
||||
MjMwNjAzMzZaFw0yNzAxMjEwNjAzMzZaMF8xCzAJBgNVBAYTAlVTMQswCQYDVQQI
|
||||
DAJDQTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzEPMA0GA1UECgwGRG9ja2VyMRow
|
||||
GAYDVQQDDBFOb3RhcnkgVGVzdGluZyBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
|
||||
ADCCAgoCggIBALIZNBcIoQDJql5w+XULXq9W3tmD47xnf+IG4u7hkDVPCT4xRG74
|
||||
LBoSuFyPUrfT+tsibMlNG6XRtSfLQdNNeQuyIuiilNXV0kXB0RR3TrhxCaKdhRU5
|
||||
oQGfpYMvbPNFB7WU/5aAiQutHH85hEMPECf1qPjq8YlUaXJLGFY3WRkW+OOBZ78U
|
||||
00PqKlvC1kR/NbsV3IkMrO+vWWJQrPFusyYjQ511eQXnRtt8P0Qic0azPffQDVxC
|
||||
WUe47hmdQ1AULbxQ9AZcPlMI7UFqo+/w/4hPEGJMeOWirLvHLXg4nsOwy7DfWl/n
|
||||
MqLdJOC/KNfQVAQtkteeZZkkIIV1gxTPYsJqPNwkP9GdJK1A8NW1ef75v7xbQCPY
|
||||
03QQonBEK7ny7b1xXGGgJzXvK9RP0UUwjt/815c4d0cgUHsy4yuvl2F44EObRshk
|
||||
fjJVsN/0wrtq4QLE5ZvbeO+7to8dLcRxkmB8axhxahega7akUyY0WxZ+iSn6fzft
|
||||
/xeCcs/L10V5z0kK4PbiNnooDzV4B6Dy/5oyNExw0jgpD0mzOK5aLb0tXGqFT/ZJ
|
||||
9vydelBq5q4jLV7SHhHM1dBJSv1fl7vOpDlEr7LBd4YAO2BowoyGLHtLhgYybXF+
|
||||
CZ9ywPb1dIIcdK5IVeZECNHMSBuhCRZUu+aun8tRcdSgLEX7mQ/GKWELAgMBAAGj
|
||||
RTBDMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYDVR0PAQH/BAQDAgFGMB0GA1UdDgQW
|
||||
BBSWWbcCebeEgZlWk2/k+abh+bEFpDANBgkqhkiG9w0BAQsFAAOCAgEAQ9gA3Q4b
|
||||
r2+ZJdIDoDzCNdtHQbb/d1NiUP/Na1MFo7omR3MnKGXy3dIp9IrQq6ROhlqUhDvl
|
||||
pZegYhTbunTVv1KKJ+5n1hY6pG/Jr8oLY3b9i4qwDLKfQGm5PmrfwAtqbLSfY2M0
|
||||
2AZyAhCdGbqB7WpTdG1J7DzGbVVWAtS05e24Mu0qZJvpHdtl4+t89vXgJ/bPrPxF
|
||||
cpAlT9DOtobTEqrXZeS937F1qNyIgyBki+7mtxkwng5cf3zQM2BJ9lSFQJOBSRDr
|
||||
haMcnaPI4pknO7OfYf5W9LaS1Dx/U/NeMBfnVBd9NjUw+TMjy2MdMLUaLa9EF7Jo
|
||||
Gjk+fKaTaUgO8I487wHPMeoEA4A4dEePzGrybRLfl1ZYGQ0xcgunz64n2xfQIy2y
|
||||
swiyaofYlLxzHzOL0N+Y76P0ic37t9R2F5ggNhfbXhClK2h4HmdjRRRt3VkxR4AD
|
||||
7OM09bEhlZby34HOlCaC0PHKwYBMjneAG3ycPN88YTMYR2/KizExe71ayNwX2KHL
|
||||
ib1nOZgZT6s+YvgsZ7lRmMD4iqjuAEh5SRAcWlolVif8bAy09BkY1vwrtgV73q88
|
||||
heEbsCE1fsfk1OfH5W4yjjiSDZFRt5oTCPQWJp+2P0RJ9LCxcbf0RrCg3hg5rD9N
|
||||
lVTA0dsixv5zF3wTuad9inhk9Rmlq1KoaqA=
|
||||
-----END CERTIFICATE-----
|
32
make/common/templates/notary/notary-signer.crt
Normal file
@ -0,0 +1,32 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFdjCCA14CCQCeVwANSZmmiDANBgkqhkiG9w0BAQsFADCBhDELMAkGA1UEBhMC
|
||||
VVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCVBhbG8gQWx0bzEVMBMG
|
||||
A1UECgwMVk13YXJlLCBJbmMuMQ8wDQYDVQQLDAZIYXJib3IxJDAiBgNVBAMMG1Nl
|
||||
bGYtc2lnbmVkIGJ5IFZNd2FyZSwgSW5jLjAeFw0xNzAzMjQwNTMyMDBaFw0yNzAz
|
||||
MjIwNTMyMDBaMHUxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIw
|
||||
EAYDVQQHDAlQYWxvIEFsdG8xFTATBgNVBAoMDFZNd2FyZSwgSW5jLjEPMA0GA1UE
|
||||
CwwGSGFyYm9yMRUwEwYDVQQDDAxub3RhcnlzaWduZXIwggIiMA0GCSqGSIb3DQEB
|
||||
AQUAA4ICDwAwggIKAoICAQC6TV2RCoH8d1g6xFvDo4FL9v+pGLe5+bu9ryjTaLbN
|
||||
dH/Cmf5/8WrmgJ3vG2Ksk796J7qsVddwvQkZn6NwDm2Tm+ETMCG85yEA3jl4Kr9R
|
||||
XfWHYWEavv0vsq6M+bUSSq7VJAhgk4wfx6qJBnFX2qKpODeYLHaHxU1EnIXrStNf
|
||||
IqR4Eu0Xre8jAkzrDdaFy/KnX4HGgNdz413CXzBCKEuu3VJj07ZvonnTzOgoLvh8
|
||||
+PCoQ2M4OBPT9gHqUov1I8nWnrjc+HuM1BW3YIGCB5TV9x0Y7hjvkr4E38gbJURj
|
||||
uDwg8jof4lMRmU/FHXFLt1ucGwNFUJdPwI7dyEKRA03Lr7htfP5sa9tmv3L93dKD
|
||||
po1gW1LsfiM3Cur5jARM/hBA+eYJr12Laf9oL59r8JmweqF3zRSwGSY336XoR/Fv
|
||||
/PAFs9vfKKWZp0uiRtuY9JZNRTF8trnfNf1957bND+DS2HWPmWkw4yK6CGa0s55X
|
||||
adiDt4gDFvKjl68dBWZoHutY+cZy/hK1D5uqagcX1kzbr/Pzy1gsq9FBBwaTJqBu
|
||||
YIAsSuzP+7NNZXoPd3rg13V93pbZr8eQN5VOQIBZK83xZEtHSJBEdUSuBOo3JS7j
|
||||
/rjEnspRqOI4soFnx1vaK0TrRyzJ5KBOuGpW4u8/ZUdIq8KIE30Mj/XI/sgAPr5j
|
||||
UQIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQBjqYBm/FRqyMH2hnHA0TMXY/WPufJ8
|
||||
TX10daELCAYJCEETXmUt1i7dnFxdAZXTnHENHdNYiS4nGBfqMLmODtcAamcv6Dcl
|
||||
JnyQPt3QlCDPKkcHgz3y4tvDDx6M5rFWYzN9QLiWAYrunIk1R4Jj7FODrM6/NODE
|
||||
0Mz1czWfsmLfX/jF80SsxnY1DCLKGgo6/RID3xTp4eIMboxCfeH2/yDA+6YPyYbV
|
||||
Si4ccwo9Foq0IYU8bimPNTyBQ0N+8ajcn328ql6aazmr894Ch5pWA3Qxaa98FcKS
|
||||
zokBvmmCuvCJ9HOmxKWdFEhSRS9GWxn7wg78UIlLP/8RfUrsecBJHgyhWRA7Qs3K
|
||||
keiG68Zrhn456IdMxjCZXgJ7gAAe77n4Cz8sFEHAvnAg9JLNEHuEBV5H1Hb7TzET
|
||||
k0lPiEY78QjutOpqHsWiagqSjlGEMqKI9c8WxXHh9030T/6NnWkdXFo+4HaEZEpp
|
||||
0JryASS53B5SwLIPrn0Y2/io/kRgbglGktPt6Ex0DwW3f96lcz3me34Nw+HOYYnz
|
||||
b0cz7JqJZgFXfEnykic3IwZs7m7Xrl9B/vvaVub9Fb5LQ7rIzrO7VkoILov/G41B
|
||||
Pd4/kagjXDTWd+UBMvZF6YGjr+TUZi5ooi7bvQ3X6N9WNYKW4a1DOokz9janStiL
|
||||
MrTKyOEOBi0Aew==
|
||||
-----END CERTIFICATE-----
|
52
make/common/templates/notary/notary-signer.key
Normal file
@ -0,0 +1,52 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQC6TV2RCoH8d1g6
|
||||
xFvDo4FL9v+pGLe5+bu9ryjTaLbNdH/Cmf5/8WrmgJ3vG2Ksk796J7qsVddwvQkZ
|
||||
n6NwDm2Tm+ETMCG85yEA3jl4Kr9RXfWHYWEavv0vsq6M+bUSSq7VJAhgk4wfx6qJ
|
||||
BnFX2qKpODeYLHaHxU1EnIXrStNfIqR4Eu0Xre8jAkzrDdaFy/KnX4HGgNdz413C
|
||||
XzBCKEuu3VJj07ZvonnTzOgoLvh8+PCoQ2M4OBPT9gHqUov1I8nWnrjc+HuM1BW3
|
||||
YIGCB5TV9x0Y7hjvkr4E38gbJURjuDwg8jof4lMRmU/FHXFLt1ucGwNFUJdPwI7d
|
||||
yEKRA03Lr7htfP5sa9tmv3L93dKDpo1gW1LsfiM3Cur5jARM/hBA+eYJr12Laf9o
|
||||
L59r8JmweqF3zRSwGSY336XoR/Fv/PAFs9vfKKWZp0uiRtuY9JZNRTF8trnfNf19
|
||||
57bND+DS2HWPmWkw4yK6CGa0s55XadiDt4gDFvKjl68dBWZoHutY+cZy/hK1D5uq
|
||||
agcX1kzbr/Pzy1gsq9FBBwaTJqBuYIAsSuzP+7NNZXoPd3rg13V93pbZr8eQN5VO
|
||||
QIBZK83xZEtHSJBEdUSuBOo3JS7j/rjEnspRqOI4soFnx1vaK0TrRyzJ5KBOuGpW
|
||||
4u8/ZUdIq8KIE30Mj/XI/sgAPr5jUQIDAQABAoICAQCqIgbFcqwcK7zWBgWrFsD3
|
||||
53u4J4t4+df6NGB7F9CAtdgKlej1XDl8gI46Em89HLwqyOdPhCD3opoR3Vg69+IX
|
||||
f62+gSD+SrA4A7jFxXvryXt0g3hTHYFHssx2j39NUghxOrOvxm6bgxJ4ifqt+Uq8
|
||||
cEtM26Xu/T4/3xTpN+7pnVBHGzmLe1q8RNiLe5qhmwtgz/ZKmdSnz0YLQDRo5jWf
|
||||
Xhxkb63WKrFIu4JzV9my/v9/GfMdHxD0a196ZqHLX0Buj4pQuVbS18dxLF94qIXC
|
||||
FCZtYtpAxmhjOR2btJ/M1S2MBMkR3vRvSOuxHd8d/zdYys5k2WElArs1TDGGDldW
|
||||
jp3FYkoygsdWTs056HM1Y9F8dV2KAWfAhEQD8mBIGVjMrCqpnyZcK6JkqVg9c7YW
|
||||
IYQ2JRwsHq58FMNa3TLTvf/OClhEfSbRWAF0AhMTpnSUgP06cbJeXyzqzHdE37hv
|
||||
74OBx7KNoS+PEQ3lVgbHsWoUzf3SqB1IOzLyzuEUgHqON2GKmmCNcRMBi3DuV9tw
|
||||
Q8LWynNxhD8vyBkmo0kAd/FwgXrxJTGdYvxyn29I7QanCTH7o8wtjSE0jj9Qo7oC
|
||||
McAYGR6oTAjrT78KhI7aZJU5nuA6ySSCJRa6et1CC+SseWknyMMJ5HTo8l7jjXJA
|
||||
9hjNGGs6giOxznizf+2YAQKCAQEA9wRQk4yN402tfuicvfQBnFUtcpqctWSgGc0T
|
||||
qzWJgH/W07FMUHzAvqCgsYMMaeteXOMZH7jijvtIlhYfIg5w+RJ9PSsSu680OzGN
|
||||
R31+l2B/QzRAHUJ6+OVgWxAn6awU1mYLaiwVmSNWEnjAPE4XeSK708OOganI3pBQ
|
||||
8zOHj+j6uV8ddG79D6FqNJHAQwpou/p+XO/BGDFgX22x4F68Z0gCQcmoyAE7ppOp
|
||||
dqq3lPoDbRQ02/5cqaIA6dhmfjK2cpz4y1nUxffzY7qJjpoB/YSdR66cCNiYcJzp
|
||||
fMVBXhF9Iyj/Cah1w+hc0NOy9dW15afFaLFK0zrtAzEaVxH/0QKCAQEAwRPOwSCl
|
||||
XrMYXmc91TF6XbhErILHK/pIEOIMF09KNJvSjY0188Ram/pFbPRYh0cIyASmRGXL
|
||||
Qq5B1Qi0vx5TCq1OCrW2yeE7zboAlnADhk1u9N8YmL6JrCKVGQO7wFD3V8uphXdM
|
||||
tixNa5WvJ6eE5Vq+SVy99V5pQgb8ErrISlW4MYK7LI7DruSDuM2tHtiOcXcdTVej
|
||||
1stXJZkH46RYvxxid9tRzfiB8K5ziZfLwPNf2wRyj1J4ojn5pPNhhfkjJ24LCZGt
|
||||
JxwSXqdP+4x7by6x3mU+hutU/lF3jl+0edSnU0cZ6lvuq2T5YGgda/VXlv1ZFQUw
|
||||
rwUXD9unU+aLgQKCAQEA9R74/pI5sthAVHFsKStb9dComtNGstI59aCF5h3oZvV1
|
||||
Lvj/q9dARWqMS9qplOoV58MMCWikmhJNw3IMTvVZsjBgyzRVEJ4aDKttcQXde0Ys
|
||||
w3m0LdTsxtSHu5XapY032FHG/gLlI+Pm48mjqbQsou6OyOOEJLNhO0qmqc/2tB4T
|
||||
v6PdTM9enAYnqCcCTQSlTfSTNJJOYT2OTuRB4U7hUvQoGTSOInrmwLRDNBjQuCso
|
||||
/zNQCQbu2P6EPYmam5yjZDTUxqZL+G/GvK49Fp9JXlQc5ycke7rD+uwa3s+3wCtG
|
||||
rH9gJitfQZrxj+Cj9EOwj0bfJLbac6ZD0CkH5GNeIQKCAQBdoGFOPapzdZ2HicDu
|
||||
NQQFlmmWzgQPS1rO9Q6v7v8o67b6dVOIVdsqb/5ii0qyrruPYtHNsR8TwrShvYsI
|
||||
cogKUWfawatV0ibR6DSIvuC2q632iIjA6QSRuGNcsfbFl32Z0WTvF57XaDxSw08g
|
||||
h5dmMM69fH+REKsyHXj3DCQ8B70+JQrm3IP/t0g4wWQF5TWNyBkpfCoy6n/j94Vf
|
||||
2j4+zmDhhjTxEGTSdYYJXtarRllhN5Ll9TQSVtK8LllIQjvNzwsDJOU2ZeJyi+e5
|
||||
L7Jbg+U01xuvCUc52/+Bxt8ZhQlu1Le4ccQW0Ows19AMnfhPe6NLEi09cdZxFi7Z
|
||||
/J4BAoIBABCzkBDFxZdfWYt69VBt9PSG8eJ6avny3hXCtKaHIQb+aD5nKjRP0DVh
|
||||
gyutCo6RasMEc6D1tJGyR/Xvhm64q4JPb5UbSaRQiVYKdgRtMM9pZeBkcBtNs18K
|
||||
yMx5ajgYorrbi86hXHX7q+JYP8MCbcqqAUSl/Hi8nPxc1foTiCNDf4kGoHvXmoxt
|
||||
0tA65tFFQhEA6KBn68SDkyTsl/zb5Sx0GJY4kZkOeF3GaxPFX12skgXv95GJUskX
|
||||
88RJsH4Qqqtzbzj8R241BH8OrcOoyELc6xPioEqUHKVxSIf2ylITbj0UQHd2u0mN
|
||||
tajKl+aoc+CDxUYbilzhhKetWWF/cJY=
|
||||
-----END PRIVATE KEY-----
|
28
make/common/templates/notary/server-config.json
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
"server": {
|
||||
"http_addr": ":4443"
|
||||
},
|
||||
"trust_service": {
|
||||
"type": "remote",
|
||||
"hostname": "notarysigner",
|
||||
"port": "7899",
|
||||
"tls_ca_file": "./notary-signer-ca.crt",
|
||||
"key_algorithm": "ecdsa"
|
||||
},
|
||||
"logging": {
|
||||
"level": "debug"
|
||||
},
|
||||
"storage": {
|
||||
"backend": "mysql",
|
||||
"db_url": "server@tcp(mysql:3306)/notaryserver?parseTime=True"
|
||||
},
|
||||
"auth": {
|
||||
"type": "token",
|
||||
"options": {
|
||||
"realm": "$token_endpoint/service/token",
|
||||
"service": "harbor-notary",
|
||||
"issuer": "harbor-token-issuer",
|
||||
"rootcertbundle": "/config/root.crt"
|
||||
}
|
||||
}
|
||||
}
|
15
make/common/templates/notary/signer-config.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"server": {
|
||||
"grpc_addr": ":7899",
|
||||
"tls_cert_file": "./notary-signer.crt",
|
||||
"tls_key_file": "./notary-signer.key"
|
||||
},
|
||||
"logging": {
|
||||
"level": "debug"
|
||||
},
|
||||
"storage": {
|
||||
"backend": "mysql",
|
||||
"db_url": "signer@tcp(mysql:3306)/notarysigner?parseTime=True",
|
||||
"default_alias":"defaultalias"
|
||||
}
|
||||
}
|
2
make/common/templates/notary/signer_env
Normal file
@ -0,0 +1,2 @@
|
||||
NOTARY_SIGNER_DEFAULTALIAS=$alias
|
||||
|
@ -20,10 +20,10 @@ http:
|
||||
addr: localhost:5001
|
||||
auth:
|
||||
token:
|
||||
issuer: registry-token-issuer
|
||||
issuer: harbor-token-issuer
|
||||
realm: $ui_url/service/token
|
||||
rootcertbundle: /etc/registry/root.crt
|
||||
service: token-service
|
||||
service: harbor-registry
|
||||
|
||||
notifications:
|
||||
endpoints:
|
||||
|
@ -1,18 +1,6 @@
|
||||
appname = registry
|
||||
appname = Harbor
|
||||
runmode = dev
|
||||
|
||||
[lang]
|
||||
types = en-US|zh-CN
|
||||
names = en-US|zh-CN
|
||||
enablegzip = true
|
||||
|
||||
[dev]
|
||||
httpport = 80
|
||||
|
||||
[mail]
|
||||
identity = $email_identity
|
||||
host = $email_server
|
||||
port = $email_server_port
|
||||
username = $email_username
|
||||
password = $email_password
|
||||
from = $email_from
|
||||
ssl = $email_ssl
|
||||
|
@ -1,29 +1,5 @@
|
||||
MYSQL_HOST=mysql
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_USR=root
|
||||
MYSQL_PWD=$db_password
|
||||
REGISTRY_URL=http://registry:5000
|
||||
JOB_SERVICE_URL=http://jobservice
|
||||
UI_URL=http://ui
|
||||
CONFIG_PATH=/etc/ui/app.conf
|
||||
EXT_REG_URL=$hostname
|
||||
HARBOR_ADMIN_PASSWORD=$harbor_admin_password
|
||||
AUTH_MODE=$auth_mode
|
||||
LDAP_URL=$ldap_url
|
||||
LDAP_SEARCH_DN=$ldap_searchdn
|
||||
LDAP_SEARCH_PWD=$ldap_search_pwd
|
||||
LDAP_BASE_DN=$ldap_basedn
|
||||
LDAP_FILTER=$ldap_filter
|
||||
LDAP_UID=$ldap_uid
|
||||
LDAP_SCOPE=$ldap_scope
|
||||
UI_SECRET=$ui_secret
|
||||
SECRET_KEY=$secret_key
|
||||
SELF_REGISTRATION=$self_registration
|
||||
USE_COMPRESSED_JS=$use_compressed_js
|
||||
LOG_LEVEL=debug
|
||||
CONFIG_PATH=/etc/ui/app.conf
|
||||
UI_SECRET=$ui_secret
|
||||
JOBSERVICE_SECRET=$jobservice_secret
|
||||
GODEBUG=netdns=cgo
|
||||
EXT_ENDPOINT=$ui_url
|
||||
TOKEN_ENDPOINT=http://ui
|
||||
VERIFY_REMOTE_CERT=$verify_remote_cert
|
||||
TOKEN_EXPIRATION=$token_expiration
|
||||
PROJECT_CREATION_RESTRICTION=$project_creation_restriction
|
||||
|
12
make/dev/adminserver/Dockerfile
Normal file
@ -0,0 +1,12 @@
|
||||
FROM golang:1.7.3
|
||||
|
||||
MAINTAINER yinw@vmware.com
|
||||
|
||||
COPY . /go/src/github.com/vmware/harbor
|
||||
|
||||
WORKDIR /go/src/github.com/vmware/harbor/src/adminserver
|
||||
|
||||
RUN go build -v -a -o /go/bin/harbor_adminserver \
|
||||
&& chmod u+x /go/bin/harbor_adminserver
|
||||
WORKDIR /go/bin/
|
||||
ENTRYPOINT ["/go/bin/harbor_adminserver"]
|
@ -3,18 +3,24 @@ services:
|
||||
log:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: make/ubuntu/log/Dockerfile
|
||||
dockerfile: make/photon/log/Dockerfile
|
||||
container_name: harbor-log
|
||||
restart: always
|
||||
volumes:
|
||||
- /var/log/harbor/:/var/log/docker/
|
||||
- /var/log/harbor/:/var/log/docker/:z
|
||||
ports:
|
||||
- 1514:514
|
||||
- 127.0.0.1:1514:514
|
||||
networks:
|
||||
- harbor
|
||||
registry:
|
||||
image: library/registry:2.5.0
|
||||
image: vmware/registry:photon-2.6.0
|
||||
container_name: registry
|
||||
restart: always
|
||||
volumes:
|
||||
- /data/registry:/storage
|
||||
- ../common/config/registry/:/etc/registry/
|
||||
- /data/registry:/storage:z
|
||||
- ./common/config/registry/:/etc/registry/:z
|
||||
networks:
|
||||
- harbor
|
||||
environment:
|
||||
- GODEBUG=netdns=cgo
|
||||
command:
|
||||
@ -23,65 +29,105 @@ services:
|
||||
- log
|
||||
logging:
|
||||
driver: "syslog"
|
||||
options:
|
||||
options:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "registry"
|
||||
mysql:
|
||||
build: ../common/db/
|
||||
container_name: harbor-db
|
||||
restart: always
|
||||
volumes:
|
||||
- /data/database:/var/lib/mysql
|
||||
- /data/database:/var/lib/mysql:z
|
||||
networks:
|
||||
- harbor
|
||||
env_file:
|
||||
- ../common/config/db/env
|
||||
depends_on:
|
||||
- log
|
||||
logging:
|
||||
driver: "syslog"
|
||||
options:
|
||||
options:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "mysql"
|
||||
adminserver:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: make/dev/adminserver/Dockerfile
|
||||
container_name: harbor-adminserver
|
||||
env_file:
|
||||
- ../common/config/adminserver/env
|
||||
restart: always
|
||||
volumes:
|
||||
- /data/config/:/etc/adminserver/config/:z
|
||||
- /data/secretkey:/etc/adminserver/key:z
|
||||
- /data/:/data/:z
|
||||
depends_on:
|
||||
- log
|
||||
networks:
|
||||
- harbor
|
||||
logging:
|
||||
driver: "syslog"
|
||||
options:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "adminserver"
|
||||
ui:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: make/dev/ui/Dockerfile
|
||||
container_name: harbor-ui
|
||||
env_file:
|
||||
- ../common/config/ui/env
|
||||
restart: always
|
||||
volumes:
|
||||
- ../common/config/ui/app.conf:/etc/ui/app.conf
|
||||
- ../common/config/ui/private_key.pem:/etc/ui/private_key.pem
|
||||
- ./common/config/ui/app.conf:/etc/ui/app.conf:z
|
||||
- ./common/config/ui/private_key.pem:/etc/ui/private_key.pem:z
|
||||
- /data/secretkey:/etc/ui/key:z
|
||||
- /data/ca_download/:/etc/ui/ca/:z
|
||||
networks:
|
||||
- harbor
|
||||
depends_on:
|
||||
- log
|
||||
- adminserver
|
||||
- registry
|
||||
logging:
|
||||
driver: "syslog"
|
||||
options:
|
||||
options:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "ui"
|
||||
jobservice:
|
||||
build:
|
||||
context: ../../
|
||||
dockerfile: make/dev/jobservice/Dockerfile
|
||||
container_name: harbor-jobservice
|
||||
env_file:
|
||||
- ../common/config/jobservice/env
|
||||
restart: always
|
||||
volumes:
|
||||
- /data/job_logs:/var/log/jobs
|
||||
- ../common/config/jobservice/app.conf:/etc/jobservice/app.conf
|
||||
- /data/job_logs:/var/log/jobs:z
|
||||
- ./common/config/jobservice/app.conf:/etc/jobservice/app.conf:z
|
||||
- /data/secretkey:/etc/jobservice/key:z
|
||||
networks:
|
||||
- harbor
|
||||
depends_on:
|
||||
- ui
|
||||
- adminserver
|
||||
logging:
|
||||
driver: "syslog"
|
||||
options:
|
||||
options:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "jobservice"
|
||||
proxy:
|
||||
image: library/nginx:1.11.5
|
||||
image: vmware/nginx:1.11.5-patched
|
||||
container_name: nginx
|
||||
restart: always
|
||||
volumes:
|
||||
- ../common/config/nginx:/etc/nginx
|
||||
- ./common/config/nginx:/etc/nginx:z
|
||||
networks:
|
||||
- harbor
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
- 4443:4443
|
||||
depends_on:
|
||||
- mysql
|
||||
- registry
|
||||
@ -89,6 +135,9 @@ services:
|
||||
- log
|
||||
logging:
|
||||
driver: "syslog"
|
||||
options:
|
||||
options:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "proxy"
|
||||
networks:
|
||||
harbor:
|
||||
external: false
|
||||
|
@ -1,11 +1,7 @@
|
||||
FROM golang:1.6.2
|
||||
FROM golang:1.7.3
|
||||
|
||||
MAINTAINER jiangd@vmware.com
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y libldap2-dev \
|
||||
&& rm -r /var/lib/apt/lists/*
|
||||
|
||||
COPY . /go/src/github.com/vmware/harbor
|
||||
|
||||
WORKDIR /go/src/github.com/vmware/harbor/src/jobservice
|
||||
|
18
make/dev/nodeclarity/Dockerfile
Normal file
@ -0,0 +1,18 @@
|
||||
FROM node:7.5.0
|
||||
|
||||
RUN mkdir -p /clarity-seed
|
||||
|
||||
COPY src/ui_ng/package.json /clarity-seed
|
||||
COPY src/ui_ng/tslint.json /clarity-seed
|
||||
COPY src/ui_ng/typings.json /clarity-seed
|
||||
COPY src/ui_ng/yarn.lock /clarity-seed
|
||||
COPY make/dev/nodeclarity/angular-cli.json /clarity-seed
|
||||
COPY make/dev/nodeclarity/entrypoint.sh /
|
||||
|
||||
WORKDIR /clarity-seed
|
||||
|
||||
RUN npm install -g @angular/cli && \
|
||||
npm install && \
|
||||
chmod u+x /entrypoint.sh
|
||||
|
||||
VOLUME ["/clarity-seed", "/clarity-seed/dist"]
|
67
make/dev/nodeclarity/angular-cli.json
Normal file
@ -0,0 +1,67 @@
|
||||
{
|
||||
"project": {
|
||||
"version": "1.0.0-beta.20-4",
|
||||
"name": "clarity-seed"
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"root": "src",
|
||||
"outDir": "dist",
|
||||
"assets": [
|
||||
"images",
|
||||
"favicon.ico"
|
||||
],
|
||||
"index": "index.html",
|
||||
"main": "main.ts",
|
||||
"test": "test.ts",
|
||||
"tsconfig": "tsconfig.json",
|
||||
"prefix": "app",
|
||||
"mobile": false,
|
||||
"styles": [
|
||||
"../node_modules/clarity-icons/clarity-icons.min.css",
|
||||
"../node_modules/clarity-ui/clarity-ui.min.css",
|
||||
"styles.css"
|
||||
],
|
||||
"scripts": [
|
||||
"../node_modules/core-js/client/shim.min.js",
|
||||
"../node_modules/mutationobserver-shim/dist/mutationobserver.min.js",
|
||||
"../node_modules/@webcomponents/custom-elements/custom-elements.min.js",
|
||||
"../node_modules/clarity-icons/clarity-icons.min.js",
|
||||
"../node_modules/web-animations-js/web-animations.min.js"
|
||||
],
|
||||
"environmentSource": "environments/environment.ts",
|
||||
"environments": {
|
||||
"dev": "environments/environment.ts",
|
||||
"prod": "environments/environment.prod.ts"
|
||||
}
|
||||
}
|
||||
],
|
||||
"addons": [],
|
||||
"packages": [],
|
||||
"e2e": {
|
||||
"protractor": {
|
||||
"config": "./protractor.config.js"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"karma": {
|
||||
"config": "./karma.conf.js"
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"styleExt": "scss",
|
||||
"prefixInterfaces": false,
|
||||
"inline": {
|
||||
"style": false,
|
||||
"template": false
|
||||
},
|
||||
"spec": {
|
||||
"class": false,
|
||||
"component": true,
|
||||
"directive": true,
|
||||
"module": false,
|
||||
"pipe": true,
|
||||
"service": true
|
||||
}
|
||||
}
|
||||
}
|
25
make/dev/nodeclarity/entrypoint.sh
Normal file
@ -0,0 +1,25 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
cd /clarity-seed
|
||||
rm -rf dist/*
|
||||
|
||||
npm_proxy=
|
||||
|
||||
while getopts p: option
|
||||
do
|
||||
case "${option}"
|
||||
in
|
||||
p) npm_proxy=${OPTARG};;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ ! -z "$npm_proxy" -a "$npm_proxy" != " " ]; then
|
||||
npm config set proxy $npm_proxy
|
||||
fi
|
||||
|
||||
npm install
|
||||
ng build
|
||||
|
||||
cp -r ./src/i18n/ dist/
|
||||
|
13
make/dev/nodeclarity/index.html
Normal file
@ -0,0 +1,13 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Clarity Seed App</title>
|
||||
<base href="/ng">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico?v=2">
|
||||
</head>
|
||||
<body>
|
||||
<harbor-app>Loading...</harbor-app>
|
||||
<script type="text/javascript" src="/ng/inline.bundle.js"></script><script type="text/javascript" src="/ng/scripts.bundle.js"></script><script type="text/javascript" src="/ng/styles.bundle.js"></script><script type="text/javascript" src="/ng/vendor.bundle.js"></script><script type="text/javascript" src="/ng/main.bundle.js"></script></body>
|
||||
</html>
|
@ -1,31 +1,20 @@
|
||||
FROM golang:1.6.2
|
||||
FROM golang:1.7.3
|
||||
|
||||
MAINTAINER jiangd@vmware.com
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y libldap2-dev \
|
||||
&& rm -r /var/lib/apt/lists/*
|
||||
|
||||
COPY src/. /go/src/github.com/vmware/harbor/src
|
||||
WORKDIR /go/src/github.com/vmware/harbor/src/ui
|
||||
|
||||
RUN go build -v -a -o /go/bin/harbor_ui
|
||||
|
||||
ENV MYSQL_USR root \
|
||||
MYSQL_PWD root \
|
||||
REGISTRY_URL localhost:5000
|
||||
|
||||
COPY src/ui/views /go/bin/views
|
||||
COPY src/ui/static /go/bin/static
|
||||
COPY src/favicon.ico /go/bin/favicon.ico
|
||||
COPY make/jsminify.sh /tmp/jsminify.sh
|
||||
|
||||
RUN chmod u+x /go/bin/harbor_ui \
|
||||
&& sed -i 's/TLS_CACERT/#TLS_CAERT/g' /etc/ldap/ldap.conf \
|
||||
&& sed -i '$a\TLS_REQCERT allow' /etc/ldap/ldap.conf \
|
||||
&& timestamp=`date '+%s'` \
|
||||
&& /tmp/jsminify.sh /go/bin/views/sections/script-include.htm /go/bin/static/resources/js/harbor.app.min.$timestamp.js /go/bin/ \
|
||||
&& sed -i "s/harbor\.app\.min\.js/harbor\.app\.min\.$timestamp\.js/g" /go/bin/views/sections/script-min-include.htm
|
||||
RUN mkdir /go/bin/harbor/
|
||||
COPY VERSION /go/bin/harbor/VERSION
|
||||
|
||||
RUN chmod u+x /go/bin/harbor_ui
|
||||
|
||||
WORKDIR /go/bin/
|
||||
ENTRYPOINT ["/go/bin/harbor_ui"]
|
||||
|
76
make/docker-compose.notary.yml
Normal file
@ -0,0 +1,76 @@
|
||||
version: '2'
|
||||
services:
|
||||
ui:
|
||||
networks:
|
||||
- harbor-notary
|
||||
proxy:
|
||||
networks:
|
||||
- harbor-notary
|
||||
notary-server:
|
||||
image: vmware/notary-photon:server-0.5.0
|
||||
container_name: notary-server
|
||||
networks:
|
||||
- notary-mdb
|
||||
- notary-sig
|
||||
- harbor-notary
|
||||
volumes:
|
||||
- ./common/config/notary:/config
|
||||
entrypoint: /usr/bin/env sh
|
||||
command: -c "/migrations/migrate.sh && notary-server -config=/config/server-config.json -logf=logfmt"
|
||||
depends_on:
|
||||
- notary-db
|
||||
- notary-signer
|
||||
logging:
|
||||
driver: "syslog"
|
||||
options:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "notary-server"
|
||||
notary-signer:
|
||||
image: vmware/notary-photon:signer-0.5.0
|
||||
container_name: notary-signer
|
||||
networks:
|
||||
notary-mdb:
|
||||
notary-sig:
|
||||
aliases:
|
||||
- notarysigner
|
||||
volumes:
|
||||
- ./common/config/notary:/config
|
||||
env_file:
|
||||
- ./common/config/notary/signer_env
|
||||
entrypoint: /usr/bin/env sh
|
||||
command: -c "/migrations/migrate.sh && notary-signer -config=/config/signer-config.json -logf=logfmt"
|
||||
depends_on:
|
||||
- notary-db
|
||||
logging:
|
||||
driver: "syslog"
|
||||
options:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "notary-signer"
|
||||
notary-db:
|
||||
image: vmware/harbor-notary-db:mariadb-10.1.10
|
||||
container_name: notary-db
|
||||
networks:
|
||||
notary-mdb:
|
||||
aliases:
|
||||
- mysql
|
||||
volumes:
|
||||
- ./common/config/notary/mysql-initdb.d:/docker-entrypoint-initdb.d
|
||||
- /data/notary-db:/var/lib/mysql
|
||||
environment:
|
||||
- TERM=dumb
|
||||
- MYSQL_ALLOW_EMPTY_PASSWORD="true"
|
||||
command: mysqld --innodb_file_per_table
|
||||
depends_on:
|
||||
- log
|
||||
logging:
|
||||
driver: "syslog"
|
||||
options:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "notary-db"
|
||||
networks:
|
||||
harbor-notary:
|
||||
external: false
|
||||
notary-mdb:
|
||||
external: false
|
||||
notary-sig:
|
||||
external: false
|
@ -1,20 +1,24 @@
|
||||
version: '2'
|
||||
services:
|
||||
log:
|
||||
image: vmware/harbor-log
|
||||
image: vmware/harbor-log:__version__
|
||||
container_name: harbor-log
|
||||
restart: always
|
||||
volumes:
|
||||
- /var/log/harbor/:/var/log/docker/
|
||||
- /var/log/harbor/:/var/log/docker/:z
|
||||
ports:
|
||||
- 1514:514
|
||||
- 127.0.0.1:1514:514
|
||||
networks:
|
||||
- harbor
|
||||
registry:
|
||||
image: library/registry:2.5.0
|
||||
image: vmware/registry:photon-2.6.0
|
||||
container_name: registry
|
||||
restart: always
|
||||
volumes:
|
||||
- /data/registry:/storage
|
||||
- ./common/config/registry/:/etc/registry/
|
||||
- /data/registry:/storage:z
|
||||
- ./common/config/registry/:/etc/registry/:z
|
||||
networks:
|
||||
- harbor
|
||||
environment:
|
||||
- GODEBUG=netdns=cgo
|
||||
command:
|
||||
@ -27,11 +31,13 @@ services:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "registry"
|
||||
mysql:
|
||||
image: vmware/harbor-db
|
||||
image: vmware/harbor-db:__version__
|
||||
container_name: harbor-db
|
||||
restart: always
|
||||
volumes:
|
||||
- /data/database:/var/lib/mysql
|
||||
- /data/database:/var/lib/mysql:z
|
||||
networks:
|
||||
- harbor
|
||||
env_file:
|
||||
- ./common/config/db/env
|
||||
depends_on:
|
||||
@ -41,48 +47,79 @@ services:
|
||||
options:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "mysql"
|
||||
ui:
|
||||
image: vmware/harbor-ui
|
||||
container_name: harbor-ui
|
||||
adminserver:
|
||||
image: vmware/harbor-adminserver:__version__
|
||||
container_name: harbor-adminserver
|
||||
env_file:
|
||||
- ./common/config/ui/env
|
||||
- ./common/config/adminserver/env
|
||||
restart: always
|
||||
volumes:
|
||||
- ./common/config/ui/app.conf:/etc/ui/app.conf
|
||||
- ./common/config/ui/private_key.pem:/etc/ui/private_key.pem
|
||||
- /data:/harbor_storage
|
||||
- /data/config/:/etc/adminserver/config/:z
|
||||
- /data/secretkey:/etc/adminserver/key:z
|
||||
- /data/:/data/:z
|
||||
networks:
|
||||
- harbor
|
||||
depends_on:
|
||||
- log
|
||||
logging:
|
||||
driver: "syslog"
|
||||
options:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "adminserver"
|
||||
ui:
|
||||
image: vmware/harbor-ui:__version__
|
||||
container_name: harbor-ui
|
||||
env_file:
|
||||
- ./common/config/ui/env
|
||||
restart: always
|
||||
volumes:
|
||||
- ./common/config/ui/app.conf:/etc/ui/app.conf:z
|
||||
- ./common/config/ui/private_key.pem:/etc/ui/private_key.pem:z
|
||||
- /data/secretkey:/etc/ui/key:z
|
||||
- /data/ca_download/:/etc/ui/ca/:z
|
||||
networks:
|
||||
- harbor
|
||||
depends_on:
|
||||
- log
|
||||
- adminserver
|
||||
- registry
|
||||
logging:
|
||||
driver: "syslog"
|
||||
options:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "ui"
|
||||
jobservice:
|
||||
image: vmware/harbor-jobservice
|
||||
image: vmware/harbor-jobservice:__version__
|
||||
container_name: harbor-jobservice
|
||||
env_file:
|
||||
- ./common/config/jobservice/env
|
||||
restart: always
|
||||
volumes:
|
||||
- /data/job_logs:/var/log/jobs
|
||||
- ./common/config/jobservice/app.conf:/etc/jobservice/app.conf
|
||||
- /data/job_logs:/var/log/jobs:z
|
||||
- ./common/config/jobservice/app.conf:/etc/jobservice/app.conf:z
|
||||
- /data/secretkey:/etc/jobservice/key:z
|
||||
networks:
|
||||
- harbor
|
||||
depends_on:
|
||||
- ui
|
||||
- adminserver
|
||||
logging:
|
||||
driver: "syslog"
|
||||
options:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "jobservice"
|
||||
proxy:
|
||||
image: nginx:1.11.5
|
||||
image: vmware/nginx:1.11.5-patched
|
||||
container_name: nginx
|
||||
restart: always
|
||||
volumes:
|
||||
- ./common/config/nginx:/etc/nginx
|
||||
- ./common/config/nginx:/etc/nginx:z
|
||||
networks:
|
||||
- harbor
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
- 4443:4443
|
||||
depends_on:
|
||||
- mysql
|
||||
- registry
|
||||
@ -93,3 +130,7 @@ services:
|
||||
options:
|
||||
syslog-address: "tcp://127.0.0.1:1514"
|
||||
tag: "proxy"
|
||||
networks:
|
||||
harbor:
|
||||
external: false
|
||||
|
||||
|
@ -8,6 +8,34 @@ hostname = reg.mydomain.com
|
||||
#It can be set to https if ssl is enabled on nginx.
|
||||
ui_url_protocol = http
|
||||
|
||||
#The password for the root user of mysql db, change this before any production use.
|
||||
db_password = root123
|
||||
|
||||
#Maximum number of job workers in job service
|
||||
max_job_workers = 3
|
||||
|
||||
#Determine whether or not to generate certificate for the registry's token.
|
||||
#If the value is on, the prepare script creates new root cert and private key
|
||||
#for generating token to access the registry. If the value is off the default key/cert will be used.
|
||||
#This flag also controls the creation of the notary signer's cert.
|
||||
customize_crt = on
|
||||
|
||||
#The path of cert and key files for nginx, they are applied only the protocol is set to https
|
||||
ssl_cert = /data/cert/server.crt
|
||||
ssl_cert_key = /data/cert/server.key
|
||||
|
||||
#The path of secretkey storage
|
||||
secretkey_path = /data
|
||||
|
||||
#Admiral's url, comment this attribute, or set its value to NA when Harbor is standalone
|
||||
admiral_url = NA
|
||||
|
||||
#NOTES: The properties between BEGIN INITIAL PROPERTIES and END INITIAL PROPERTIES
|
||||
#only take effect in the first boot, the subsequent changes of these properties
|
||||
#should be performed on web ui
|
||||
|
||||
#************************BEGIN INITIAL PROPERTIES************************
|
||||
|
||||
#Email account settings for sending out password resetting emails.
|
||||
|
||||
#Email server uses the given username and password to authenticate on TLS connections to host and act as identity.
|
||||
@ -52,46 +80,23 @@ ldap_uid = uid
|
||||
#the scope to search for users, 1-LDAP_SCOPE_BASE, 2-LDAP_SCOPE_ONELEVEL, 3-LDAP_SCOPE_SUBTREE
|
||||
ldap_scope = 3
|
||||
|
||||
#The password for the root user of mysql db, change this before any production use.
|
||||
db_password = root123
|
||||
#Timeout (in seconds) when connecting to an LDAP Server. The default value (and most reasonable) is 5 seconds.
|
||||
ldap_timeout = 5
|
||||
|
||||
#Turn on or off the self-registration feature
|
||||
self_registration = on
|
||||
|
||||
#Determine whether the UI should use compressed js files.
|
||||
#For production, set it to on. For development, set it to off.
|
||||
use_compressed_js = on
|
||||
|
||||
#Maximum number of job workers in job service
|
||||
max_job_workers = 3
|
||||
|
||||
#The expiration time (in minute) of token created by token service, default is 30 minutes
|
||||
token_expiration = 30
|
||||
|
||||
#The flag to control what users have permission to create projects
|
||||
#The default value "everyone" allows everyone to creates a project.
|
||||
#Set to "adminonly" so that only admin user can create project.
|
||||
project_creation_restriction = everyone
|
||||
|
||||
#Determine whether the job service should verify the ssl cert when it connects to a remote registry.
|
||||
#Set this flag to off when the remote registry uses a self-signed or untrusted certificate.
|
||||
verify_remote_cert = on
|
||||
|
||||
#Determine whether or not to generate certificate for the registry's token.
|
||||
#If the value is on, the prepare script creates new root cert and private key
|
||||
#for generating token to access the registry. If the value is off, a key/certificate must
|
||||
#be supplied for token generation.
|
||||
customize_crt = on
|
||||
|
||||
#Information of your organization for certificate
|
||||
crt_country = CN
|
||||
crt_state = State
|
||||
crt_location = CN
|
||||
crt_organization = organization
|
||||
crt_organizationalunit = organizational unit
|
||||
crt_commonname = example.com
|
||||
crt_email = example@example.com
|
||||
|
||||
#The flag to control what users have permission to create projects
|
||||
#Be default everyone can create a project, set to "adminonly" such that only admin can create project.
|
||||
project_creation_restriction = everyone
|
||||
|
||||
#The path of cert and key files for nginx, they are applied only the protocol is set to https
|
||||
ssl_cert = /data/cert/server.crt
|
||||
ssl_cert_key = /data/cert/server.key
|
||||
#************************END INITIAL PROPERTIES************************
|
||||
#############
|
||||
|
||||
|
@ -49,14 +49,20 @@ note() { printf "\n${underline}${bold}${blue}Note:${reset} ${blue}%s${reset}\n"
|
||||
set -e
|
||||
set +o noglob
|
||||
|
||||
usage=$'Please set hostname and other necessary attributes in harbor.cfg first. DO NOT use localhost or 127.0.0.1 for hostname, because Harbor needs to be accessed by external clients.'
|
||||
usage=$'Please set hostname and other necessary attributes in harbor.cfg first. DO NOT use localhost or 127.0.0.1 for hostname, because Harbor needs to be accessed by external clients.
|
||||
Please set --with-notary if needs enable Notary in Harbor, and set ui_url_protocol/ssl_cert/ssl_cert_key in harbor.cfg bacause notary must run under https.'
|
||||
item=0
|
||||
|
||||
# notary is not enabled by default
|
||||
with_notary=$false
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case $1 in
|
||||
--help)
|
||||
note "$usage"
|
||||
exit 0;;
|
||||
--with-notary)
|
||||
with_notary=true;;
|
||||
*)
|
||||
note "$usage"
|
||||
exit 1;;
|
||||
@ -134,10 +140,10 @@ h2 "[Step $item]: checking installation environment ..."; let item+=1
|
||||
check_docker
|
||||
check_dockercompose
|
||||
|
||||
if [ -f harbor*.tgz ]
|
||||
if [ -f harbor*.tar.gz ]
|
||||
then
|
||||
h2 "[Step $item]: loading Harbor images ..."; let item+=1
|
||||
docker load -i ./harbor*.tgz
|
||||
docker load -i ./harbor*.tar.gz
|
||||
fi
|
||||
echo ""
|
||||
|
||||
@ -146,19 +152,38 @@ if [ -n "$host" ]
|
||||
then
|
||||
sed "s/^hostname = .*/hostname = $host/g" -i ./harbor.cfg
|
||||
fi
|
||||
./prepare
|
||||
if [ $with_notary ]
|
||||
then
|
||||
./prepare --with-notary
|
||||
else
|
||||
./prepare
|
||||
fi
|
||||
echo ""
|
||||
|
||||
h2 "[Step $item]: checking existing instance of Harbor ..."; let item+=1
|
||||
if [ -n "$(docker-compose -f docker-compose*.yml ps -q)" ]
|
||||
then
|
||||
note "stopping existing Harbor instance ..."
|
||||
docker-compose -f docker-compose*.yml down
|
||||
if [ $with_notary ]
|
||||
then
|
||||
if [ -n "$(docker-compose -f docker-compose.yml -f docker-compose.notary.yml ps -q)" ]
|
||||
then
|
||||
note "stopping existing Harbor instance ..."
|
||||
docker-compose -f docker-compose.yml -f docker-compose.notary.yml down -v
|
||||
fi
|
||||
else
|
||||
if [ -n "$(docker-compose -f docker-compose.yml ps -q)" ]
|
||||
then
|
||||
note "stopping existing Harbor instance ..."
|
||||
docker-compose -f docker-compose.yml down -v
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
|
||||
h2 "[Step $item]: starting Harbor ..."
|
||||
docker-compose -f docker-compose*.yml up -d
|
||||
if [ $with_notary ]
|
||||
then
|
||||
docker-compose -f docker-compose.yml -f docker-compose.notary.yml up -d
|
||||
else
|
||||
docker-compose -f docker-compose.yml up -d
|
||||
fi
|
||||
|
||||
protocol=http
|
||||
hostname=reg.mydomain.com
|
||||
|
@ -1,71 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
echo "This shell will minify the Javascript in Harbor project."
|
||||
echo "Usage: #jsminify [src] [dest] [basedir]"
|
||||
|
||||
#prepare workspace
|
||||
rm -rf $2 /tmp/harbor.app.temp.js
|
||||
|
||||
if [ -z $3 ]
|
||||
then
|
||||
BASEPATH=/go/bin
|
||||
else
|
||||
BASEPATH=$3
|
||||
fi
|
||||
|
||||
#concat the js files from js include file
|
||||
echo "Concat js files..."
|
||||
|
||||
cat $1 | while read LINE || [[ -n $LINE ]]
|
||||
do
|
||||
if [ -n "$LINE" ]
|
||||
then
|
||||
TEMP="$BASEPATH""$LINE"
|
||||
cat `echo "$TEMP" | sed 's/<script src=\"//g' | sed 's/\"><\/script>//g'` >> /tmp/harbor.app.temp.js
|
||||
printf "\n" >> /tmp/harbor.app.temp.js
|
||||
fi
|
||||
done
|
||||
|
||||
# If you want run this script on Mac OS X,
|
||||
# I suggest you install gnu-sed (whth --with-default-names option).
|
||||
# $ brew install gnu-sed --with-default-names
|
||||
# Reference:
|
||||
# http://stackoverflow.com/a/27834828/3167471
|
||||
|
||||
#remove space
|
||||
echo "Remove space.."
|
||||
sed 's/ \+/ /g' -i /tmp/harbor.app.temp.js
|
||||
|
||||
#remove '//' and '/*'
|
||||
echo "Remove '//'and '/*' annotation..."
|
||||
sed '/^\/\//'d -i /tmp/harbor.app.temp.js
|
||||
sed '/\/\*/{/\*\//d;:a;N;/\*\//d;ba};s,//.*,,' -i /tmp/harbor.app.temp.js
|
||||
|
||||
cat > $2 << EOF
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
EOF
|
||||
|
||||
#remove '\n'
|
||||
echo "Remove CR ..."
|
||||
cat /tmp/harbor.app.temp.js | tr -d '\n' >> $2
|
||||
|
||||
#clear workspace
|
||||
rm -rf /tmp/harbor.app.temp.js
|
||||
|
||||
echo "Done."
|
||||
exit 0
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
# Targets:
|
||||
#
|
||||
# build: build harbor photon images
|
||||
# clean: clean ui and jobservice harbor images
|
||||
# clean: clean adminserver, ui and jobservice harbor images
|
||||
|
||||
# common
|
||||
SHELL := /bin/bash
|
||||
@ -22,6 +22,9 @@ DOCKERRMIMAGE=$(DOCKERCMD) rmi
|
||||
DOCKERIMASES=$(DOCKERCMD) images
|
||||
|
||||
# binary
|
||||
ADMINSERVERSOURCECODE=$(SRCPATH)/adminserver
|
||||
ADMINSERVERBINARYPATH=$(MAKEDEVPATH)/adminserver
|
||||
ADMINSERVERBINARYNAME=harbor_adminserver
|
||||
UISOURCECODE=$(SRCPATH)/ui
|
||||
UIBINARYPATH=$(MAKEDEVPATH)/ui
|
||||
UIBINARYNAME=harbor_ui
|
||||
@ -31,6 +34,9 @@ JOBSERVICEBINARYNAME=harbor_jobservice
|
||||
|
||||
# photon dockerfile
|
||||
DOCKERFILEPATH=$(MAKEPATH)/photon
|
||||
DOCKERFILEPATH_ADMINSERVER=$(DOCKERFILEPATH)/adminserver
|
||||
DOCKERFILENAME_ADMINSERVER=Dockerfile
|
||||
DOCKERIMAGENAME_ADMINSERVER=vmware/harbor-adminserver
|
||||
DOCKERFILEPATH_UI=$(DOCKERFILEPATH)/ui
|
||||
DOCKERFILENAME_UI=Dockerfile
|
||||
DOCKERIMAGENAME_UI=vmware/harbor-ui
|
||||
@ -56,6 +62,10 @@ check_environment:
|
||||
@$(MAKEPATH)/$(CHECKENVCMD)
|
||||
|
||||
build:
|
||||
@echo "building adminserver container for photon..."
|
||||
$(DOCKERBUILD) -f $(DOCKERFILEPATH_ADMINSERVER)/$(DOCKERFILENAME_ADMINSERVER) -t $(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG) .
|
||||
@echo "Done."
|
||||
|
||||
@echo "building ui container for photon..."
|
||||
$(DOCKERBUILD) -f $(DOCKERFILEPATH_UI)/$(DOCKERFILENAME_UI) -t $(DOCKERIMAGENAME_UI):$(VERSIONTAG) .
|
||||
@echo "Done."
|
||||
@ -70,6 +80,7 @@ build:
|
||||
|
||||
cleanimage:
|
||||
@echo "cleaning image for photon..."
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG)
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_UI):$(VERSIONTAG)
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG)
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_LOG):$(VERSIONTAG)
|
||||
|
8
make/photon/adminserver/Dockerfile
Normal file
@ -0,0 +1,8 @@
|
||||
FROM library/photon:1.0
|
||||
|
||||
RUN mkdir /harbor/
|
||||
COPY ./make/dev/adminserver/harbor_adminserver /harbor/
|
||||
|
||||
RUN chmod u+x /harbor/harbor_adminserver
|
||||
WORKDIR /harbor/
|
||||
ENTRYPOINT ["/harbor/harbor_adminserver"]
|
@ -1,20 +1,15 @@
|
||||
FROM library/photon:1.0
|
||||
|
||||
RUN mkdir /harbor/
|
||||
RUN tdnf install -y sed apr-util-ldap
|
||||
|
||||
COPY ./make/dev/ui/harbor_ui /harbor/
|
||||
|
||||
COPY ./src/ui/views /harbor/views
|
||||
COPY ./src/ui/static /harbor/static
|
||||
COPY ./src/favicon.ico /harbor/favicon.ico
|
||||
COPY ./make/jsminify.sh /tmp/jsminify.sh
|
||||
COPY ./VERSION /harbor/VERSION
|
||||
|
||||
RUN chmod u+x /harbor/harbor_ui \
|
||||
&& timestamp=`date '+%s'` \
|
||||
&& /tmp/jsminify.sh /harbor/views/sections/script-include.htm /harbor/static/resources/js/harbor.app.min.$timestamp.js /harbor/ \
|
||||
&& sed -i "s/harbor\.app\.min\.js/harbor\.app\.min\.$timestamp\.js/g" /harbor/views/sections/script-min-include.htm \
|
||||
&& echo "TLS_REQCERT allow" >> /etc/openldap/ldap.conf
|
||||
RUN chmod u+x /harbor/harbor_ui
|
||||
|
||||
WORKDIR /harbor/
|
||||
ENTRYPOINT ["/harbor/harbor_ui"]
|
||||
|
318
make/prepare
@ -19,8 +19,10 @@ if sys.version_info[:3][0] == 3:
|
||||
import configparser as ConfigParser
|
||||
import io as StringIO
|
||||
|
||||
def validate(conf):
|
||||
def validate(conf, args):
|
||||
protocol = rcp.get("configuration", "ui_url_protocol")
|
||||
if protocol != "https" and args.notary_mode:
|
||||
raise Exception("Error: the protocol must be https when Harbor is deployed with Notary")
|
||||
if protocol == "https":
|
||||
if not rcp.has_option("configuration", "ssl_cert"):
|
||||
raise Exception("Error: The protocol is https but attribute ssl_cert is not set")
|
||||
@ -38,32 +40,64 @@ def validate(conf):
|
||||
raise Exception("Error invalid value for project_creation_restriction: %s" % project_creation)
|
||||
|
||||
def get_secret_key(path):
|
||||
key_file = os.path.join(path, "secretkey")
|
||||
secret_key = _get_secret(path, "secretkey")
|
||||
if len(secret_key) != 16:
|
||||
raise Exception("secret key's length has to be 16 chars, current length: %d" % len(secret_key))
|
||||
return secret_key
|
||||
|
||||
def get_alias(path):
|
||||
alias = _get_secret(path, "defaultalias", length=8)
|
||||
return alias
|
||||
|
||||
def _get_secret(folder, filename, length=16):
|
||||
key_file = os.path.join(folder, filename)
|
||||
if os.path.isfile(key_file):
|
||||
with open(key_file, 'r') as f:
|
||||
key = f.read()
|
||||
print("loaded secret key")
|
||||
if len(key) != 16:
|
||||
raise Exception("secret key's length has to be 16 chars, current length: %d" % len(key))
|
||||
print("loaded secret from file: %s" % key_file)
|
||||
return key
|
||||
if not os.path.isdir(path):
|
||||
os.makedirs(path, mode=0600)
|
||||
key = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(16))
|
||||
if not os.path.isdir(folder):
|
||||
os.makedirs(folder, mode=0600)
|
||||
key = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(length))
|
||||
with open(key_file, 'w') as f:
|
||||
f.write(key)
|
||||
print("generated and saved secret key")
|
||||
print("Generated and saved secret to file: %s" % key_file)
|
||||
os.chmod(key_file, 0600)
|
||||
return key
|
||||
|
||||
def prep_conf_dir(root, name):
|
||||
absolute_path = os.path.join(root, name)
|
||||
if not os.path.exists(absolute_path):
|
||||
os.makedirs(absolute_path)
|
||||
return absolute_path
|
||||
|
||||
def render(src, dest, **kw):
|
||||
t = Template(open(src, 'r').read())
|
||||
with open(dest, 'w') as f:
|
||||
f.write(t.substitute(**kw))
|
||||
print("Generated configuration file: %s" % dest)
|
||||
|
||||
base_dir = os.path.dirname(__file__)
|
||||
config_dir = os.path.join(base_dir, "common/config")
|
||||
templates_dir = os.path.join(base_dir, "common/templates")
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-conf', dest='cfgfile', default=base_dir+'/harbor.cfg',type=str,help="the path of Harbor configuration file")
|
||||
parser.add_argument('--data-volume', dest='data_volume', default='/data/',type=str,help="the path of Harbor data volume, which is set in template of docker-compose.")
|
||||
def delfile(src):
|
||||
if os.path.isfile(src):
|
||||
try:
|
||||
os.remove(src)
|
||||
print("Clearing the configuration file: %s" % src)
|
||||
except:
|
||||
pass
|
||||
elif os.path.isdir(src):
|
||||
for item in os.listdir(src):
|
||||
itemsrc=os.path.join(src,item)
|
||||
delfile(itemsrc)
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('--conf', dest='cfgfile', default=base_dir+'/harbor.cfg',type=str,help="the path of Harbor configuration file")
|
||||
parser.add_argument('--with-notary', dest='notary_mode', default=False, action='store_true', help="the Harbor instance is to be deployed with notary")
|
||||
args = parser.parse_args()
|
||||
|
||||
delfile(config_dir)
|
||||
#Read configurations
|
||||
conf = StringIO.StringIO()
|
||||
conf.write("[configuration]\n")
|
||||
@ -72,16 +106,16 @@ conf.seek(0, os.SEEK_SET)
|
||||
rcp = ConfigParser.RawConfigParser()
|
||||
rcp.readfp(conf)
|
||||
|
||||
validate(rcp)
|
||||
validate(rcp, args)
|
||||
|
||||
hostname = rcp.get("configuration", "hostname")
|
||||
protocol = rcp.get("configuration", "ui_url_protocol")
|
||||
ui_url = protocol + "://" + hostname
|
||||
email_identity = rcp.get("configuration", "email_identity")
|
||||
email_server = rcp.get("configuration", "email_server")
|
||||
email_server_port = rcp.get("configuration", "email_server_port")
|
||||
email_username = rcp.get("configuration", "email_username")
|
||||
email_password = rcp.get("configuration", "email_password")
|
||||
email_host = rcp.get("configuration", "email_server")
|
||||
email_port = rcp.get("configuration", "email_server_port")
|
||||
email_usr = rcp.get("configuration", "email_username")
|
||||
email_pwd = rcp.get("configuration", "email_password")
|
||||
email_from = rcp.get("configuration", "email_from")
|
||||
email_ssl = rcp.get("configuration", "email_ssl")
|
||||
harbor_admin_password = rcp.get("configuration", "harbor_admin_password")
|
||||
@ -102,56 +136,40 @@ else:
|
||||
ldap_filter = ""
|
||||
ldap_uid = rcp.get("configuration", "ldap_uid")
|
||||
ldap_scope = rcp.get("configuration", "ldap_scope")
|
||||
ldap_timeout = rcp.get("configuration", "ldap_timeout")
|
||||
db_password = rcp.get("configuration", "db_password")
|
||||
self_registration = rcp.get("configuration", "self_registration")
|
||||
use_compressed_js = rcp.get("configuration", "use_compressed_js")
|
||||
if protocol == "https":
|
||||
cert_path = rcp.get("configuration", "ssl_cert")
|
||||
cert_key_path = rcp.get("configuration", "ssl_cert_key")
|
||||
customize_crt = rcp.get("configuration", "customize_crt")
|
||||
crt_country = rcp.get("configuration", "crt_country")
|
||||
crt_state = rcp.get("configuration", "crt_state")
|
||||
crt_location = rcp.get("configuration", "crt_location")
|
||||
crt_organization = rcp.get("configuration", "crt_organization")
|
||||
crt_organizationalunit = rcp.get("configuration", "crt_organizationalunit")
|
||||
crt_commonname = rcp.get("configuration", "crt_commonname")
|
||||
crt_email = rcp.get("configuration", "crt_email")
|
||||
max_job_workers = rcp.get("configuration", "max_job_workers")
|
||||
token_expiration = rcp.get("configuration", "token_expiration")
|
||||
verify_remote_cert = rcp.get("configuration", "verify_remote_cert")
|
||||
proj_cre_restriction = rcp.get("configuration", "project_creation_restriction")
|
||||
#secret_key = rcp.get("configuration", "secret_key")
|
||||
secret_key = get_secret_key(args.data_volume)
|
||||
secretkey_path = rcp.get("configuration", "secretkey_path")
|
||||
if rcp.has_option("configuration", "admiral_url"):
|
||||
admiral_url = rcp.get("configuration", "admiral_url")
|
||||
else:
|
||||
admiral_url = ""
|
||||
secret_key = get_secret_key(secretkey_path)
|
||||
########
|
||||
|
||||
ui_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))
|
||||
|
||||
ui_config_dir = os.path.join(config_dir,"ui")
|
||||
if not os.path.exists(ui_config_dir):
|
||||
os.makedirs(os.path.join(config_dir, "ui"))
|
||||
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"))
|
||||
|
||||
db_config_dir = os.path.join(config_dir, "db")
|
||||
if not os.path.exists(db_config_dir):
|
||||
os.makedirs(os.path.join(config_dir, "db"))
|
||||
|
||||
job_config_dir = os.path.join(config_dir, "jobservice")
|
||||
if not os.path.exists(job_config_dir):
|
||||
os.makedirs(job_config_dir)
|
||||
|
||||
registry_config_dir = os.path.join(config_dir, "registry")
|
||||
if not os.path.exists(registry_config_dir):
|
||||
os.makedirs(registry_config_dir)
|
||||
|
||||
nginx_config_dir = os.path.join(config_dir, "nginx")
|
||||
if not os.path.exists(nginx_config_dir):
|
||||
os.makedirs(nginx_config_dir)
|
||||
|
||||
def render(src, dest, **kw):
|
||||
t = Template(open(src, 'r').read())
|
||||
with open(dest, 'w') as f:
|
||||
f.write(t.substitute(**kw))
|
||||
print("Generated configuration file: %s" % dest)
|
||||
ui_config_dir = prep_conf_dir(config_dir,"ui")
|
||||
db_config_dir = prep_conf_dir(config_dir, "db")
|
||||
job_config_dir = prep_conf_dir(config_dir, "jobservice")
|
||||
registry_config_dir = prep_conf_dir(config_dir, "registry")
|
||||
nginx_config_dir = prep_conf_dir (config_dir, "nginx")
|
||||
nginx_conf_d = prep_conf_dir(nginx_config_dir, "conf.d")
|
||||
|
||||
adminserver_conf_env = os.path.join(config_dir, "adminserver", "env")
|
||||
ui_conf_env = os.path.join(config_dir, "ui", "env")
|
||||
ui_conf = os.path.join(config_dir, "ui", "app.conf")
|
||||
jobservice_conf = os.path.join(config_dir, "jobservice", "app.conf")
|
||||
@ -160,18 +178,6 @@ 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")
|
||||
def delfile(src):
|
||||
if os.path.isfile(src):
|
||||
try:
|
||||
os.remove(src)
|
||||
print("Clearing the configuration file: %s" % src)
|
||||
except:
|
||||
pass
|
||||
elif os.path.isdir(src):
|
||||
for item in os.listdir(src):
|
||||
itemsrc=os.path.join(src,item)
|
||||
delfile(itemsrc)
|
||||
delfile(config_dir)
|
||||
|
||||
if protocol == "https":
|
||||
target_cert_path = os.path.join(cert_dir, os.path.basename(cert_path))
|
||||
@ -187,14 +193,12 @@ if protocol == "https":
|
||||
else:
|
||||
render(os.path.join(templates_dir, "nginx", "nginx.http.conf"),
|
||||
nginx_conf)
|
||||
|
||||
render(os.path.join(templates_dir, "ui", "env"),
|
||||
ui_conf_env,
|
||||
hostname=hostname,
|
||||
db_password=db_password,
|
||||
|
||||
render(os.path.join(templates_dir, "adminserver", "env"),
|
||||
adminserver_conf_env,
|
||||
ui_url=ui_url,
|
||||
auth_mode=auth_mode,
|
||||
harbor_admin_password=harbor_admin_password,
|
||||
self_registration=self_registration,
|
||||
ldap_url=ldap_url,
|
||||
ldap_searchdn =ldap_searchdn,
|
||||
ldap_search_pwd =ldap_search_pwd,
|
||||
@ -202,26 +206,33 @@ render(os.path.join(templates_dir, "ui", "env"),
|
||||
ldap_filter=ldap_filter,
|
||||
ldap_uid=ldap_uid,
|
||||
ldap_scope=ldap_scope,
|
||||
self_registration=self_registration,
|
||||
use_compressed_js=use_compressed_js,
|
||||
ui_secret=ui_secret,
|
||||
secret_key=secret_key,
|
||||
verify_remote_cert=verify_remote_cert,
|
||||
project_creation_restriction=proj_cre_restriction,
|
||||
token_expiration=token_expiration)
|
||||
|
||||
render(os.path.join(templates_dir, "ui", "app.conf"),
|
||||
ui_conf,
|
||||
email_identity=email_identity,
|
||||
email_server=email_server,
|
||||
email_server_port=email_server_port,
|
||||
email_username=email_username,
|
||||
email_password=email_password,
|
||||
email_from=email_from,
|
||||
ldap_timeout=ldap_timeout,
|
||||
db_password=db_password,
|
||||
email_host=email_host,
|
||||
email_port=email_port,
|
||||
email_usr=email_usr,
|
||||
email_pwd=email_pwd,
|
||||
email_ssl=email_ssl,
|
||||
ui_url=ui_url)
|
||||
email_from=email_from,
|
||||
email_identity=email_identity,
|
||||
harbor_admin_password=harbor_admin_password,
|
||||
project_creation_restriction=proj_cre_restriction,
|
||||
verify_remote_cert=verify_remote_cert,
|
||||
max_job_workers=max_job_workers,
|
||||
ui_secret=ui_secret,
|
||||
jobservice_secret=jobservice_secret,
|
||||
token_expiration=token_expiration,
|
||||
admiral_url=admiral_url,
|
||||
with_notary=args.notary_mode
|
||||
)
|
||||
|
||||
render(os.path.join(templates_dir, "registry", "config.yml"),
|
||||
render(os.path.join(templates_dir, "ui", "env"),
|
||||
ui_conf_env,
|
||||
ui_secret=ui_secret,
|
||||
jobservice_secret=jobservice_secret,)
|
||||
|
||||
render(os.path.join(templates_dir, "registry",
|
||||
"config.yml"),
|
||||
registry_conf,
|
||||
ui_url=ui_url)
|
||||
|
||||
@ -231,16 +242,16 @@ render(os.path.join(templates_dir, "db", "env"),
|
||||
|
||||
render(os.path.join(templates_dir, "jobservice", "env"),
|
||||
job_conf_env,
|
||||
db_password=db_password,
|
||||
ui_secret=ui_secret,
|
||||
max_job_workers=max_job_workers,
|
||||
secret_key=secret_key,
|
||||
ui_url=ui_url,
|
||||
verify_remote_cert=verify_remote_cert)
|
||||
|
||||
jobservice_secret=jobservice_secret)
|
||||
|
||||
print("Generated configuration file: %s" % jobservice_conf)
|
||||
shutil.copyfile(os.path.join(templates_dir, "jobservice", "app.conf"), jobservice_conf)
|
||||
|
||||
print("Generated configuration file: %s" % ui_conf)
|
||||
shutil.copyfile(os.path.join(templates_dir, "ui", "app.conf"), ui_conf)
|
||||
|
||||
|
||||
def validate_crt_subj(dirty_subj):
|
||||
subj_list = [item for item in dirty_subj.strip().split("/") \
|
||||
if len(item.split("=")) == 2 and len(item.split("=")[1]) > 0]
|
||||
@ -251,51 +262,112 @@ FNULL = open(os.devnull, 'w')
|
||||
from functools import wraps
|
||||
def stat_decorator(func):
|
||||
@wraps(func)
|
||||
def check_wrapper(*args, **kwargs):
|
||||
stat = func(*args, **kwargs)
|
||||
message = "Generated configuration file: %s" % kwargs['path'] \
|
||||
if stat == 0 else "Fail to generate %s" % kwargs['path']
|
||||
def check_wrapper(*args, **kw):
|
||||
stat = func(*args, **kw)
|
||||
message = "Generated certificate, key file: %s, cert file: %s" % (kw['key_path'], kw['cert_path']) \
|
||||
if stat == 0 else "Fail to generate key file: %s, cert file: %s" % (kw['key_path'], kw['cert_path'])
|
||||
print(message)
|
||||
if stat != 0:
|
||||
sys.exit(1)
|
||||
return check_wrapper
|
||||
|
||||
@stat_decorator
|
||||
def check_private_key_stat(*args, **kwargs):
|
||||
return subprocess.call(["openssl", "genrsa", "-out", kwargs['path'], "4096"],\
|
||||
stdout=FNULL, stderr=subprocess.STDOUT)
|
||||
def create_root_cert(subj, key_path="./k.key", cert_path="./cert.crt"):
|
||||
rc = subprocess.call(["openssl", "genrsa", "-out", key_path, "4096"], stdout=FNULL, stderr=subprocess.STDOUT)
|
||||
if rc != 0:
|
||||
return rc
|
||||
return subprocess.call(["openssl", "req", "-new", "-x509", "-key", key_path,\
|
||||
"-out", cert_path, "-days", "3650", "-subj", subj], stdout=FNULL, stderr=subprocess.STDOUT)
|
||||
|
||||
@stat_decorator
|
||||
def check_certificate_stat(*args, **kwargs):
|
||||
dirty_subj = "/C={0}/ST={1}/L={2}/O={3}/OU={4}/CN={5}/emailAddress={6}"\
|
||||
.format(crt_country, crt_state, crt_location, crt_organization,\
|
||||
crt_organizationalunit, crt_commonname, crt_email)
|
||||
subj = validate_crt_subj(dirty_subj)
|
||||
return subprocess.call(["openssl", "req", "-new", "-x509", "-key",\
|
||||
private_key_pem, "-out", root_crt, "-days", "3650", "-subj", subj], \
|
||||
stdout=FNULL, stderr=subprocess.STDOUT)
|
||||
def create_cert(subj, ca_key, ca_cert, key_path="./k.key", cert_path="./cert.crt"):
|
||||
cert_dir = os.path.dirname(cert_path)
|
||||
csr_path = os.path.join(cert_dir, "tmp.csr")
|
||||
rc = subprocess.call(["openssl", "req", "-newkey", "rsa:4096", "-nodes","-sha256","-keyout", key_path,\
|
||||
"-out", csr_path, "-subj", subj], stdout=FNULL, stderr=subprocess.STDOUT)
|
||||
if rc != 0:
|
||||
return rc
|
||||
return subprocess.call(["openssl", "x509", "-req", "-days", "3650", "-in", csr_path, "-CA", \
|
||||
ca_cert, "-CAkey", ca_key, "-CAcreateserial", "-out", cert_path], stdout=FNULL, stderr=subprocess.STDOUT)
|
||||
|
||||
def openssl_is_installed(stat):
|
||||
if stat == 0:
|
||||
return True
|
||||
else:
|
||||
def openssl_installed():
|
||||
shell_stat = subprocess.check_call(["which", "openssl"], stdout=FNULL, stderr=subprocess.STDOUT)
|
||||
if shell_stat != 0:
|
||||
print("Cannot find openssl installed in this computer\nUse default SSL certificate file")
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
if customize_crt == 'on':
|
||||
if customize_crt == 'on' and openssl_installed():
|
||||
shell_stat = subprocess.check_call(["which", "openssl"], stdout=FNULL, stderr=subprocess.STDOUT)
|
||||
if openssl_is_installed(shell_stat):
|
||||
private_key_pem = os.path.join(config_dir, "ui", "private_key.pem")
|
||||
root_crt = os.path.join(config_dir, "registry", "root.crt")
|
||||
|
||||
check_private_key_stat(path=private_key_pem)
|
||||
check_certificate_stat(path=root_crt)
|
||||
|
||||
empty_subj = "/C=/ST=/L=/O=/CN=/"
|
||||
private_key_pem = os.path.join(config_dir, "ui", "private_key.pem")
|
||||
root_crt = os.path.join(config_dir, "registry", "root.crt")
|
||||
create_root_cert(empty_subj, key_path=private_key_pem, cert_path=root_crt)
|
||||
os.chmod(private_key_pem, 0600)
|
||||
os.chmod(root_crt, 0600)
|
||||
else:
|
||||
print("Generated configuration file: %s" % ui_config_dir + "private_key.pem")
|
||||
print("Copied configuration file: %s" % ui_config_dir + "private_key.pem")
|
||||
shutil.copyfile(os.path.join(templates_dir, "ui", "private_key.pem"), os.path.join(ui_config_dir, "private_key.pem"))
|
||||
print("Generated configuration file: %s" % registry_config_dir + "root.crt")
|
||||
print("Copied configuration file: %s" % registry_config_dir + "root.crt")
|
||||
shutil.copyfile(os.path.join(templates_dir, "registry", "root.crt"), os.path.join(registry_config_dir, "root.crt"))
|
||||
|
||||
if args.notary_mode:
|
||||
notary_config_dir = prep_conf_dir(config_dir, "notary")
|
||||
notary_temp_dir = os.path.join(templates_dir, "notary")
|
||||
print("Copying sql file for notary DB")
|
||||
if os.path.exists(os.path.join(notary_config_dir, "mysql-initdb.d")):
|
||||
shutil.rmtree(os.path.join(notary_config_dir, "mysql-initdb.d"))
|
||||
shutil.copytree(os.path.join(notary_temp_dir, "mysql-initdb.d"), os.path.join(notary_config_dir, "mysql-initdb.d"))
|
||||
if customize_crt == 'on' and openssl_installed():
|
||||
try:
|
||||
temp_cert_dir = os.path.join(base_dir, "cert_tmp")
|
||||
if not os.path.exists(temp_cert_dir):
|
||||
os.makedirs(temp_cert_dir)
|
||||
ca_subj = "/C=US/ST=California/L=Palo Alto/O=VMware, Inc./OU=Harbor/CN=Self-signed by VMware, Inc."
|
||||
cert_subj = "/C=US/ST=California/L=Palo Alto/O=VMware, Inc./OU=Harbor/CN=notarysigner"
|
||||
signer_ca_cert = os.path.join(temp_cert_dir, "notary-signer-ca.crt")
|
||||
signer_ca_key = os.path.join(temp_cert_dir, "notary-signer-ca.key")
|
||||
signer_cert_path = os.path.join(temp_cert_dir, "notary-signer.crt")
|
||||
signer_key_path = os.path.join(temp_cert_dir, "notary-signer.key")
|
||||
create_root_cert(ca_subj, key_path=signer_ca_key, cert_path=signer_ca_cert)
|
||||
create_cert(cert_subj, signer_ca_key, signer_ca_cert, key_path=signer_key_path, cert_path=signer_cert_path)
|
||||
print("Copying certs for notary signer")
|
||||
os.chmod(signer_cert_path, 0600)
|
||||
os.chmod(signer_key_path, 0600)
|
||||
os.chmod(signer_ca_cert, 0600)
|
||||
shutil.copy2(signer_cert_path, notary_config_dir)
|
||||
shutil.copy2(signer_key_path, notary_config_dir)
|
||||
shutil.copy2(signer_ca_cert, notary_config_dir)
|
||||
finally:
|
||||
srl_tmp = os.path.join(os.getcwd(), ".srl")
|
||||
if os.path.isfile(srl_tmp):
|
||||
os.remove(srl_tmp)
|
||||
if os.path.isdir(temp_cert_dir):
|
||||
shutil.rmtree(temp_cert_dir, True)
|
||||
else:
|
||||
print("Copying certs for notary signer")
|
||||
shutil.copy2(os.path.join(notary_temp_dir, "notary-signer.crt"), notary_config_dir)
|
||||
shutil.copy2(os.path.join(notary_temp_dir, "notary-signer.key"), notary_config_dir)
|
||||
shutil.copy2(os.path.join(notary_temp_dir, "notary-signer-ca.crt"), notary_config_dir)
|
||||
shutil.copy2(os.path.join(registry_config_dir, "root.crt"), notary_config_dir)
|
||||
print("Copying notary signer configuration file")
|
||||
shutil.copy2(os.path.join(notary_temp_dir, "signer-config.json"), notary_config_dir)
|
||||
render(os.path.join(notary_temp_dir, "server-config.json"),
|
||||
os.path.join(notary_config_dir, "server-config.json"),
|
||||
token_endpoint=ui_url)
|
||||
|
||||
print("Copying nginx configuration file for notary")
|
||||
shutil.copy2(os.path.join(templates_dir, "nginx", "notary.upstream.conf"), nginx_conf_d)
|
||||
render(os.path.join(templates_dir, "nginx", "notary.server.conf"),
|
||||
os.path.join(nginx_conf_d, "notary.server.conf"),
|
||||
ssl_cert = os.path.join("/etc/nginx/cert", os.path.basename(target_cert_path)),
|
||||
ssl_cert_key = os.path.join("/etc/nginx/cert", os.path.basename(target_cert_key_path)))
|
||||
|
||||
|
||||
default_alias = get_alias(secretkey_path)
|
||||
render(os.path.join(notary_temp_dir, "signer_env"), os.path.join(notary_config_dir, "signer_env"), alias = default_alias)
|
||||
|
||||
FNULL.close()
|
||||
print("The configuration files are ready, please use docker-compose to start the service.")
|
||||
|
||||
|
@ -1,79 +0,0 @@
|
||||
# Makefile for a harbor project
|
||||
#
|
||||
# Targets:
|
||||
#
|
||||
# build: build harbor ubuntu images
|
||||
# clean: clean ui and jobservice harbor images
|
||||
|
||||
# common
|
||||
SHELL := /bin/bash
|
||||
BUILDPATH=$(CURDIR)
|
||||
MAKEPATH=$(BUILDPATH)/make
|
||||
MAKEDEVPATH=$(MAKEPATH)/dev
|
||||
SRCPATH=./src
|
||||
TOOLSPATH=$(BUILDPATH)/tools
|
||||
CHECKENVCMD=checkenv.sh
|
||||
DEVFLAG=true
|
||||
|
||||
# docker parameters
|
||||
DOCKERCMD=$(shell which docker)
|
||||
DOCKERBUILD=$(DOCKERCMD) build
|
||||
DOCKERRMIMAGE=$(DOCKERCMD) rmi
|
||||
DOCKERIMASES=$(DOCKERCMD) images
|
||||
|
||||
# binary
|
||||
UISOURCECODE=$(SRCPATH)/ui
|
||||
UIBINARYPATH=$(MAKEDEVPATH)/ui
|
||||
UIBINARYNAME=harbor_ui
|
||||
JOBSERVICESOURCECODE=$(SRCPATH)/jobservice
|
||||
JOBSERVICEBINARYPATH=$(MAKEDEVPATH)/jobservice
|
||||
JOBSERVICEBINARYNAME=harbor_jobservice
|
||||
|
||||
# ubuntu dockerfile
|
||||
DOCKERFILEPATH=$(MAKEPATH)/ubuntu
|
||||
DOCKERFILEPATH_UI=$(DOCKERFILEPATH)/ui
|
||||
DOCKERFILENAME_UI=Dockerfile
|
||||
DOCKERIMAGENAME_UI=vmware/harbor-ui
|
||||
DOCKERFILEPATH_JOBSERVICE=$(DOCKERFILEPATH)/jobservice
|
||||
DOCKERFILENAME_JOBSERVICE=Dockerfile
|
||||
DOCKERIMAGENAME_JOBSERVICE=vmware/harbor-jobservice
|
||||
DOCKERFILEPATH_LOG=$(DOCKERFILEPATH)/log
|
||||
DOCKERFILENAME_LOG=Dockerfile
|
||||
DOCKERIMAGENAME_LOG=vmware/harbor-log
|
||||
|
||||
# version prepare
|
||||
VERSIONFILEPATH=$(SRCPATH)/views/sections
|
||||
VERSIONFILENAME=header-content.htm
|
||||
GITCMD=$(shell which git)
|
||||
GITTAG=$(GITCMD) describe --tags
|
||||
ifeq ($(DEVFLAG), true)
|
||||
VERSIONTAG=dev
|
||||
else
|
||||
VERSIONTAG=$(shell $(GITTAG))
|
||||
endif
|
||||
|
||||
check_environment:
|
||||
@$(MAKEPATH)/$(CHECKENVCMD)
|
||||
|
||||
build:
|
||||
@echo "building ui container for ubuntu..."
|
||||
$(DOCKERBUILD) -f $(DOCKERFILEPATH_UI)/$(DOCKERFILENAME_UI) -t $(DOCKERIMAGENAME_UI):$(VERSIONTAG) .
|
||||
@echo "Done."
|
||||
|
||||
@echo "building jobservice container for ubuntu..."
|
||||
$(DOCKERBUILD) -f $(DOCKERFILEPATH_JOBSERVICE)/$(DOCKERFILENAME_JOBSERVICE) -t $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) .
|
||||
@echo "Done."
|
||||
|
||||
@echo "building log container for ubuntu..."
|
||||
$(DOCKERBUILD) -f $(DOCKERFILEPATH_LOG)/$(DOCKERFILENAME_LOG) -t $(DOCKERIMAGENAME_LOG):$(VERSIONTAG) .
|
||||
@echo "Done."
|
||||
|
||||
cleanimage:
|
||||
@echo "cleaning image for ubuntu..."
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_UI):$(VERSIONTAG)
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG)
|
||||
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_LOG):$(VERSIONTAG)
|
||||
|
||||
.PHONY: clean
|
||||
clean: cleanimage
|
||||
|
@ -1,14 +0,0 @@
|
||||
FROM golang:1.6.2
|
||||
|
||||
MAINTAINER jiangd@vmware.com
|
||||
|
||||
RUN apt-get update && apt-get install -y libldap2-dev \
|
||||
&& rm -r /var/lib/apt/lists/*
|
||||
|
||||
RUN mkdir /harbor/
|
||||
COPY ./make/dev/jobservice/harbor_jobservice /harbor/
|
||||
|
||||
RUN chmod u+x /harbor/harbor_jobservice
|
||||
|
||||
WORKDIR /harbor/
|
||||
ENTRYPOINT ["/harbor/harbor_jobservice"]
|
@ -1,18 +0,0 @@
|
||||
FROM library/ubuntu:14.04
|
||||
|
||||
RUN rm /etc/rsyslog.d/* && rm /etc/rsyslog.conf
|
||||
|
||||
ADD make/common/log/rsyslog.conf /etc/rsyslog.conf
|
||||
|
||||
# rotate logs weekly
|
||||
# notes: file name cannot contain dot, or the script will not run
|
||||
ADD make/common/log/rotate.sh /etc/cron.weekly/rotate
|
||||
|
||||
# rsyslog configuration file for docker
|
||||
ADD make/common/log/rsyslog_docker.conf /etc/rsyslog.d/
|
||||
|
||||
VOLUME /var/log/docker/
|
||||
|
||||
EXPOSE 514
|
||||
|
||||
CMD cron && rsyslogd -n
|
@ -1,31 +0,0 @@
|
||||
FROM golang:1.6.2
|
||||
|
||||
MAINTAINER jiangd@vmware.com
|
||||
|
||||
RUN apt-get update && apt-get install -y libldap2-dev \
|
||||
&& rm -r /var/lib/apt/lists/*
|
||||
|
||||
ENV MYSQL_USR root \
|
||||
MYSQL_PWD root \
|
||||
REGISTRY_URL localhost:5000
|
||||
|
||||
RUN mkdir /harbor/
|
||||
COPY ./make/dev/ui/harbor_ui /harbor/
|
||||
|
||||
COPY ./src/ui/views /harbor/views
|
||||
COPY ./src/ui/static /harbor/static
|
||||
COPY ./src/favicon.ico /harbor/favicon.ico
|
||||
COPY ./make/jsminify.sh /tmp/jsminify.sh
|
||||
|
||||
RUN chmod u+x /harbor/harbor_ui \
|
||||
&& sed -i 's/TLS_CACERT/#TLS_CAERT/g' /etc/ldap/ldap.conf \
|
||||
&& sed -i '$a\TLS_REQCERT allow' /etc/ldap/ldap.conf \
|
||||
&& timestamp=`date '+%s'` \
|
||||
&& /tmp/jsminify.sh /harbor/views/sections/script-include.htm /harbor/static/resources/js/harbor.app.min.$timestamp.js /harbor/ \
|
||||
&& sed -i "s/harbor\.app\.min\.js/harbor\.app\.min\.$timestamp\.js/g" /harbor/views/sections/script-min-include.htm
|
||||
|
||||
WORKDIR /harbor/
|
||||
ENTRYPOINT ["/harbor/harbor_ui"]
|
||||
|
||||
EXPOSE 80
|
||||
|
48
src/adminserver/api/base.go
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"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
|
||||
}
|
31
src/adminserver/api/base_test.go
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestHandleInternalServerError(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
handleInternalServerError(w)
|
||||
|
||||
if w.Code != http.StatusInternalServerError {
|
||||
t.Errorf("unexpected status code: %d != %d", w.Code, http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
}
|
77
src/adminserver/api/cfg.go
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
"github.com/vmware/harbor/src/adminserver/systemcfg"
|
||||
"github.com/vmware/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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
168
src/adminserver/api/cfg_test.go
Normal file
@ -0,0 +1,168 @@
|
||||
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/vmware/harbor/src/adminserver/systemcfg"
|
||||
"github.com/vmware/harbor/src/common"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
37
src/adminserver/api/systeminfo.go
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/vmware/harbor/src/adminserver/systeminfo/imagestorage"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
)
|
||||
|
||||
// Capacity handles /api/systeminfo/capacity and returns system capacity
|
||||
func Capacity(w http.ResponseWriter, r *http.Request) {
|
||||
capacity, err := imagestorage.GlobalDriver.Cap()
|
||||
if err != nil {
|
||||
log.Errorf("failed to get capacity: %v", err)
|
||||
handleInternalServerError(w)
|
||||
return
|
||||
}
|
||||
|
||||
if err = writeJSON(w, capacity); err != nil {
|
||||
log.Errorf("failed to write response: %v", err)
|
||||
return
|
||||
}
|
||||
}
|
73
src/adminserver/api/systeminfo_test.go
Normal file
@ -0,0 +1,73 @@
|
||||
// Copyright (c) 2017 VMware, Inc. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/vmware/harbor/src/adminserver/systeminfo/imagestorage"
|
||||
)
|
||||
|
||||
type fakeImageStorageDriver struct {
|
||||
capacity *imagestorage.Capacity
|
||||
err error
|
||||
}
|
||||
|
||||
func (f *fakeImageStorageDriver) Name() string {
|
||||
return "fake"
|
||||
}
|
||||
|
||||
func (f *fakeImageStorageDriver) Cap() (*imagestorage.Capacity, error) {
|
||||
return f.capacity, f.err
|
||||
}
|
||||
|
||||
func TestCapacity(t *testing.T) {
|
||||
cases := []struct {
|
||||
driver imagestorage.Driver
|
||||
responseCode int
|
||||
capacity *imagestorage.Capacity
|
||||
}{
|
||||
{&fakeImageStorageDriver{nil, errors.New("error")}, http.StatusInternalServerError, nil},
|
||||
{&fakeImageStorageDriver{&imagestorage.Capacity{100, 90}, nil}, http.StatusOK, &imagestorage.Capacity{100, 90}},
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("", "", nil)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create request: %v", err)
|
||||
}
|
||||
for _, c := range cases {
|
||||
imagestorage.GlobalDriver = c.driver
|
||||
w := httptest.NewRecorder()
|
||||
Capacity(w, req)
|
||||
assert.Equal(t, c.responseCode, w.Code, "unexpected response code")
|
||||
if c.responseCode == http.StatusOK {
|
||||
b, err := ioutil.ReadAll(w.Body)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read from response body: %v", err)
|
||||
}
|
||||
capacity := &imagestorage.Capacity{}
|
||||
if err = json.Unmarshal(b, capacity); err != nil {
|
||||
t.Fatalf("failed to unmarshal: %v", err)
|
||||
}
|
||||
assert.Equal(t, c.capacity, capacity)
|
||||
}
|
||||
}
|
||||
}
|
64
src/adminserver/auth/auth.go
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright (c) 2017 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"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
secret, err := req.Cookie("secret")
|
||||
if err != nil {
|
||||
if err == http.ErrNoCookie {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
if secret == nil {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for _, v := range s.secrets {
|
||||
if secret.Value == v {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
56
src/adminserver/auth/auth_test.go
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright (c) 2017 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 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)
|
||||
}
|
||||
req2.AddCookie(&http.Cookie{
|
||||
Name: "secret",
|
||||
Value: 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")
|
||||
}
|
||||
}
|
50
src/adminserver/client/auth/auth.go
Normal file
@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2017 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
|
||||
}
|
43
src/adminserver/client/auth/auth_test.go
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright (c) 2017 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")
|
||||
}
|
183
src/adminserver/client/client.go
Normal file
@ -0,0 +1,183 @@
|
||||
// Copyright (c) 2017 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
|
||||
}
|
81
src/adminserver/client/client_test.go
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2017 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)
|
||||
}
|
77
src/adminserver/handlers/handler.go
Normal file
@ -0,0 +1,77 @@
|
||||
// Copyright (c) 2017 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 handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
gorilla_handlers "github.com/gorilla/handlers"
|
||||
"github.com/vmware/harbor/src/adminserver/auth"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
)
|
||||
|
||||
// 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("UI_SECRET"),
|
||||
"jobserviceSecret": os.Getenv("JOBSERVICE_SECRET"),
|
||||
}
|
||||
h = newAuthHandler(auth.NewSecretAuthenticator(secrets), h)
|
||||
h = gorilla_handlers.LoggingHandler(os.Stdout, h)
|
||||
return h
|
||||
}
|
||||
|
||||
type authHandler struct {
|
||||
authenticator auth.Authenticator
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
func newAuthHandler(authenticator auth.Authenticator, handler http.Handler) http.Handler {
|
||||
return &authHandler{
|
||||
authenticator: authenticator,
|
||||
handler: handler,
|
||||
}
|
||||
}
|
||||
|
||||
func (a *authHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
if a.authenticator == nil {
|
||||
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
|
||||
}
|
72
src/adminserver/handlers/handlers_test.go
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright (c) 2017 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 handlers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/vmware/harbor/src/adminserver/auth"
|
||||
)
|
||||
|
||||
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
|
||||
responseCode int
|
||||
}{
|
||||
|
||||
{nil, nil, http.StatusOK},
|
||||
{&fakeAuthenticator{
|
||||
authenticated: false,
|
||||
err: nil,
|
||||
}, nil, http.StatusUnauthorized},
|
||||
{&fakeAuthenticator{
|
||||
authenticated: false,
|
||||
err: errors.New("error"),
|
||||
}, nil, http.StatusInternalServerError},
|
||||
{&fakeAuthenticator{
|
||||
authenticated: true,
|
||||
err: nil,
|
||||
}, &fakeHandler{http.StatusNotFound}, http.StatusNotFound},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
handler := newAuthHandler(c.authenticator, c.handler)
|
||||
w := httptest.NewRecorder()
|
||||
handler.ServeHTTP(w, nil)
|
||||
assert.Equal(t, c.responseCode, w.Code, "unexpected response code")
|
||||
}
|
||||
}
|
31
src/adminserver/handlers/router.go
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2017 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 handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/vmware/harbor/src/adminserver/api"
|
||||
)
|
||||
|
||||
func newRouter() http.Handler {
|
||||
r := mux.NewRouter()
|
||||
r.HandleFunc("/api/configurations", api.ListCfgs).Methods("GET")
|
||||
r.HandleFunc("/api/configurations", api.UpdateCfgs).Methods("PUT")
|
||||
r.HandleFunc("/api/configurations/reset", api.ResetCfgs).Methods("POST")
|
||||
r.HandleFunc("/api/systeminfo/capacity", api.Capacity).Methods("GET")
|
||||
return r
|
||||
}
|
63
src/adminserver/main.go
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright (c) 2017 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 main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/vmware/harbor/src/adminserver/handlers"
|
||||
syscfg "github.com/vmware/harbor/src/adminserver/systemcfg"
|
||||
sysinfo "github.com/vmware/harbor/src/adminserver/systeminfo"
|
||||
"github.com/vmware/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")
|
||||
|
||||
sysinfo.Init()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|