Merge pull request #1 from vmware/master

Updated from original project
This commit is contained in:
BhEaN 2017-04-21 21:30:36 +02:00 committed by GitHub
commit 632a30e3da
1131 changed files with 87591 additions and 22583 deletions

26
.gitignore vendored
View File

@ -1,8 +1,34 @@
harbor harbor
make/common/config/* make/common/config/*
make/dev/adminserver/harbor_adminserver
make/dev/ui/harbor_ui make/dev/ui/harbor_ui
make/dev/jobservice/harbor_jobservice make/dev/jobservice/harbor_jobservice
src/adminserver/adminserver
src/ui/ui src/ui/ui
src/jobservice/jobservice src/jobservice/jobservice
src/common/dao/dao.test
*.pyc *.pyc
jobservice/test 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

View File

@ -3,7 +3,7 @@ sudo: true
language: go language: go
go: go:
- 1.6.2 - 1.7.3
go_import_path: github.com/vmware/harbor go_import_path: github.com/vmware/harbor
@ -13,25 +13,25 @@ services:
dist: trusty dist: trusty
env: env:
DB_HOST: 127.0.0.1
DB_PORT: 3306
DB_USR: root
DB_PWD: root123
MYSQL_HOST: localhost MYSQL_HOST: localhost
MYSQL_PORT: 3306 MYSQL_PORT: 3306
MYSQL_USR: root MYSQL_USR: root
MYSQL_PWD: root123 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 DOCKER_COMPOSE_VERSION: 1.7.1
HARBOR_ADMIN: admin HARBOR_ADMIN: admin
HARBOR_ADMIN_PASSWD: Harbor12345 HARBOR_ADMIN_PASSWD: Harbor12345
UI_SECRET: tempString UI_SECRET: tempString
MAX_JOB_WORKERS: 3 MAX_JOB_WORKERS: 3
SECRET_KEY: 1234567890123456
AUTH_MODE: db_auth AUTH_MODE: db_auth
SELF_REGISTRATION: "on" SELF_REGISTRATION: on
KEY_PATH: /data/secretkey
before_install: before_install:
- sudo ./tests/hostcfg.sh - sudo ./tests/hostcfg.sh
- sudo ./tests/generateCerts.sh
- sudo ./make/prepare - sudo ./make/prepare
install: install:
@ -70,28 +70,40 @@ install:
before_script: before_script:
# create tables and load data # create tables and load data
# - mysql < ./make/db/registry.sql -uroot --verbose # - 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: 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 service mysql stop
- sudo ./tests/testprepare.sh - 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 fgt golint
- go list ./... | grep -v -E 'vendor|tests' | xargs -L1 go vet - go list ./... | grep -v -E 'vendor|tests' | xargs -L1 go vet
- export MYSQL_HOST=$IP - export MYSQL_HOST=$IP
- export REGISTRY_URL=$IP:5000 - export REGISTRY_URL=$IP:5000
- echo $REGISTRY_URL - echo $REGISTRY_URL
- ./tests/pushimage.sh - ./tests/pushimage.sh
- ./tests/coverage4gotest.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 - goveralls -coverprofile=profile.cov -service=travis-ci
- docker-compose -f make/docker-compose.test.yml down - docker-compose -f make/docker-compose.test.yml down
- sudo rm -rf /data/config/*
- docker-compose -f make/dev/docker-compose.yml up -d - 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 - docker ps
- go run tests/startuptest.go http://localhost/ - ./tests/notarytest.sh
- go run tests/userlogintest.go -name ${HARBOR_ADMIN} -passwd ${HARBOR_ADMIN_PASSWD} - ./tests/swaggerchecker.sh
- ./tests/startuptest.sh
- ./tests/userlogintest.sh ${HARBOR_ADMIN} ${HARBOR_ADMIN_PASSWD}
# - sudo ./tests/testprepare.sh # - sudo ./tests/testprepare.sh
# - go test -v ./tests/apitests # - go test -v ./tests/apitests

View File

@ -5,6 +5,7 @@ Alexey Erkak <eryigin at mail.ru>
Allen Heavey <xheavey at gmail.com> Allen Heavey <xheavey at gmail.com>
Amanda Zhang <amzhang at vmware.com> Amanda Zhang <amzhang at vmware.com>
Andre Cruz <andre at brpx.com> Andre Cruz <andre at brpx.com>
Aron Parsons <aron at knackworks.com>
Benniu Ji <benniuji at gmail.com> Benniu Ji <benniuji at gmail.com>
Bin Liu <liubin0329 at gmail.com> Bin Liu <liubin0329 at gmail.com>
Bobby Zhang <junzhang at vmware.com> Bobby Zhang <junzhang at vmware.com>
@ -12,6 +13,7 @@ Brian Christner <brian.christner at gmail.com>
Chaofeng Wu <chaofengw at vmware.com> Chaofeng Wu <chaofengw at vmware.com>
Daniel Jiang <jiangd at vmware.com> Daniel Jiang <jiangd at vmware.com>
Deshi Xiao <xiaods at gmail.com> Deshi Xiao <xiaods at gmail.com>
Feileng Cui <feilengcui008 at gmail.com>
Guangping Fu <krystism at gmail.com> Guangping Fu <krystism at gmail.com>
Haining Henry Zhang <henryzhang at vmware.com> Haining Henry Zhang <henryzhang at vmware.com>
Hao Xia <haox at vmware.com> Hao Xia <haox at vmware.com>
@ -19,6 +21,7 @@ Haoyuan <harryge00 at gmail.com>
Jack Liu <ljack at vmware.com> Jack Liu <ljack at vmware.com>
Jessy Zhang <jessyz at vmware.com> Jessy Zhang <jessyz at vmware.com>
Jianye Li <li.jianye at gmail.com> Jianye Li <li.jianye at gmail.com>
Kira <me at imkira.com>
Kun Wang <kunw at vmware.com> Kun Wang <kunw at vmware.com>
Mahesh Paolini-Subramanya <mahesh at dieswaytoofast.com> Mahesh Paolini-Subramanya <mahesh at dieswaytoofast.com>
Maxwell <710028463 at qq.com> Maxwell <710028463 at qq.com>
@ -29,6 +32,7 @@ Penghao Cen <scorpiocph at gmail.com>
Phillip Gomez <gomez.phillip at gmail.com> Phillip Gomez <gomez.phillip at gmail.com>
Robin Naundorf <r.naundorf at fh-muenster.de> Robin Naundorf <r.naundorf at fh-muenster.de>
Shan Zhu <zhus at vmware.com> Shan Zhu <zhus at vmware.com>
Steven Zou <szou at vmware.com>
Robin Yue <jmyue at hotmail.com> Robin Yue <jmyue at hotmail.com>
Tobe Chen <tobeg3oogle at gmail.com> Tobe Chen <tobeg3oogle at gmail.com>
Victoria Zheng <vzheng at vmware.com> Victoria Zheng <vzheng at vmware.com>

View File

@ -1,5 +1,33 @@
# Changelog # 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) ## v0.4.5 (2016-10-31)
- Virtual appliance of Harbor for vSphere. - Virtual appliance of Harbor for vSphere.

2392
LICENSE

File diff suppressed because it is too large Load Diff

820
Makefile
View File

@ -1,368 +1,452 @@
# Makefile for Harbor project # Makefile for Harbor project
# #
# Targets: # Targets:
# #
# all: prepare env, compile binarys, build images and install images # all: prepare env, compile binarys, build images and install images
# prepare: prepare env # prepare: prepare env
# compile: compile ui and jobservice code # compile: compile adminserver, ui and jobservice code
# compile_buildgolangimage: #
# compile local building golang image # compile_golangimage:
# forexample : make compile_buildgolangimage -e \ # compile from golang image
# GOBUILDIMAGE=harborgo:1.6.2 # for example: make compile_golangimage -e GOBUILDIMAGE= \
# compile_golangimage: # golang:1.7.3
# compile from golang image # compile_adminserver, compile_ui, compile_jobservice: compile specific binary
# for example: make compile_golangimage -e GOBUILDIMAGE= \ #
# harborgo:1.6.2 # build: build Harbor docker images (defuault: build_photon)
# compile_ui, compile_jobservice: compile specific binary # for example: make build -e BASEIMAGE=photon
# # build_photon: build Harbor docker images from photon baseimage
# build: build Harbor docker images (defuault: build_photon) #
# for example: make build -e BASEIMAGE=photon # install: include compile binarys, build images, prepare specific \
# build_photon: build Harbor docker images from photon bsaeimage # version composefile and startup Harbor instance
# build_ubuntu: build Harbor docker images from ubuntu baseimage #
# # start: startup Harbor instance
# install: include compile binarys, build images, prepare specific \ #
# version composefile and startup Harbor instance # down: shutdown Harbor instance
# #
# start: startup Harbor instance # package_online:
# # prepare online install package
# down: shutdown Harbor instance # for example: make package_online -e DEVFLAG=false\
# # REGISTRYSERVER=reg-bj.eng.vmware.com \
# package_online: # REGISTRYPROJECTNAME=harborrelease
# prepare online install package #
# for example: make package_online -e DEVFLAG=false\ # package_offline:
# REGISTRYSERVER=reg-bj.eng.vmware.com \ # prepare offline install package
# REGISTRYPROJECTNAME=harborrelease #
# # pushimage: push Harbor images to specific registry server
# package_offline: # for example: make pushimage -e DEVFLAG=false REGISTRYUSER=admin \
# prepare offline install package # REGISTRYPASSWORD=***** \
# # REGISTRYSERVER=reg-bj.eng.vmware.com/ \
# pushimage: push Harbor images to specific registry server # REGISTRYPROJECTNAME=harborrelease
# for example: make pushimage -e DEVFLAG=false REGISTRYUSER=admin \ # note**: need add "/" on end of REGISTRYSERVER. If not setting \
# REGISTRYPASSWORD=***** \ # this value will push images directly to dockerhub.
# REGISTRYSERVER=reg-bj.eng.vmware.com/ \ # make pushimage -e DEVFLAG=false REGISTRYUSER=vmware \
# REGISTRYPROJECTNAME=harborrelease # REGISTRYPASSWORD=***** \
# note**: need add "/" on end of REGISTRYSERVER. If not setting \ # REGISTRYPROJECTNAME=vmware
# this value will push images directly to dockerhub. #
# make pushimage -e DEVFLAG=false REGISTRYUSER=vmware \ # clean: remove binary, Harbor images, specific version docker-compose \
# REGISTRYPASSWORD=***** \ # file, specific version tag and online/offline install package
# REGISTRYPROJECTNAME=vmware # cleanbinary: remove adminserver, ui and jobservice binary
# # cleanimage: remove Harbor images
# clean: remove binary, Harbor images, specific version docker-compose \ # cleandockercomposefile:
# file, specific version tag and online/offline install package # remove specific version docker-compose
# cleanbinary: remove ui and jobservice binary # cleanversiontag:
# cleanimage: remove Harbor images # cleanpackageremove specific version tag
# cleandockercomposefile: # cleanpackage: remove online/offline install package
# remove specific version docker-compose #
# cleanversiontag: # other example:
# cleanpackageremove specific version tag # clean specific version binarys and images:
# cleanpackage: remove online/offline install package # make clean -e VERSIONTAG=[TAG]
# # note**: If commit new code to github, the git commit TAG will \
# other example: # change. Better use this commond clean previous images and \
# clean specific version binarys and images: # files with specific TAG.
# make clean -e VERSIONTAG=[TAG] # By default DEVFLAG=true, if you want to release new version of Harbor, \
# note**: If commit new code to github, the git commit TAG will \ # should setting the flag to false.
# change. Better use this commond clean previous images and \ # make XXXX -e DEVFLAG=false
# files with specific TAG.
# By default DEVFLAG=true, if you want to release new version of Harbor, \ SHELL := /bin/bash
# should setting the flag to false. BUILDPATH=$(CURDIR)
# make XXXX -e DEVFLAG=false MAKEPATH=$(BUILDPATH)/make
MAKEDEVPATH=$(MAKEPATH)/dev
SHELL := /bin/bash SRCPATH=./src
BUILDPATH=$(CURDIR) TOOLSPATH=$(BUILDPATH)/tools
MAKEPATH=$(BUILDPATH)/make UIPATH=$(BUILDPATH)/src/ui
MAKEDEVPATH=$(MAKEPATH)/dev UINGPATH=$(BUILDPATH)/src/ui_ng
SRCPATH=./src GOBASEPATH=/go/src/github.com/vmware
TOOLSPATH=$(BUILDPATH)/tools CHECKENVCMD=checkenv.sh
GOBASEPATH=/go/src/github.com/vmware BASEIMAGE=photon
CHECKENVCMD=checkenv.sh COMPILETAG=compile_normal
BASEIMAGE=photon REGISTRYSERVER=
COMPILETAG=compile_normal REGISTRYPROJECTNAME=vmware
REGISTRYSERVER= DEVFLAG=true
REGISTRYPROJECTNAME=vmware NOTARYFLAG=false
DEVFLAG=true REGISTRYVERSION=photon-2.6.0
NGINXVERSION=1.11.5-patched
# docker parameters PHOTONVERSION=1.0
DOCKERCMD=$(shell which docker) NOTARYVERSION=server-0.5.0
DOCKERBUILD=$(DOCKERCMD) build NOTARYSIGNERVERSION=signer-0.5.0
DOCKERRMIMAGE=$(DOCKERCMD) rmi MARIADBVERSION=mariadb-10.1.10
DOCKERPULL=$(DOCKERCMD) pull HTTPPROXY=
DOCKERIMASES=$(DOCKERCMD) images
DOCKERSAVE=$(DOCKERCMD) save #clarity parameters
DOCKERCOMPOSECMD=$(shell which docker-compose) CLARITYIMAGE=vmware/harbor-clarity-ui-builder[:tag]
DOCKERTAG=$(DOCKERCMD) tag CLARITYSEEDPATH=/clarity-seed
CLARITYBUILDSCRIPT=/entrypoint.sh
# go parameters
GOCMD=$(shell which go) # docker parameters
GOBUILD=$(GOCMD) build DOCKERCMD=$(shell which docker)
GOCLEAN=$(GOCMD) clean DOCKERBUILD=$(DOCKERCMD) build
GOINSTALL=$(GOCMD) install DOCKERRMIMAGE=$(DOCKERCMD) rmi
GOTEST=$(GOCMD) test DOCKERPULL=$(DOCKERCMD) pull
GODEP=$(GOTEST) -i DOCKERIMASES=$(DOCKERCMD) images
GOFMT=gofmt -w DOCKERSAVE=$(DOCKERCMD) save
GOBUILDIMAGE=reg.mydomain.com/library/harborgo[:tag] DOCKERCOMPOSECMD=$(shell which docker-compose)
GOBUILDPATH=$(GOBASEPATH)/harbor DOCKERTAG=$(DOCKERCMD) tag
GOIMAGEBUILDCMD=/usr/local/go/bin/go
GOIMAGEBUILD=$(GOIMAGEBUILDCMD) build # go parameters
GOBUILDPATH_UI=$(GOBUILDPATH)/src/ui GOCMD=$(shell which go)
GOBUILDPATH_JOBSERVICE=$(GOBUILDPATH)/src/jobservice GOBUILD=$(GOCMD) build
GOBUILDMAKEPATH=$(GOBUILDPATH)/make GOCLEAN=$(GOCMD) clean
GOBUILDMAKEPATH_UI=$(GOBUILDMAKEPATH)/dev/ui GOINSTALL=$(GOCMD) install
GOBUILDMAKEPATH_JOBSERVICE=$(GOBUILDMAKEPATH)/dev/jobservice GOTEST=$(GOCMD) test
GOLANGDOCKERFILENAME=Dockerfile.golang GODEP=$(GOTEST) -i
GOFMT=gofmt -w
# binary GOBUILDIMAGE=reg.mydomain.com/library/harborgo[:tag]
UISOURCECODE=$(SRCPATH)/ui GOBUILDPATH=$(GOBASEPATH)/harbor
UIBINARYPATH=$(MAKEDEVPATH)/ui GOIMAGEBUILDCMD=/usr/local/go/bin/go
UIBINARYNAME=harbor_ui GOIMAGEBUILD=$(GOIMAGEBUILDCMD) build
JOBSERVICESOURCECODE=$(SRCPATH)/jobservice GOBUILDPATH_ADMINSERVER=$(GOBUILDPATH)/src/adminserver
JOBSERVICEBINARYPATH=$(MAKEDEVPATH)/jobservice GOBUILDPATH_UI=$(GOBUILDPATH)/src/ui
JOBSERVICEBINARYNAME=harbor_jobservice GOBUILDPATH_JOBSERVICE=$(GOBUILDPATH)/src/jobservice
GOBUILDMAKEPATH=$(GOBUILDPATH)/make
# prepare parameters GOBUILDMAKEPATH_ADMINSERVER=$(GOBUILDMAKEPATH)/dev/adminserver
PREPAREPATH=$(TOOLSPATH) GOBUILDMAKEPATH_UI=$(GOBUILDMAKEPATH)/dev/ui
PREPARECMD=prepare GOBUILDMAKEPATH_JOBSERVICE=$(GOBUILDMAKEPATH)/dev/jobservice
GOLANGDOCKERFILENAME=Dockerfile.golang
# configfile
CONFIGPATH=$(MAKEPATH) # binary
CONFIGFILE=harbor.cfg ADMINSERVERSOURCECODE=$(SRCPATH)/adminserver
ADMINSERVERBINARYPATH=$(MAKEDEVPATH)/adminserver
# makefile ADMINSERVERBINARYNAME=harbor_adminserver
MAKEFILEPATH_PHOTON=$(MAKEPATH)/photon UISOURCECODE=$(SRCPATH)/ui
MAKEFILEPATH_UBUNTU=$(MAKEPATH)/ubuntu UIBINARYPATH=$(MAKEDEVPATH)/ui
UIBINARYNAME=harbor_ui
# common dockerfile JOBSERVICESOURCECODE=$(SRCPATH)/jobservice
DOCKERFILEPATH_COMMON=$(MAKEPATH)/common JOBSERVICEBINARYPATH=$(MAKEDEVPATH)/jobservice
DOCKERFILEPATH_DB=$(DOCKERFILEPATH_COMMON)/db JOBSERVICEBINARYNAME=harbor_jobservice
DOCKERFILENAME_DB=Dockerfile
# prepare parameters
# docker image name PREPAREPATH=$(TOOLSPATH)
DOCKERIMAGENAME_UI=vmware/harbor-ui PREPARECMD=prepare
DOCKERIMAGENAME_JOBSERVICE=vmware/harbor-jobservice
DOCKERIMAGENAME_LOG=vmware/harbor-log # configfile
DOCKERIMAGENAME_DB=vmware/harbor-db CONFIGPATH=$(MAKEPATH)
CONFIGFILE=harbor.cfg
# docker-compose files # makefile
DOCKERCOMPOSEFILEPATH=$(MAKEPATH) MAKEFILEPATH_PHOTON=$(MAKEPATH)/photon
DOCKERCOMPOSETPLFILENAME=docker-compose.tpl
DOCKERCOMPOSEFILENAME=docker-compose.yml # common dockerfile
DOCKERFILEPATH_COMMON=$(MAKEPATH)/common
# version prepare DOCKERFILEPATH_DB=$(DOCKERFILEPATH_COMMON)/db
VERSIONFILEPATH=$(SRCPATH)/ui/views/sections DOCKERFILENAME_DB=Dockerfile
VERSIONFILENAME=header-content.htm
GITCMD=$(shell which git) # docker image name
GITTAG=$(GITCMD) describe --tags DOCKERIMAGENAME_ADMINSERVER=vmware/harbor-adminserver
ifeq ($(DEVFLAG), true) DOCKERIMAGENAME_UI=vmware/harbor-ui
VERSIONTAG=dev DOCKERIMAGENAME_JOBSERVICE=vmware/harbor-jobservice
else DOCKERIMAGENAME_LOG=vmware/harbor-log
VERSIONTAG=$(shell $(GITTAG)) DOCKERIMAGENAME_DB=vmware/harbor-db
endif
# docker-compose files
SEDCMD=$(shell which sed) DOCKERCOMPOSEFILEPATH=$(MAKEPATH)
DOCKERCOMPOSETPLFILENAME=docker-compose.tpl
# package DOCKERCOMPOSEFILENAME=docker-compose.yml
TARCMD=$(shell which tar) DOCKERCOMPOSENOTARYFILENAME=docker-compose.notary.yml
ZIPCMD=$(shell which gzip)
DOCKERIMGFILE=harbor # version prepare
HARBORPKG=harbor VERSIONFILEPATH=$(CURDIR)
VERSIONFILENAME=VERSION
# pushimage GITCMD=$(shell which git)
PUSHSCRIPTPATH=$(MAKEPATH) GITTAG=$(GITCMD) describe --tags
PUSHSCRIPTNAME=pushimage.sh GITTAGVERSION=$(shell git describe --tags || echo UNKNOWN)
REGISTRYUSER=user ifeq ($(DEVFLAG), true)
REGISTRYPASSWORD=default VERSIONTAG=dev
else
version: VERSIONTAG=$(GITTAGVERSION)
@if [ "$(DEVFLAG)" = "false" ] ; then \ endif
$(SEDCMD) -i 's/version=\"{{.Version}}\"/version=\"$(VERSIONTAG)\"/' -i $(VERSIONFILEPATH)/$(VERSIONFILENAME) ; \
fi SEDCMD=$(shell which sed)
check_environment: # package
@$(MAKEPATH)/$(CHECKENVCMD) TARCMD=$(shell which tar)
ZIPCMD=$(shell which gzip)
compile_ui: DOCKERIMGFILE=harbor
@echo "compiling binary for ui..." HARBORPKG=harbor
@$(GOBUILD) -o $(UIBINARYPATH)/$(UIBINARYNAME) $(UISOURCECODE)
@echo "Done." # pushimage
PUSHSCRIPTPATH=$(MAKEPATH)
compile_jobservice: PUSHSCRIPTNAME=pushimage.sh
@echo "compiling binary for jobservice..." REGISTRYUSER=user
@$(GOBUILD) -o $(JOBSERVICEBINARYPATH)/$(JOBSERVICEBINARYNAME) $(JOBSERVICESOURCECODE) REGISTRYPASSWORD=default
@echo "Done."
version:
compile_normal: compile_ui compile_jobservice @printf $(GITTAGVERSION) > $(VERSIONFILEPATH)/$(VERSIONFILENAME);
compile_buildgolangimage: check_environment:
@echo "compiling golang image for harbor ..." @$(MAKEPATH)/$(CHECKENVCMD)
@$(DOCKERBUILD) -t $(GOBUILDIMAGE) -f $(TOOLSPATH)/$(GOLANGDOCKERFILENAME) .
@echo "Done." compile_adminserver:
@echo "compiling binary for adminserver..."
compile_golangimage: @$(GOBUILD) -o $(ADMINSERVERBINARYPATH)/$(ADMINSERVERBINARYNAME) $(ADMINSERVERSOURCECODE)
@echo "compiling binary for ui (golang image)..." @echo "Done."
@echo $(GOBASEPATH)
@echo $(GOBUILDPATH) compile_ui:
@$(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_UI) $(GOBUILDIMAGE) $(GOIMAGEBUILD) -v -o $(GOBUILDMAKEPATH_UI)/$(UIBINARYNAME) @echo "compiling binary for ui..."
@echo "Done." @$(GOBUILD) -o $(UIBINARYPATH)/$(UIBINARYNAME) $(UISOURCECODE)
@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) compile_jobservice:
@echo "Done." @echo "compiling binary for jobservice..."
@$(GOBUILD) -o $(JOBSERVICEBINARYPATH)/$(JOBSERVICEBINARYNAME) $(JOBSERVICESOURCECODE)
compile:check_environment $(COMPILETAG) @echo "Done."
prepare: compile_clarity:
@echo "preparing..." @echo "compiling binary for clarity ui..."
@$(MAKEPATH)/$(PREPARECMD) -conf $(CONFIGPATH)/$(CONFIGFILE) @if [ "$(HTTPPROXY)" != "" ] ; then \
$(DOCKERCMD) run --rm -v $(UIPATH)/static:$(CLARITYSEEDPATH)/dist -v $(UINGPATH)/src:$(CLARITYSEEDPATH)/src $(CLARITYIMAGE) $(SHELL) $(CLARITYBUILDSCRIPT) -p $(HTTPPROXY); \
build_common: version else \
@echo "buildging db container for photon..." $(DOCKERCMD) run --rm -v $(UIPATH)/static:$(CLARITYSEEDPATH)/dist -v $(UINGPATH)/src:$(CLARITYSEEDPATH)/src $(CLARITYIMAGE) $(SHELL) $(CLARITYBUILDSCRIPT); \
@cd $(DOCKERFILEPATH_DB) && $(DOCKERBUILD) -f $(DOCKERFILENAME_DB) -t $(DOCKERIMAGENAME_DB):$(VERSIONTAG) . fi
@echo "Done." @echo "Done."
build_photon: build_common compile_normal: compile_clarity compile_adminserver compile_ui compile_jobservice
make -f $(MAKEFILEPATH_PHOTON)/Makefile build -e DEVFLAG=$(DEVFLAG)
compile_golangimage: compile_clarity
build_ubuntu: build_common @echo "compiling binary for adminserver (golang image)..."
make -f $(MAKEFILEPATH_UBUNTU)/Makefile build -e DEVFLAG=$(DEVFLAG) @echo $(GOBASEPATH)
@echo $(GOBUILDPATH)
build: build_$(BASEIMAGE) @$(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_ADMINSERVER) $(GOBUILDIMAGE) $(GOIMAGEBUILD) -v -o $(GOBUILDMAKEPATH_ADMINSERVER)/$(ADMINSERVERBINARYNAME)
@echo "Done."
modify_composefile:
@echo "preparing docker-compose file..." @echo "compiling binary for ui (golang image)..."
@cp $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSETPLFILENAME) $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSEFILENAME) @echo $(GOBASEPATH)
@$(SEDCMD) -i 's/image\: vmware.*/&:$(VERSIONTAG)/g' $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSEFILENAME) @echo $(GOBUILDPATH)
@$(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_UI) $(GOBUILDIMAGE) $(GOIMAGEBUILD) -v -o $(GOBUILDMAKEPATH_UI)/$(UIBINARYNAME)
install: compile build prepare modify_composefile @echo "Done."
@echo "loading harbor images..."
@$(DOCKERCOMPOSECMD) -f $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSEFILENAME) up -d @echo "compiling binary for jobservice (golang image)..."
@echo "Install complete. You can visit harbor now." @$(DOCKERCMD) run --rm -v $(BUILDPATH):$(GOBUILDPATH) -w $(GOBUILDPATH_JOBSERVICE) $(GOBUILDIMAGE) $(GOIMAGEBUILD) -v -o $(GOBUILDMAKEPATH_JOBSERVICE)/$(JOBSERVICEBINARYNAME)
@echo "Done."
package_online: modify_composefile
@echo "packing online package ..." compile:check_environment $(COMPILETAG)
@cp -r make $(HARBORPKG)
@if [ -n "$(REGISTRYSERVER)" ] ; then \ prepare:
$(SEDCMD) -i 's/image\: vmware/image\: $(REGISTRYSERVER)\/$(REGISTRYPROJECTNAME)/' \ @echo "preparing..."
$(HARBORPKG)/docker-compose.yml ; \ @if [ "$(NOTARYFLAG)" = "true" ] ; then \
fi $(MAKEPATH)/$(PREPARECMD) --conf $(CONFIGPATH)/$(CONFIGFILE) --with-notary; \
@cp LICENSE $(HARBORPKG)/LICENSE else \
@cp NOTICE $(HARBORPKG)/NOTICE $(MAKEPATH)/$(PREPARECMD) --conf $(CONFIGPATH)/$(CONFIGFILE) ; \
@$(TARCMD) -zcvf harbor-online-installer-$(VERSIONTAG).tgz \ fi
--exclude=$(HARBORPKG)/common/db --exclude=$(HARBORPKG)/common/config\
--exclude=$(HARBORPKG)/common/log --exclude=$(HARBORPKG)/ubuntu \ build_common: version
--exclude=$(HARBORPKG)/photon --exclude=$(HARBORPKG)/kubernetes \ @echo "buildging db container for photon..."
--exclude=$(HARBORPKG)/dev --exclude=$(DOCKERCOMPOSETPLFILENAME) \ @cd $(DOCKERFILEPATH_DB) && $(DOCKERBUILD) -f $(DOCKERFILENAME_DB) -t $(DOCKERIMAGENAME_DB):$(VERSIONTAG) .
--exclude=$(HARBORPKG)/checkenv.sh \ @echo "Done."
--exclude=$(HARBORPKG)/jsminify.sh \
--exclude=$(HARBORPKG)/pushimage.sh \ build_photon: build_common
$(HARBORPKG) make -f $(MAKEFILEPATH_PHOTON)/Makefile build -e DEVFLAG=$(DEVFLAG)
@rm -rf $(HARBORPKG) build: build_$(BASEIMAGE)
@echo "Done."
modify_composefile:
package_offline: compile build modify_composefile @echo "preparing docker-compose file..."
@echo "packing offline package ..." @cp $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSETPLFILENAME) $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSEFILENAME)
@cp -r make $(HARBORPKG) @$(SEDCMD) -i 's/__version__/$(VERSIONTAG)/g' $(DOCKERCOMPOSEFILEPATH)/$(DOCKERCOMPOSEFILENAME)
@cp LICENSE $(HARBORPKG)/LICENSE modify_sourcefiles:
@cp NOTICE $(HARBORPKG)/NOTICE @echo "change mode of source files."
@chmod 600 $(MAKEPATH)/common/templates/notary/notary-signer.key
@echo "pulling nginx and registry..." @chmod 600 $(MAKEPATH)/common/templates/notary/notary-signer.crt
@$(DOCKERPULL) registry:2.5.0 @chmod 600 $(MAKEPATH)/common/templates/notary/notary-signer-ca.crt
@$(DOCKERPULL) nginx:1.11.5 @chmod 600 $(MAKEPATH)/common/templates/ui/private_key.pem
@chmod 600 $(MAKEPATH)/common/templates/registry/root.crt
@echo "saving harbor docker image"
@$(DOCKERSAVE) -o $(HARBORPKG)/$(DOCKERIMGFILE).$(VERSIONTAG).tgz \ install: compile build modify_sourcefiles prepare modify_composefile start
$(DOCKERIMAGENAME_UI):$(VERSIONTAG) \
$(DOCKERIMAGENAME_LOG):$(VERSIONTAG) \ package_online: modify_composefile
$(DOCKERIMAGENAME_DB):$(VERSIONTAG) \ @echo "packing online package ..."
$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) \ @cp -r make $(HARBORPKG)
nginx:1.11.5 registry:2.5.0 photon:1.0 @if [ -n "$(REGISTRYSERVER)" ] ; then \
$(SEDCMD) -i 's/image\: vmware/image\: $(REGISTRYSERVER)\/$(REGISTRYPROJECTNAME)/' \
@$(TARCMD) -zcvf harbor-offline-installer-$(VERSIONTAG).tgz \ $(HARBORPKG)/docker-compose.yml ; \
--exclude=$(HARBORPKG)/common/db --exclude=$(HARBORPKG)/common/config\ fi
--exclude=$(HARBORPKG)/common/log --exclude=$(HARBORPKG)/ubuntu \ @cp LICENSE $(HARBORPKG)/LICENSE
--exclude=$(HARBORPKG)/photon --exclude=$(HARBORPKG)/kubernetes \ @cp NOTICE $(HARBORPKG)/NOTICE
--exclude=$(HARBORPKG)/dev --exclude=$(DOCKERCOMPOSETPLFILENAME) \
--exclude=$(HARBORPKG)/checkenv.sh \ @if [ "$(NOTARYFLAG)" = "true" ] ; then \
--exclude=$(HARBORPKG)/jsminify.sh \ $(TARCMD) -zcvf harbor-online-installer-$(GITTAGVERSION).tgz \
--exclude=$(HARBORPKG)/pushimage.sh \ $(HARBORPKG)/common/templates $(HARBORPKG)/prepare \
$(HARBORPKG) $(HARBORPKG)/LICENSE $(HARBORPKG)/NOTICE \
$(HARBORPKG)/install.sh $(HARBORPKG)/$(DOCKERCOMPOSEFILENAME) \
@rm -rf $(HARBORPKG) $(HARBORPKG)/harbor.cfg $(HARBORPKG)/$(DOCKERCOMPOSENOTARYFILENAME); \
@echo "Done." else \
$(TARCMD) -zcvf harbor-online-installer-$(GITTAGVERSION).tgz \
pushimage: $(HARBORPKG)/common/templates $(HARBORPKG)/prepare \
@echo "pushing harbor images ..." $(HARBORPKG)/LICENSE $(HARBORPKG)/NOTICE \
@$(DOCKERTAG) $(DOCKERIMAGENAME_UI):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG) $(HARBORPKG)/install.sh $(HARBORPKG)/$(DOCKERCOMPOSEFILENAME) \
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG) \ $(HARBORPKG)/harbor.cfg ; \
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER) fi
@$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG)
@rm -rf $(HARBORPKG)
@$(DOCKERTAG) $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) @echo "Done."
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) \
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER) package_offline: compile build modify_sourcefiles modify_composefile
@$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) @echo "packing offline package ..."
@cp -r make $(HARBORPKG)
@$(DOCKERTAG) $(DOCKERIMAGENAME_LOG):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_LOG):$(VERSIONTAG)
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_LOG):$(VERSIONTAG) \ @cp LICENSE $(HARBORPKG)/LICENSE
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER) @cp NOTICE $(HARBORPKG)/NOTICE
@$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_LOG):$(VERSIONTAG)
@echo "pulling nginx and registry..."
@$(DOCKERTAG) $(DOCKERIMAGENAME_DB):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_DB):$(VERSIONTAG) @$(DOCKERPULL) vmware/registry:$(REGISTRYVERSION)
@$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_DB):$(VERSIONTAG) \ @$(DOCKERPULL) vmware/nginx:$(NGINXVERSION)
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER) @if [ "$(NOTARYFLAG)" = "true" ] ; then \
@$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_DB):$(VERSIONTAG) echo "pulling notary and harbor-notary-db..."; \
$(DOCKERPULL) vmware/notary-photon:$(NOTARYVERSION); \
start: $(DOCKERPULL) vmware/notary-photon:$(NOTARYSIGNERVERSION); \
@echo "loading harbor images..." $(DOCKERPULL) vmware/harbor-notary-db:$(MARIADBVERSION); \
@$(DOCKERCOMPOSECMD) -f $(DOCKERCOMPOSEFILEPATH)/docker-compose.yml up -d fi
@echo "Start complete. You can visit harbor now."
@echo "saving harbor docker image"
down: @if [ "$(NOTARYFLAG)" = "true" ] ; then \
@echo "stoping harbor instance..." $(DOCKERSAVE) $(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG) \
@$(DOCKERCOMPOSECMD) -f $(DOCKERCOMPOSEFILEPATH)/docker-compose.yml down $(DOCKERIMAGENAME_UI):$(VERSIONTAG) \
@echo "Done." $(DOCKERIMAGENAME_LOG):$(VERSIONTAG) \
$(DOCKERIMAGENAME_DB):$(VERSIONTAG) \
cleanbinary: $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) \
@echo "cleaning binary..." vmware/nginx:$(NGINXVERSION) vmware/registry:$(REGISTRYVERSION) photon:$(PHOTONVERSION) \
@if [ -f $(UIBINARYPATH)/$(UIBINARYNAME) ] ; then rm $(UIBINARYPATH)/$(UIBINARYNAME) ; fi vmware/notary-photon:$(NOTARYVERSION) vmware/notary-photon:$(NOTARYSIGNERVERSION) \
@if [ -f $(JOBSERVICEBINARYPATH)/$(JOBSERVICEBINARYNAME) ] ; then rm $(JOBSERVICEBINARYPATH)/$(JOBSERVICEBINARYNAME) ; fi vmware/harbor-notary-db:$(MARIADBVERSION) | gzip > $(HARBORPKG)/$(DOCKERIMGFILE).$(VERSIONTAG).tar.gz; \
else \
cleanimage: $(DOCKERSAVE) $(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG) \
@echo "cleaning image for photon..." $(DOCKERIMAGENAME_UI):$(VERSIONTAG) \
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_UI):$(VERSIONTAG) $(DOCKERIMAGENAME_LOG):$(VERSIONTAG) \
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_DB):$(VERSIONTAG) $(DOCKERIMAGENAME_DB):$(VERSIONTAG) \
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) \
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_LOG):$(VERSIONTAG) vmware/nginx:$(NGINXVERSION) vmware/registry:$(REGISTRYVERSION) \
# - $(DOCKERRMIMAGE) -f registry:2.5.0 photon:$(PHOTONVERSION) | gzip > $(HARBORPKG)/$(DOCKERIMGFILE).$(VERSIONTAG).tar.gz; \
# - $(DOCKERRMIMAGE) -f nginx:1.11.5 fi
cleandockercomposefile: @if [ "$(NOTARYFLAG)" = "true" ] ; then \
@echo "cleaning $(DOCKERCOMPOSEFILEPATH)/docker-compose.yml" $(TARCMD) -zcvf harbor-offline-installer-$(GITTAGVERSION).tgz \
@if [ -f $(DOCKERCOMPOSEFILEPATH)/docker-compose.yml ] ; then rm $(DOCKERCOMPOSEFILEPATH)/docker-compose.yml ; fi $(HARBORPKG)/common/templates $(HARBORPKG)/$(DOCKERIMGFILE).$(VERSIONTAG).tar.gz \
$(HARBORPKG)/prepare $(HARBORPKG)/NOTICE \
cleanversiontag: $(HARBORPKG)/LICENSE $(HARBORPKG)/install.sh \
@echo "cleaning version TAG" $(HARBORPKG)/harbor.cfg $(HARBORPKG)/$(DOCKERCOMPOSEFILENAME) \
@$(SEDCMD) -i 's/version=\"$(VERSIONTAG)\"/version=\"{{.Version}}\"/' -i $(VERSIONFILEPATH)/$(VERSIONFILENAME) $(HARBORPKG)/$(DOCKERCOMPOSENOTARYFILENAME) ; \
else \
cleanpackage: $(TARCMD) -zcvf harbor-offline-installer-$(GITTAGVERSION).tgz \
@echo "cleaning harbor install package" $(HARBORPKG)/common/templates $(HARBORPKG)/$(DOCKERIMGFILE).$(VERSIONTAG).tar.gz \
@if [ -d $(BUILDPATH)/harbor ] ; then rm -rf $(BUILDPATH)/harbor ; fi $(HARBORPKG)/prepare $(HARBORPKG)/NOTICE \
@if [ -f $(BUILDPATH)/harbor-online-installer-$(VERSIONTAG).tgz ] ; \ $(HARBORPKG)/LICENSE $(HARBORPKG)/install.sh \
then rm $(BUILDPATH)/harbor-online-installer-$(VERSIONTAG).tgz ; fi $(HARBORPKG)/harbor.cfg $(HARBORPKG)/$(DOCKERCOMPOSEFILENAME) ; \
@if [ -f $(BUILDPATH)/harbor-offline-installer-$(VERSIONTAG).tgz ] ; \ fi
then rm $(BUILDPATH)/harbor-offline-installer-$(VERSIONTAG).tgz ; fi
@rm -rf $(HARBORPKG)
.PHONY: cleanall @echo "Done."
cleanall: cleanbinary cleanimage cleandockercomposefile cleanversiontag cleanpackage
pushimage:
clean: @echo "pushing harbor images ..."
@echo " make cleanall: remove binary, Harbor images, specific version docker-compose" @$(DOCKERTAG) $(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG)
@echo " file, specific version tag, online and offline install package" @$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG) \
@echo " make cleanbinary: remove ui and jobservice binary" $(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER)
@echo " make cleanimage: remove Harbor images" @$(DOCKERRMIMAGE) $(REGISTRYSERVER)$(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG)
@echo " make cleandockercomposefile: remove specific version docker-compose"
@echo " make cleanversiontag: cleanpackageremove specific version tag" @$(DOCKERTAG) $(DOCKERIMAGENAME_UI):$(VERSIONTAG) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG)
@echo " make cleanpackage: remove online and offline install package" @$(PUSHSCRIPTPATH)/$(PUSHSCRIPTNAME) $(REGISTRYSERVER)$(DOCKERIMAGENAME_UI):$(VERSIONTAG) \
$(REGISTRYUSER) $(REGISTRYPASSWORD) $(REGISTRYSERVER)
all: install @$(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
View File

@ -1,8 +1,8 @@
NOTICE 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. 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.

View File

@ -3,6 +3,9 @@
[![Build Status](https://travis-ci.org/vmware/harbor.svg?branch=master)](https://travis-ci.org/vmware/harbor) [![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) [![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"> <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. 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. * **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. * **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. * **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. * **Graphical user portal**: User can easily browse, search repositories and manage projects.
* **Auditing**: All the operations to the repositories are tracked. * **Auditing**: All the operations to the repositories are tracked.
* **RESTful API**: RESTful APIs for most administrative operations, easy to integrate with external systems. * **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 ### 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 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. 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. 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: 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) * 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) * 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) * NGINX 1.11.5: [docker image](https://hub.docker.com/_/nginx/), [license](https://github.com/nginxinc/docker-nginx/blob/master/LICENSE)

View File

@ -20,28 +20,22 @@ The notary feature allows publishers to sign their images offline and to push th
### 2. Vulnerability Scanning ### 2. Vulnerability Scanning
The capability to scan images for vulnerability. The capability to scan images for vulnerability.
### 3. Image replication between Harbor instances (Completed) ### 3. Image replication enhancement
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. 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) ### 4. Authentication (OAuth2)
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)
In addition to LDAP/AD and local users, OAuth 2.0 can be used to authenticate a user. 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. 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. User can add a description to a repository. The access count of a repo can be aggregated and displayed.
### 7. Migration tool to move from an existing registry to Harbor
### 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
A tool to migrate images from a vanilla registry server to Harbor, without the need to export/import a large amount of data. A tool to migrate images from a vanilla registry server to Harbor, without the need to export/import a large amount of data.

1
VERSION Normal file
View File

@ -0,0 +1 @@
dev

View File

@ -6,9 +6,6 @@
Read this first!** Read this first!**
Guide for Harbor online installer and offline installer. 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)** **[Harbor User Guide](user_guide.md)**
How to use Harbor to manage images, projects, replications and users. 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/) [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/) [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/) [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/) [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/) [Making a Private Secured Docker Registry in 15 Minutes](http://alexanderzeitler.com/articles/deploying-a-private-secured-docker-registry-within-15-minutes/)

View File

@ -1,21 +1,21 @@
## Introduction ## 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 ## 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 Software | Required Version
----------------------|-------------------------- ----------------------|--------------------------
docker | 1.10.0 + docker | 1.12.0 +
docker-compose | 1.7.1 + docker-compose | 1.11.0 +
python | 2.7 + python | 2.7 +
git | 1.9.1 + git | 1.9.1 +
make | 3.81 + make | 3.81 +
golang* | 1.6.0 + golang* | 1.7.3 +
*optional *optional, required only if you use your own Golang environment.
## Step 2: Getting the source code ## Step 2: Getting the source code
@ -24,52 +24,39 @@ golang* | 1.6.0 +
$ git clone https://github.com/vmware/harbor $ git clone https://github.com/vmware/harbor
``` ```
## Step 3: Resolving dependencies of Go language ## Step 3: Building and installing Harbor
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
### Configuration ### 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 ```sh
$ cd harbor $ cd harbor
$ vi make/harbor.cfg $ vi make/harbor.cfg
``` ```
### Compiling and Running ### Compiling and Running
You can compile the code by one of the three approaches: 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 ```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 ```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 #### 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/. $ mv harbor $GOPATH/src/github.com/vmware/.
``` ```
* Build, install and run Harbor * Build, install and run Harbor without Notary:
```sh ```sh
$ cd $GOPATH/src/github.com/vmware/harbor $ cd $GOPATH/src/github.com/vmware/harbor
$ make install $ make install
``` ```
#### III. Manual build process (compatible with previous versions) * Build, install and run Harbor with Notary:
```sh ```sh
$ cd make $ cd $GOPATH/src/github.com/vmware/harbor
$ make install -e NOTARYFLAG=true
$ ./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
```
### Verify your installation ### Verify your installation
If everyting worked properly, you can get the below message: If everything worked properly, you can get the below message:
```sh ```sh
... ...
----Harbor has been installed and started successfully.---- Start complete. You can visit harbor now.
Now you should be able to visit the admin portal at http://$YOURIP.
For more details, please visit https://github.com/vmware/harbor .
``` ```
Refer to [Installation and Configuration Guide](installation_guide.md#managing-harbors-lifecycle) for more information about managing your Harbor instance. 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 Variable | Description
-------------------|------------- -------------------|-------------
BASEIMAGE | Container base image, default: photon BASEIMAGE | Container base image, default: photon
CLARITYIMAGE | Clarity UI builder image, default: harbor-clarity-ui-builder
DEVFLAG | Build model flag, default: dev DEVFLAG | Build model flag, default: dev
COMPILETAG | Compile model flag, default: compile_normal (local golang build) 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 REGISTRYSERVER | Remote registry server IP address
REGISTRYUSER | Remote registry server user name REGISTRYUSER | Remote registry server user name
REGISTRYPASSWORD | Remote registry server user password REGISTRYPASSWORD | Remote registry server user password
@ -139,44 +116,29 @@ REGISTRYPROJECTNAME| Project name on remote registry server
Target | Description 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 prepare | prepare env
compile | compile ui and jobservice code compile | compile ui and jobservice code
compile_golangimage | compile local golang image
compile_ui | compile ui binary compile_ui | compile ui binary
compile_jobservice | compile jobservice binary compile_jobservice | compile jobservice binary
compile_clarity | compile Clarity binary
build | build Harbor docker images (default: using build_photon) build | build Harbor docker images (default: using build_photon)
build_photon | build Harbor docker images from Photon OS base image 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 install | compile binaries, build images, prepare specific version of compose file and startup Harbor instance
start | startup Harbor instance start | startup Harbor instance (set NOTARYFLAG=true when with Notary)
down | shutdown Harbor instance down | shutdown Harbor instance (set NOTARYFLAG=true when with Notary)
package_online | prepare online install package package_online | prepare online install package
package_offline | prepare offline install package package_offline | prepare offline install package
pushimage | push Harbor images to specific registry server 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 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 cleanbinary | remove ui and jobservice binary
cleanimage | remove Harbor images cleanimage | remove Harbor images
cleandockercomposefile | remove specific version docker-compose cleandockercomposefile | remove specific version docker-compose
cleanversiontag | remove specific version tag cleanversiontag | remove specific version tag
cleanpackage | remove online/offline install package cleanpackage | remove online/offline install package
#### EXAMPLE: #### 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 #### Push Harbor images to specific registry server
```sh ```sh
@ -198,7 +160,7 @@ cleanpackage | remove online/offline install package
$ make clean -e VERSIONTAG=[TAG] $ 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. #### 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 $ make XXXX -e DEVFLAG=false
``` ```

View File

@ -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. 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**. 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 openssl x509 -req -days 365 -in yourdomain.com.csr -CA ca.crt -CAkey ca.key -CAcreateserial -extfile extfile.cnf -out yourdomain.com
.crt .crt
``` ```
##Configuration and Installation ## Configuration and Installation
After obtaining the **yourdomain.com.crt** and **yourdomain.com.key** files, After obtaining the **yourdomain.com.crt** and **yourdomain.com.key** files,
you can put them into directory such as ```/root/cert/```: 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 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. 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:
``` ```

View File

@ -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. 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.

View File

@ -4,57 +4,55 @@
### Steps to localize the UI in your language ### 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', "APP_TITLE": {
'sign_up': 'Sign Up', "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" }} export const supportedLangs = ['en-us', 'zh-cn', '<language>-<locale>'];
<script src="/static/resources/js/services/i18n/locale_messages_zh-CN.js"></script> ```
{{ else if eq .Lang "en-US"}} Define the language display name and append it to the name list:
<script src="/static/resources/js/services/i18n/locale_messages_en-US.js"></script> ```
{{ else if eq .Lang "<language>-<locale>"}} export const languageNames = {
<script src="/static/resources/js/services/i18n/locale_messages_<language>-<locale>.js"></script> "en-us": "English",
{{ end }} "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.** **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. Locate the file `src/ui_ng/src/app/base/navigator/navigator.component.html` and then find the following code piece:
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.
``` ```
[lang] <div class="dropdown-menu">
types = en-US|zh-CN|<language>-<locale> <a href="javascript:void(0)" clrDropdownItem (click)='switchLanguage("en-us")' [class.lang-selected]='matchLang("en-us")'>English</a>
names = en-US|zh-CN|<language>-<locale> <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: 4. Next, please refer [compile guideline](compile_guide.md) to rebuild and restart Harbor.
```
docker-compose down
docker-compose up --build -d
```

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
docs/img/ldap_auth.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 57 KiB

BIN
docs/img/new_auth.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
docs/img/new_delete_tag.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 52 KiB

BIN
docs/img/new_rule_list.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 46 KiB

BIN
docs/img/new_self_reg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -1,21 +1,18 @@
# Installation and Configuration Guide # 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. - **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. - **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. 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. 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)**. 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 ## 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. 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 #### Configuring Harbor
Configuration parameters are located in the file **harbor.cfg**. 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. 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!_ * **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 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 = smtp.mydomain.com
* email_server_port = 25 * email_server_port = 25
* email_username = sample_admin@mydomain.com * email_username = sample_admin@mydomain.com
* email_password = abc * email_password = abc
* email_from = `admin \<sample_admin@mydomain.com\>` * email_from = admin <sample_admin@mydomain.com>
* email_ssl = false * 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** ._ * **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**. * **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_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_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. * **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 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._
* **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.
* **token_expiration**: The expiration time (in minutes) of a token created by token service, default is 30 minutes. * **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. * **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) #### 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 #### 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. 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 ```sh
$ sudo ./install.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. **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)** . For information on how to use Harbor, please refer to **[User Guide of Harbor](user_guide.md)** .
#### Configuring Harbor with HTTPS access #### Configuring Harbor with HTTPS access
@ -146,18 +166,17 @@ Starting registry ... done
Starting proxy ... 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 $ vim harbor.cfg
$ sudo prepare
$ sudo install.sh $ sudo docker-compose up -d
``` ```
Removing Harbor's containers while keeping the image data and Harbor's database files on the file system: 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): Removing Harbor's database and image data (for a clean re-installation):
@ -166,6 +185,20 @@ $ rm -r /data/database
$ rm -r /data/registry $ 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. Please check the [Docker Compose command-line reference](https://docs.docker.com/compose/reference/) for more on docker-compose.
### Persistent data and log files ### Persistent data and log files
@ -202,27 +235,17 @@ proxy:
tag: "proxy" tag: "proxy"
``` ```
2.Modify templates/registry/config.yml 2.Modify harbor.cfg, add the port to the parameter "hostname"
Add the customized port, e.g. ":8888", after "$ui_url".
``` ```
auth: hostname = 192.168.0.2:8888
token:
issuer: registry-token-issuer
realm: $ui_url:8888/service/token
rootcertbundle: /etc/registry/root.crt
service: token-service
``` ```
3.Run install.sh to update and start Harbor. 3.Re-deploy Harbor refering to previous section "Managing Harbor's lifecycle".
```sh
$ sudo docker-compose down
$ sudo install.sh
```
### For HTTPS protocol ### For HTTPS protocol
1.Enable HTTPS in Harbor by following this [guide](https://github.com/vmware/harbor/blob/master/docs/configure_https.md). 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 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: proxy:
@ -232,7 +255,7 @@ proxy:
- ./config/nginx:/etc/nginx - ./config/nginx:/etc/nginx
ports: ports:
- 80:80 - 80:80
- 4443:443 - 8888:443
depends_on: depends_on:
- mysql - mysql
- registry - registry
@ -245,23 +268,14 @@ proxy:
tag: "proxy" tag: "proxy"
``` ```
3.Modify templates/registry/config.yml 3.Modify harbor.cfg, add the port to the parameter "hostname"
Add the customized port, e.g. ":4443", after "$ui_url".
``` ```
auth: hostname = 192.168.0.2:8888
token:
issuer: registry-token-issuer
realm: $ui_url:4443/service/token
rootcertbundle: /etc/registry/root.crt
service: token-service
``` ```
4.Run install.sh to update and start Harbor. 4.Re-deploy Harbor refering to previous section "Managing Harbor's lifecycle".
```sh
$ sudo docker-compose down
$ sudo install.sh
```
## Troubleshooting ## Troubleshooting
1. When Harbor does not work properly, run the below commands to find out if all containers of Harbor are in **UP** status: 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-db docker-entrypoint.sh mysqld Up 3306/tcp
harbor-jobservice /harbor/harbor_jobservice Up 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 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 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 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; proxy_set_header X-Forwarded-Proto $scheme;
``` ```
And run the following commands to restart Harbor: and re-deploy Harbor refer to the previous section "Managing Harbor's lifecycle".
```sh
$ sudo docker-compose down
$ sudo ./prepare
$ sudo docker-compose up -d
```

View File

@ -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>
```

View File

@ -1,5 +1,3 @@
# this is an example of the Uber API
# as a demonstration of an API spec in YAML
swagger: '2.0' swagger: '2.0'
info: info:
title: Harbor API title: Harbor API
@ -517,7 +515,6 @@ paths:
responses: responses:
200: 200:
description: Get current user information successfully. description: Get current user information successfully.
in: body
schema: schema:
$ref: '#/definitions/User' $ref: '#/definitions/User'
401: 401:
@ -659,6 +656,11 @@ paths:
format: int32 format: int32
required: true required: true
description: Relevant project ID. description: Relevant project ID.
- name: detail
in: query
type: boolean
required: false
description: Get detail info or not.
- name: q - name: q
in: query in: query
type: string type: string
@ -680,11 +682,11 @@ paths:
- Products - Products
responses: responses:
200: 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: schema:
type: array type: array
items: items:
type: string $ref: '#/definitions/Repository'
headers: headers:
X-Total-Count: X-Total-Count:
description: The total count of repositories description: The total count of repositories
@ -700,26 +702,27 @@ paths:
description: Project ID does not exist. description: Project ID does not exist.
500: 500:
description: Unexpected internal errors. description: Unexpected internal errors.
/repositories/{repo_name}/tags/{tag}:
delete: delete:
summary: Delete a repository or a tag in a repository. summary: Delete a tag in a repository.
description: | 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: parameters:
- name: repo_name - name: repo_name
in: query in: path
type: string type: string
required: true required: true
description: The name of repository which will be deleted. description: The name of repository which will be deleted.
- name: tag - name: tag
in: query in: path
type: string type: string
required: false required: true
description: Tag of a repository. description: Tag of a repository.
tags: tags:
- Products - Products
responses: responses:
200: 200:
description: Delete repository or tag successfully. description: Delete tag successfully.
400: 400:
description: Invalid repo_name. description: Invalid repo_name.
401: 401:
@ -728,41 +731,69 @@ paths:
description: Repository or tag not found. description: Repository or tag not found.
403: 403:
description: Forbidden. description: Forbidden.
/repositories/tags: /repositories/{repo_name}/tags:
get: get:
summary: Get tags of a relevant repository. summary: Get tags of a relevant repository.
description: | description: |
This endpoint aims to retrieve tags from a relevant repository. This endpoint aims to retrieve tags from a relevant repository.
parameters: parameters:
- name: repo_name - name: repo_name
in: query in: path
type: string type: string
required: true required: true
description: Relevant repository name. description: Relevant repository name.
- name: detail
in: query
type: boolean
required: false
description: If detail is true, the manifests is returned too.
tags: tags:
- Products - Products
responses: responses:
200: 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: schema:
type: array type: array
items: items:
type: string $ref: '#/definitions/DetailedTag'
500: 500:
description: Unexpected internal errors. 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: get:
summary: Get manifests of a relevant repository. summary: Get manifests of a relevant repository.
description: | description: |
This endpoint aims to retreive manifests from a relevant repository. This endpoint aims to retreive manifests from a relevant repository.
parameters: parameters:
- name: repo_name - name: repo_name
in: query in: path
type: string type: string
required: true required: true
description: Repository name description: Repository name
- name: tag - name: tag
in: query in: path
type: string type: string
required: true required: true
description: Tag name description: Tag name
@ -777,11 +808,37 @@ paths:
200: 200:
description: Retrieved manifests from a relevant repository successfully. description: Retrieved manifests from a relevant repository successfully.
schema: schema:
$ref: '#/definitions/Repository' $ref: '#/definitions/Manifest'
404: 404:
description: Retrieved manifests from a relevant repository not found. description: Retrieved manifests from a relevant repository not found.
500: 500:
description: Unexpected internal errors. 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: /repositories/top:
get: get:
summary: Get public repositories which are accessed most. summary: Get public repositories which are accessed most.
@ -794,15 +851,20 @@ paths:
format: int32 format: int32
required: false required: false
description: The number of the requested public repositories, default is 10 if not provided. 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: tags:
- Products - Products
responses: responses:
200: 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: schema:
type: array type: array
items: items:
$ref: '#/definitions/TopRepo' $ref: '#/definitions/Repository'
400: 400:
description: Bad request because of invalid count. description: Bad request because of invalid count.
500: 500:
@ -1168,12 +1230,12 @@ paths:
description: | description: |
This endpoint is for ping validates whether the target is reachable and whether the credential is valid. This endpoint is for ping validates whether the target is reachable and whether the credential is valid.
parameters: parameters:
- name: id - name: target
in: query in: body
type: integer description: The target object.
format: int64 required: true
required: false schema:
description: The replication's policy ID. $ref: '#/definitions/PingTarget'
tags: tags:
- Products - Products
responses: responses:
@ -1187,6 +1249,31 @@ paths:
description: Target not found. description: Target not found.
500: 500:
description: Unexpected internal errors. 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}: /targets/{id}:
put: put:
summary: Update replication's target. summary: Update replication's target.
@ -1203,7 +1290,7 @@ paths:
in: body in: body
required: true required: true
schema: schema:
$ref: '#/definitions/RepTargetPost' $ref: '#/definitions/PutTarget'
description: Updates of replication's target. description: Updates of replication's target.
tags: tags:
- Products - Products
@ -1309,7 +1396,229 @@ paths:
403: 403:
description: User does not have permission of admin role. description: User does not have permission of admin role.
500: 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: definitions:
Search: Search:
type: object type: object
@ -1318,26 +1627,12 @@ definitions:
description: Search results of the projects that matched the filter keywords. description: Search results of the projects that matched the filter keywords.
type: array type: array
items: items:
$ref: '#/definitions/SearchProject' $ref: '#/definitions/Project'
repositories: repositories:
description: Search results of the repositories that matched the filter keywords. description: Search results of the repositories that matched the filter keywords.
type: array type: array
items: items:
$ref: '#/definitions/SearchRepository' $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: SearchRepository:
type: object type: object
properties: properties:
@ -1353,6 +1648,12 @@ definitions:
repository_name: repository_name:
type: string type: string
description: The name of the repository 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: ProjectReq:
type: object type: object
properties: properties:
@ -1403,7 +1704,7 @@ definitions:
repo_count: repo_count:
type: integer type: integer
description: The number of the repositories under this project. description: The number of the repositories under this project.
Repository: Manifest:
type: object type: object
properties: properties:
manifest: manifest:
@ -1522,7 +1823,7 @@ definitions:
TopRepo: TopRepo:
type: object type: object
properties: properties:
repo_name: name:
type: string type: string
description: The name of the repo description: The name of the repo
count: count:
@ -1723,6 +2024,33 @@ definitions:
password: password:
type: string type: string
description: The target server password. 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: HasAdminRole:
type: object type: object
properties: properties:
@ -1741,3 +2069,179 @@ definitions:
comment: comment:
type: string type: string
description: The new comment. 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
View 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
View 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"
```

View File

@ -1,5 +1,5 @@
#User Guide # User Guide
##Overview ## Overview
This guide walks you through the fundamentals of using Harbor. You'll learn how to use Harbor to: This guide walks you through the fundamentals of using Harbor. You'll learn how to use Harbor to:
* Manage your projects. * 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. * Replicate projects to a remote registry.
* Search projects and repositories. * Search projects and repositories.
* Manage Harbor system if you are the system administrator: * Manage Harbor system if you are the system administrator:
+ Manage users. * Manage users.
+ Manage destinations. * Manage destinations.
+ Manage replication policies. * Manage replication policies.
* Manage configuration.
* Pull and push images using Docker client. * Pull and push images using Docker client.
* Delete repositories and images. * Delete repositories and images.
* Content trust.
## Role Based Access Control(RBAC)
##Role Based Access Control
![rbac](img/rbac.png) ![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: 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. * **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: Harbor supports two authentication modes:
* **Database(db_auth)** * **Database(db_auth)**
Users are stored in the local database. 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. 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. 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: 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. * **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) ![browse project](img/new_project_log.png)
##Managing members of a project ## Managing members of a project
###Adding members ### Adding members
You can add members with different roles to an existing project. You can add members with different roles to an existing project.
![browse project](img/new_add_member.png) ![browse project](img/new_add_member.png)
###Updating and removing members ### Updating and removing members
You can update or remove a member by clicking the icon on the right. You can update or remove a member by clicking the icon on the left.
![browse project](img/new_remove_update_member.png) ![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. 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. 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. **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 ## 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. 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) ![browse project](img/new_search.png)
##Administrator options ## Administrator options
###Managing user ### 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 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) ![browse project](img/new_set_admin_remove_user.png)
###Managing destination ### Managing endpoint
You can list, add, edit and delete destinations in the "Destination" tab. Only destinations which are not referenced by any policies can be edited. 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 ### Managing replication
You can list, edit, enable and disable policies in the "Replication" tab. Make sure the policy is disabled before you edit it. 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) ![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.** **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: 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*
###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: If the project that the image belongs to is private, you should sign in first:
```sh ```sh
@ -149,9 +176,9 @@ You can now pull the image:
$ docker pull 10.117.169.182/library/ubuntu:14.04 $ 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. Before pushing an image, you must create a corresponding project on Harbor web UI.
First, log in from Docker client: 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.** **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. 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, 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. 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. 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 ```sh
$ docker-compose stop $ 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. **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. Verify the result of the above test, then use the below commands to perform garbage collection and restart Harbor.
```sh ```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 $ docker-compose start
``` ```
For more information about GC, please see [GC](https://github.com/docker/docker.github.io/blob/master/registry/garbage-collection.md). 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)

View File

@ -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).

View File

@ -1,4 +1,4 @@
FROM mysql:5.6 FROM mysql:5.6.35
WORKDIR /tmp WORKDIR /tmp

View File

@ -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 # These statements _must_ be on individual lines, and _must_ end with
# semicolons (no line breaks or comments are permitted). # semicolons (no line breaks or comments are permitted).
# TODO proper SQL escaping on ALL the things D: # 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' TEMP_FILE='/tmp/mysql-first-time.sql'
cat > "$TEMP_FILE" <<-EOSQL cat > "$TEMP_FILE" <<-EOSQL
DELETE FROM mysql.user ; DELETE FROM mysql.user ;

View 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

View File

@ -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_LEVEL=debug
LOG_DIR=/var/log/jobs CONFIG_PATH=/etc/jobservice/app.conf
UI_SECRET=$ui_secret
JOBSERVICE_SECRET=$jobservice_secret
GODEBUG=netdns=cgo GODEBUG=netdns=cgo
EXT_ENDPOINT=$ui_url
TOKEN_ENDPOINT=http://ui

View File

@ -21,6 +21,12 @@ http {
server ui:80; 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 { server {
listen 80; listen 80;

View File

@ -8,11 +8,11 @@ events {
http { http {
tcp_nodelay on; 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 # this is necessary for us to be able to disable request buffering in all cases
proxy_http_version 1.1; proxy_http_version 1.1;
upstream registry { upstream registry {
server registry:5000; server registry:5000;
} }
@ -20,7 +20,15 @@ http {
upstream ui { upstream ui {
server ui:80; 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 { server {
listen 443 ssl; listen 443 ssl;

View 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;
}
}

View File

@ -0,0 +1,4 @@
upstream notary-server {
server notary-server:4443;
}

View File

@ -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.%"

View File

@ -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.%";

View 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-----

View 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-----

View 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-----

View 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"
}
}
}

View 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"
}
}

View File

@ -0,0 +1,2 @@
NOTARY_SIGNER_DEFAULTALIAS=$alias

View File

@ -20,10 +20,10 @@ http:
addr: localhost:5001 addr: localhost:5001
auth: auth:
token: token:
issuer: registry-token-issuer issuer: harbor-token-issuer
realm: $ui_url/service/token realm: $ui_url/service/token
rootcertbundle: /etc/registry/root.crt rootcertbundle: /etc/registry/root.crt
service: token-service service: harbor-registry
notifications: notifications:
endpoints: endpoints:

View File

@ -1,18 +1,6 @@
appname = registry appname = Harbor
runmode = dev runmode = dev
enablegzip = true
[lang]
types = en-US|zh-CN
names = en-US|zh-CN
[dev] [dev]
httpport = 80 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

View File

@ -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 LOG_LEVEL=debug
CONFIG_PATH=/etc/ui/app.conf
UI_SECRET=$ui_secret
JOBSERVICE_SECRET=$jobservice_secret
GODEBUG=netdns=cgo 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

View 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"]

View File

@ -3,18 +3,24 @@ services:
log: log:
build: build:
context: ../../ context: ../../
dockerfile: make/ubuntu/log/Dockerfile dockerfile: make/photon/log/Dockerfile
container_name: harbor-log
restart: always restart: always
volumes: volumes:
- /var/log/harbor/:/var/log/docker/ - /var/log/harbor/:/var/log/docker/:z
ports: ports:
- 1514:514 - 127.0.0.1:1514:514
networks:
- harbor
registry: registry:
image: library/registry:2.5.0 image: vmware/registry:photon-2.6.0
container_name: registry
restart: always restart: always
volumes: volumes:
- /data/registry:/storage - /data/registry:/storage:z
- ../common/config/registry/:/etc/registry/ - ./common/config/registry/:/etc/registry/:z
networks:
- harbor
environment: environment:
- GODEBUG=netdns=cgo - GODEBUG=netdns=cgo
command: command:
@ -23,65 +29,105 @@ services:
- log - log
logging: logging:
driver: "syslog" driver: "syslog"
options: options:
syslog-address: "tcp://127.0.0.1:1514" syslog-address: "tcp://127.0.0.1:1514"
tag: "registry" tag: "registry"
mysql: mysql:
build: ../common/db/ build: ../common/db/
container_name: harbor-db
restart: always restart: always
volumes: volumes:
- /data/database:/var/lib/mysql - /data/database:/var/lib/mysql:z
networks:
- harbor
env_file: env_file:
- ../common/config/db/env - ../common/config/db/env
depends_on: depends_on:
- log - log
logging: logging:
driver: "syslog" driver: "syslog"
options: options:
syslog-address: "tcp://127.0.0.1:1514" syslog-address: "tcp://127.0.0.1:1514"
tag: "mysql" 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: ui:
build: build:
context: ../../ context: ../../
dockerfile: make/dev/ui/Dockerfile dockerfile: make/dev/ui/Dockerfile
container_name: harbor-ui
env_file: env_file:
- ../common/config/ui/env - ../common/config/ui/env
restart: always restart: always
volumes: volumes:
- ../common/config/ui/app.conf:/etc/ui/app.conf - ./common/config/ui/app.conf:/etc/ui/app.conf:z
- ../common/config/ui/private_key.pem:/etc/ui/private_key.pem - ./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: depends_on:
- log - log
- adminserver
- registry
logging: logging:
driver: "syslog" driver: "syslog"
options: options:
syslog-address: "tcp://127.0.0.1:1514" syslog-address: "tcp://127.0.0.1:1514"
tag: "ui" tag: "ui"
jobservice: jobservice:
build: build:
context: ../../ context: ../../
dockerfile: make/dev/jobservice/Dockerfile dockerfile: make/dev/jobservice/Dockerfile
container_name: harbor-jobservice
env_file: env_file:
- ../common/config/jobservice/env - ../common/config/jobservice/env
restart: always restart: always
volumes: volumes:
- /data/job_logs:/var/log/jobs - /data/job_logs:/var/log/jobs:z
- ../common/config/jobservice/app.conf:/etc/jobservice/app.conf - ./common/config/jobservice/app.conf:/etc/jobservice/app.conf:z
- /data/secretkey:/etc/jobservice/key:z
networks:
- harbor
depends_on: depends_on:
- ui - ui
- adminserver
logging: logging:
driver: "syslog" driver: "syslog"
options: options:
syslog-address: "tcp://127.0.0.1:1514" syslog-address: "tcp://127.0.0.1:1514"
tag: "jobservice" tag: "jobservice"
proxy: proxy:
image: library/nginx:1.11.5 image: vmware/nginx:1.11.5-patched
container_name: nginx
restart: always restart: always
volumes: volumes:
- ../common/config/nginx:/etc/nginx - ./common/config/nginx:/etc/nginx:z
networks:
- harbor
ports: ports:
- 80:80 - 80:80
- 443:443 - 443:443
- 4443:4443
depends_on: depends_on:
- mysql - mysql
- registry - registry
@ -89,6 +135,9 @@ services:
- log - log
logging: logging:
driver: "syslog" driver: "syslog"
options: options:
syslog-address: "tcp://127.0.0.1:1514" syslog-address: "tcp://127.0.0.1:1514"
tag: "proxy" tag: "proxy"
networks:
harbor:
external: false

View File

@ -1,11 +1,7 @@
FROM golang:1.6.2 FROM golang:1.7.3
MAINTAINER jiangd@vmware.com 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 COPY . /go/src/github.com/vmware/harbor
WORKDIR /go/src/github.com/vmware/harbor/src/jobservice WORKDIR /go/src/github.com/vmware/harbor/src/jobservice

View 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"]

View 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
}
}
}

View 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/

View 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>

View File

@ -1,31 +1,20 @@
FROM golang:1.6.2 FROM golang:1.7.3
MAINTAINER jiangd@vmware.com 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 COPY src/. /go/src/github.com/vmware/harbor/src
WORKDIR /go/src/github.com/vmware/harbor/src/ui WORKDIR /go/src/github.com/vmware/harbor/src/ui
RUN go build -v -a -o /go/bin/harbor_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/views /go/bin/views
COPY src/ui/static /go/bin/static COPY src/ui/static /go/bin/static
COPY src/favicon.ico /go/bin/favicon.ico COPY src/favicon.ico /go/bin/favicon.ico
COPY make/jsminify.sh /tmp/jsminify.sh
RUN chmod u+x /go/bin/harbor_ui \ RUN mkdir /go/bin/harbor/
&& sed -i 's/TLS_CACERT/#TLS_CAERT/g' /etc/ldap/ldap.conf \ COPY VERSION /go/bin/harbor/VERSION
&& sed -i '$a\TLS_REQCERT allow' /etc/ldap/ldap.conf \
&& timestamp=`date '+%s'` \ RUN chmod u+x /go/bin/harbor_ui
&& /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
WORKDIR /go/bin/ WORKDIR /go/bin/
ENTRYPOINT ["/go/bin/harbor_ui"] ENTRYPOINT ["/go/bin/harbor_ui"]

View 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

View File

@ -1,20 +1,24 @@
version: '2' version: '2'
services: services:
log: log:
image: vmware/harbor-log image: vmware/harbor-log:__version__
container_name: harbor-log container_name: harbor-log
restart: always restart: always
volumes: volumes:
- /var/log/harbor/:/var/log/docker/ - /var/log/harbor/:/var/log/docker/:z
ports: ports:
- 1514:514 - 127.0.0.1:1514:514
networks:
- harbor
registry: registry:
image: library/registry:2.5.0 image: vmware/registry:photon-2.6.0
container_name: registry container_name: registry
restart: always restart: always
volumes: volumes:
- /data/registry:/storage - /data/registry:/storage:z
- ./common/config/registry/:/etc/registry/ - ./common/config/registry/:/etc/registry/:z
networks:
- harbor
environment: environment:
- GODEBUG=netdns=cgo - GODEBUG=netdns=cgo
command: command:
@ -27,11 +31,13 @@ services:
syslog-address: "tcp://127.0.0.1:1514" syslog-address: "tcp://127.0.0.1:1514"
tag: "registry" tag: "registry"
mysql: mysql:
image: vmware/harbor-db image: vmware/harbor-db:__version__
container_name: harbor-db container_name: harbor-db
restart: always restart: always
volumes: volumes:
- /data/database:/var/lib/mysql - /data/database:/var/lib/mysql:z
networks:
- harbor
env_file: env_file:
- ./common/config/db/env - ./common/config/db/env
depends_on: depends_on:
@ -41,48 +47,79 @@ services:
options: options:
syslog-address: "tcp://127.0.0.1:1514" syslog-address: "tcp://127.0.0.1:1514"
tag: "mysql" tag: "mysql"
ui: adminserver:
image: vmware/harbor-ui image: vmware/harbor-adminserver:__version__
container_name: harbor-ui container_name: harbor-adminserver
env_file: env_file:
- ./common/config/ui/env - ./common/config/adminserver/env
restart: always restart: always
volumes: volumes:
- ./common/config/ui/app.conf:/etc/ui/app.conf - /data/config/:/etc/adminserver/config/:z
- ./common/config/ui/private_key.pem:/etc/ui/private_key.pem - /data/secretkey:/etc/adminserver/key:z
- /data:/harbor_storage - /data/:/data/:z
networks:
- harbor
depends_on: depends_on:
- log - 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: logging:
driver: "syslog" driver: "syslog"
options: options:
syslog-address: "tcp://127.0.0.1:1514" syslog-address: "tcp://127.0.0.1:1514"
tag: "ui" tag: "ui"
jobservice: jobservice:
image: vmware/harbor-jobservice image: vmware/harbor-jobservice:__version__
container_name: harbor-jobservice container_name: harbor-jobservice
env_file: env_file:
- ./common/config/jobservice/env - ./common/config/jobservice/env
restart: always restart: always
volumes: volumes:
- /data/job_logs:/var/log/jobs - /data/job_logs:/var/log/jobs:z
- ./common/config/jobservice/app.conf:/etc/jobservice/app.conf - ./common/config/jobservice/app.conf:/etc/jobservice/app.conf:z
- /data/secretkey:/etc/jobservice/key:z
networks:
- harbor
depends_on: depends_on:
- ui - ui
- adminserver
logging: logging:
driver: "syslog" driver: "syslog"
options: options:
syslog-address: "tcp://127.0.0.1:1514" syslog-address: "tcp://127.0.0.1:1514"
tag: "jobservice" tag: "jobservice"
proxy: proxy:
image: nginx:1.11.5 image: vmware/nginx:1.11.5-patched
container_name: nginx container_name: nginx
restart: always restart: always
volumes: volumes:
- ./common/config/nginx:/etc/nginx - ./common/config/nginx:/etc/nginx:z
networks:
- harbor
ports: ports:
- 80:80 - 80:80
- 443:443 - 443:443
- 4443:4443
depends_on: depends_on:
- mysql - mysql
- registry - registry
@ -93,3 +130,7 @@ services:
options: options:
syslog-address: "tcp://127.0.0.1:1514" syslog-address: "tcp://127.0.0.1:1514"
tag: "proxy" tag: "proxy"
networks:
harbor:
external: false

View File

@ -8,6 +8,34 @@ hostname = reg.mydomain.com
#It can be set to https if ssl is enabled on nginx. #It can be set to https if ssl is enabled on nginx.
ui_url_protocol = http 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 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. #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 #the scope to search for users, 1-LDAP_SCOPE_BASE, 2-LDAP_SCOPE_ONELEVEL, 3-LDAP_SCOPE_SUBTREE
ldap_scope = 3 ldap_scope = 3
#The password for the root user of mysql db, change this before any production use. #Timeout (in seconds) when connecting to an LDAP Server. The default value (and most reasonable) is 5 seconds.
db_password = root123 ldap_timeout = 5
#Turn on or off the self-registration feature #Turn on or off the self-registration feature
self_registration = on 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 #The expiration time (in minute) of token created by token service, default is 30 minutes
token_expiration = 30 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. #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. #Set this flag to off when the remote registry uses a self-signed or untrusted certificate.
verify_remote_cert = on verify_remote_cert = on
#************************END INITIAL PROPERTIES************************
#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
############# #############

View File

@ -49,14 +49,20 @@ note() { printf "\n${underline}${bold}${blue}Note:${reset} ${blue}%s${reset}\n"
set -e set -e
set +o noglob 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 item=0
# notary is not enabled by default
with_notary=$false
while [ $# -gt 0 ]; do while [ $# -gt 0 ]; do
case $1 in case $1 in
--help) --help)
note "$usage" note "$usage"
exit 0;; exit 0;;
--with-notary)
with_notary=true;;
*) *)
note "$usage" note "$usage"
exit 1;; exit 1;;
@ -134,10 +140,10 @@ h2 "[Step $item]: checking installation environment ..."; let item+=1
check_docker check_docker
check_dockercompose check_dockercompose
if [ -f harbor*.tgz ] if [ -f harbor*.tar.gz ]
then then
h2 "[Step $item]: loading Harbor images ..."; let item+=1 h2 "[Step $item]: loading Harbor images ..."; let item+=1
docker load -i ./harbor*.tgz docker load -i ./harbor*.tar.gz
fi fi
echo "" echo ""
@ -146,19 +152,38 @@ if [ -n "$host" ]
then then
sed "s/^hostname = .*/hostname = $host/g" -i ./harbor.cfg sed "s/^hostname = .*/hostname = $host/g" -i ./harbor.cfg
fi fi
./prepare if [ $with_notary ]
then
./prepare --with-notary
else
./prepare
fi
echo "" echo ""
h2 "[Step $item]: checking existing instance of Harbor ..."; let item+=1 h2 "[Step $item]: checking existing instance of Harbor ..."; let item+=1
if [ -n "$(docker-compose -f docker-compose*.yml ps -q)" ] if [ $with_notary ]
then then
note "stopping existing Harbor instance ..." if [ -n "$(docker-compose -f docker-compose.yml -f docker-compose.notary.yml ps -q)" ]
docker-compose -f docker-compose*.yml down 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 fi
echo "" echo ""
h2 "[Step $item]: starting Harbor ..." 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 protocol=http
hostname=reg.mydomain.com hostname=reg.mydomain.com

View File

@ -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

View File

@ -3,7 +3,7 @@
# Targets: # Targets:
# #
# build: build harbor photon images # build: build harbor photon images
# clean: clean ui and jobservice harbor images # clean: clean adminserver, ui and jobservice harbor images
# common # common
SHELL := /bin/bash SHELL := /bin/bash
@ -22,6 +22,9 @@ DOCKERRMIMAGE=$(DOCKERCMD) rmi
DOCKERIMASES=$(DOCKERCMD) images DOCKERIMASES=$(DOCKERCMD) images
# binary # binary
ADMINSERVERSOURCECODE=$(SRCPATH)/adminserver
ADMINSERVERBINARYPATH=$(MAKEDEVPATH)/adminserver
ADMINSERVERBINARYNAME=harbor_adminserver
UISOURCECODE=$(SRCPATH)/ui UISOURCECODE=$(SRCPATH)/ui
UIBINARYPATH=$(MAKEDEVPATH)/ui UIBINARYPATH=$(MAKEDEVPATH)/ui
UIBINARYNAME=harbor_ui UIBINARYNAME=harbor_ui
@ -31,6 +34,9 @@ JOBSERVICEBINARYNAME=harbor_jobservice
# photon dockerfile # photon dockerfile
DOCKERFILEPATH=$(MAKEPATH)/photon DOCKERFILEPATH=$(MAKEPATH)/photon
DOCKERFILEPATH_ADMINSERVER=$(DOCKERFILEPATH)/adminserver
DOCKERFILENAME_ADMINSERVER=Dockerfile
DOCKERIMAGENAME_ADMINSERVER=vmware/harbor-adminserver
DOCKERFILEPATH_UI=$(DOCKERFILEPATH)/ui DOCKERFILEPATH_UI=$(DOCKERFILEPATH)/ui
DOCKERFILENAME_UI=Dockerfile DOCKERFILENAME_UI=Dockerfile
DOCKERIMAGENAME_UI=vmware/harbor-ui DOCKERIMAGENAME_UI=vmware/harbor-ui
@ -56,6 +62,10 @@ check_environment:
@$(MAKEPATH)/$(CHECKENVCMD) @$(MAKEPATH)/$(CHECKENVCMD)
build: 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..." @echo "building ui container for photon..."
$(DOCKERBUILD) -f $(DOCKERFILEPATH_UI)/$(DOCKERFILENAME_UI) -t $(DOCKERIMAGENAME_UI):$(VERSIONTAG) . $(DOCKERBUILD) -f $(DOCKERFILEPATH_UI)/$(DOCKERFILENAME_UI) -t $(DOCKERIMAGENAME_UI):$(VERSIONTAG) .
@echo "Done." @echo "Done."
@ -70,6 +80,7 @@ build:
cleanimage: cleanimage:
@echo "cleaning image for photon..." @echo "cleaning image for photon..."
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_ADMINSERVER):$(VERSIONTAG)
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_UI):$(VERSIONTAG) - $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_UI):$(VERSIONTAG)
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG) - $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_JOBSERVICE):$(VERSIONTAG)
- $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_LOG):$(VERSIONTAG) - $(DOCKERRMIMAGE) -f $(DOCKERIMAGENAME_LOG):$(VERSIONTAG)

View 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"]

View File

@ -1,20 +1,15 @@
FROM library/photon:1.0 FROM library/photon:1.0
RUN mkdir /harbor/ RUN mkdir /harbor/
RUN tdnf install -y sed apr-util-ldap
COPY ./make/dev/ui/harbor_ui /harbor/ COPY ./make/dev/ui/harbor_ui /harbor/
COPY ./src/ui/views /harbor/views COPY ./src/ui/views /harbor/views
COPY ./src/ui/static /harbor/static COPY ./src/ui/static /harbor/static
COPY ./src/favicon.ico /harbor/favicon.ico 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 \ 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
WORKDIR /harbor/ WORKDIR /harbor/
ENTRYPOINT ["/harbor/harbor_ui"] ENTRYPOINT ["/harbor/harbor_ui"]

View File

@ -19,8 +19,10 @@ if sys.version_info[:3][0] == 3:
import configparser as ConfigParser import configparser as ConfigParser
import io as StringIO import io as StringIO
def validate(conf): def validate(conf, args):
protocol = rcp.get("configuration", "ui_url_protocol") 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 protocol == "https":
if not rcp.has_option("configuration", "ssl_cert"): if not rcp.has_option("configuration", "ssl_cert"):
raise Exception("Error: The protocol is https but attribute ssl_cert is not set") 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) raise Exception("Error invalid value for project_creation_restriction: %s" % project_creation)
def get_secret_key(path): 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): if os.path.isfile(key_file):
with open(key_file, 'r') as f: with open(key_file, 'r') as f:
key = f.read() key = f.read()
print("loaded secret key") print("loaded secret from file: %s" % key_file)
if len(key) != 16:
raise Exception("secret key's length has to be 16 chars, current length: %d" % len(key))
return key return key
if not os.path.isdir(path): if not os.path.isdir(folder):
os.makedirs(path, mode=0600) os.makedirs(folder, mode=0600)
key = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(16)) key = ''.join(random.choice(string.ascii_letters+string.digits) for i in range(length))
with open(key_file, 'w') as f: with open(key_file, 'w') as f:
f.write(key) 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 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__) base_dir = os.path.dirname(__file__)
config_dir = os.path.join(base_dir, "common/config") config_dir = os.path.join(base_dir, "common/config")
templates_dir = os.path.join(base_dir, "common/templates") templates_dir = os.path.join(base_dir, "common/templates")
def delfile(src):
parser = argparse.ArgumentParser() if os.path.isfile(src):
parser.add_argument('-conf', dest='cfgfile', default=base_dir+'/harbor.cfg',type=str,help="the path of Harbor configuration file") try:
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.") 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() args = parser.parse_args()
delfile(config_dir)
#Read configurations #Read configurations
conf = StringIO.StringIO() conf = StringIO.StringIO()
conf.write("[configuration]\n") conf.write("[configuration]\n")
@ -72,16 +106,16 @@ conf.seek(0, os.SEEK_SET)
rcp = ConfigParser.RawConfigParser() rcp = ConfigParser.RawConfigParser()
rcp.readfp(conf) rcp.readfp(conf)
validate(rcp) validate(rcp, args)
hostname = rcp.get("configuration", "hostname") hostname = rcp.get("configuration", "hostname")
protocol = rcp.get("configuration", "ui_url_protocol") protocol = rcp.get("configuration", "ui_url_protocol")
ui_url = protocol + "://" + hostname ui_url = protocol + "://" + hostname
email_identity = rcp.get("configuration", "email_identity") email_identity = rcp.get("configuration", "email_identity")
email_server = rcp.get("configuration", "email_server") email_host = rcp.get("configuration", "email_server")
email_server_port = rcp.get("configuration", "email_server_port") email_port = rcp.get("configuration", "email_server_port")
email_username = rcp.get("configuration", "email_username") email_usr = rcp.get("configuration", "email_username")
email_password = rcp.get("configuration", "email_password") email_pwd = rcp.get("configuration", "email_password")
email_from = rcp.get("configuration", "email_from") email_from = rcp.get("configuration", "email_from")
email_ssl = rcp.get("configuration", "email_ssl") email_ssl = rcp.get("configuration", "email_ssl")
harbor_admin_password = rcp.get("configuration", "harbor_admin_password") harbor_admin_password = rcp.get("configuration", "harbor_admin_password")
@ -102,56 +136,40 @@ else:
ldap_filter = "" ldap_filter = ""
ldap_uid = rcp.get("configuration", "ldap_uid") ldap_uid = rcp.get("configuration", "ldap_uid")
ldap_scope = rcp.get("configuration", "ldap_scope") ldap_scope = rcp.get("configuration", "ldap_scope")
ldap_timeout = rcp.get("configuration", "ldap_timeout")
db_password = rcp.get("configuration", "db_password") db_password = rcp.get("configuration", "db_password")
self_registration = rcp.get("configuration", "self_registration") self_registration = rcp.get("configuration", "self_registration")
use_compressed_js = rcp.get("configuration", "use_compressed_js")
if protocol == "https": if protocol == "https":
cert_path = rcp.get("configuration", "ssl_cert") cert_path = rcp.get("configuration", "ssl_cert")
cert_key_path = rcp.get("configuration", "ssl_cert_key") cert_key_path = rcp.get("configuration", "ssl_cert_key")
customize_crt = rcp.get("configuration", "customize_crt") 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") max_job_workers = rcp.get("configuration", "max_job_workers")
token_expiration = rcp.get("configuration", "token_expiration") token_expiration = rcp.get("configuration", "token_expiration")
verify_remote_cert = rcp.get("configuration", "verify_remote_cert") verify_remote_cert = rcp.get("configuration", "verify_remote_cert")
proj_cre_restriction = rcp.get("configuration", "project_creation_restriction") proj_cre_restriction = rcp.get("configuration", "project_creation_restriction")
#secret_key = rcp.get("configuration", "secret_key") secretkey_path = rcp.get("configuration", "secretkey_path")
secret_key = get_secret_key(args.data_volume) 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)) 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") adminserver_config_dir = os.path.join(config_dir,"adminserver")
if not os.path.exists(ui_config_dir): if not os.path.exists(adminserver_config_dir):
os.makedirs(os.path.join(config_dir, "ui")) os.makedirs(os.path.join(config_dir, "adminserver"))
db_config_dir = os.path.join(config_dir, "db") ui_config_dir = prep_conf_dir(config_dir,"ui")
if not os.path.exists(db_config_dir): db_config_dir = prep_conf_dir(config_dir, "db")
os.makedirs(os.path.join(config_dir, "db")) job_config_dir = prep_conf_dir(config_dir, "jobservice")
registry_config_dir = prep_conf_dir(config_dir, "registry")
job_config_dir = os.path.join(config_dir, "jobservice") nginx_config_dir = prep_conf_dir (config_dir, "nginx")
if not os.path.exists(job_config_dir): nginx_conf_d = prep_conf_dir(nginx_config_dir, "conf.d")
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)
adminserver_conf_env = os.path.join(config_dir, "adminserver", "env")
ui_conf_env = os.path.join(config_dir, "ui", "env") ui_conf_env = os.path.join(config_dir, "ui", "env")
ui_conf = os.path.join(config_dir, "ui", "app.conf") ui_conf = os.path.join(config_dir, "ui", "app.conf")
jobservice_conf = os.path.join(config_dir, "jobservice", "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") job_conf_env = os.path.join(config_dir, "jobservice", "env")
nginx_conf = os.path.join(config_dir, "nginx", "nginx.conf") nginx_conf = os.path.join(config_dir, "nginx", "nginx.conf")
cert_dir = os.path.join(config_dir, "nginx", "cert") 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": if protocol == "https":
target_cert_path = os.path.join(cert_dir, os.path.basename(cert_path)) target_cert_path = os.path.join(cert_dir, os.path.basename(cert_path))
@ -187,14 +193,12 @@ if protocol == "https":
else: else:
render(os.path.join(templates_dir, "nginx", "nginx.http.conf"), render(os.path.join(templates_dir, "nginx", "nginx.http.conf"),
nginx_conf) nginx_conf)
render(os.path.join(templates_dir, "ui", "env"), render(os.path.join(templates_dir, "adminserver", "env"),
ui_conf_env, adminserver_conf_env,
hostname=hostname,
db_password=db_password,
ui_url=ui_url, ui_url=ui_url,
auth_mode=auth_mode, auth_mode=auth_mode,
harbor_admin_password=harbor_admin_password, self_registration=self_registration,
ldap_url=ldap_url, ldap_url=ldap_url,
ldap_searchdn =ldap_searchdn, ldap_searchdn =ldap_searchdn,
ldap_search_pwd =ldap_search_pwd, ldap_search_pwd =ldap_search_pwd,
@ -202,26 +206,33 @@ render(os.path.join(templates_dir, "ui", "env"),
ldap_filter=ldap_filter, ldap_filter=ldap_filter,
ldap_uid=ldap_uid, ldap_uid=ldap_uid,
ldap_scope=ldap_scope, ldap_scope=ldap_scope,
self_registration=self_registration, ldap_timeout=ldap_timeout,
use_compressed_js=use_compressed_js, db_password=db_password,
ui_secret=ui_secret, email_host=email_host,
secret_key=secret_key, email_port=email_port,
verify_remote_cert=verify_remote_cert, email_usr=email_usr,
project_creation_restriction=proj_cre_restriction, email_pwd=email_pwd,
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,
email_ssl=email_ssl, 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, registry_conf,
ui_url=ui_url) ui_url=ui_url)
@ -231,16 +242,16 @@ render(os.path.join(templates_dir, "db", "env"),
render(os.path.join(templates_dir, "jobservice", "env"), render(os.path.join(templates_dir, "jobservice", "env"),
job_conf_env, job_conf_env,
db_password=db_password,
ui_secret=ui_secret, ui_secret=ui_secret,
max_job_workers=max_job_workers, jobservice_secret=jobservice_secret)
secret_key=secret_key,
ui_url=ui_url,
verify_remote_cert=verify_remote_cert)
print("Generated configuration file: %s" % jobservice_conf) print("Generated configuration file: %s" % jobservice_conf)
shutil.copyfile(os.path.join(templates_dir, "jobservice", "app.conf"), 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): def validate_crt_subj(dirty_subj):
subj_list = [item for item in dirty_subj.strip().split("/") \ subj_list = [item for item in dirty_subj.strip().split("/") \
if len(item.split("=")) == 2 and len(item.split("=")[1]) > 0] if len(item.split("=")) == 2 and len(item.split("=")[1]) > 0]
@ -251,51 +262,112 @@ FNULL = open(os.devnull, 'w')
from functools import wraps from functools import wraps
def stat_decorator(func): def stat_decorator(func):
@wraps(func) @wraps(func)
def check_wrapper(*args, **kwargs): def check_wrapper(*args, **kw):
stat = func(*args, **kwargs) stat = func(*args, **kw)
message = "Generated configuration file: %s" % kwargs['path'] \ message = "Generated certificate, key file: %s, cert file: %s" % (kw['key_path'], kw['cert_path']) \
if stat == 0 else "Fail to generate %s" % kwargs['path'] if stat == 0 else "Fail to generate key file: %s, cert file: %s" % (kw['key_path'], kw['cert_path'])
print(message) print(message)
if stat != 0: if stat != 0:
sys.exit(1) sys.exit(1)
return check_wrapper return check_wrapper
@stat_decorator @stat_decorator
def check_private_key_stat(*args, **kwargs): def create_root_cert(subj, key_path="./k.key", cert_path="./cert.crt"):
return subprocess.call(["openssl", "genrsa", "-out", kwargs['path'], "4096"],\ rc = subprocess.call(["openssl", "genrsa", "-out", key_path, "4096"], stdout=FNULL, stderr=subprocess.STDOUT)
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 @stat_decorator
def check_certificate_stat(*args, **kwargs): def create_cert(subj, ca_key, ca_cert, key_path="./k.key", cert_path="./cert.crt"):
dirty_subj = "/C={0}/ST={1}/L={2}/O={3}/OU={4}/CN={5}/emailAddress={6}"\ cert_dir = os.path.dirname(cert_path)
.format(crt_country, crt_state, crt_location, crt_organization,\ csr_path = os.path.join(cert_dir, "tmp.csr")
crt_organizationalunit, crt_commonname, crt_email) rc = subprocess.call(["openssl", "req", "-newkey", "rsa:4096", "-nodes","-sha256","-keyout", key_path,\
subj = validate_crt_subj(dirty_subj) "-out", csr_path, "-subj", subj], stdout=FNULL, stderr=subprocess.STDOUT)
return subprocess.call(["openssl", "req", "-new", "-x509", "-key",\ if rc != 0:
private_key_pem, "-out", root_crt, "-days", "3650", "-subj", subj], \ return rc
stdout=FNULL, stderr=subprocess.STDOUT) 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): def openssl_installed():
if stat == 0: shell_stat = subprocess.check_call(["which", "openssl"], stdout=FNULL, stderr=subprocess.STDOUT)
return True if shell_stat != 0:
else:
print("Cannot find openssl installed in this computer\nUse default SSL certificate file") print("Cannot find openssl installed in this computer\nUse default SSL certificate file")
return False 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) shell_stat = subprocess.check_call(["which", "openssl"], stdout=FNULL, stderr=subprocess.STDOUT)
if openssl_is_installed(shell_stat): empty_subj = "/C=/ST=/L=/O=/CN=/"
private_key_pem = os.path.join(config_dir, "ui", "private_key.pem") private_key_pem = os.path.join(config_dir, "ui", "private_key.pem")
root_crt = os.path.join(config_dir, "registry", "root.crt") root_crt = os.path.join(config_dir, "registry", "root.crt")
create_root_cert(empty_subj, key_path=private_key_pem, cert_path=root_crt)
check_private_key_stat(path=private_key_pem) os.chmod(private_key_pem, 0600)
check_certificate_stat(path=root_crt) os.chmod(root_crt, 0600)
else: 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")) 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")) 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() FNULL.close()
print("The configuration files are ready, please use docker-compose to start the service.") print("The configuration files are ready, please use docker-compose to start the service.")

View File

@ -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

View File

@ -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"]

View File

@ -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

View File

@ -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

View 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
}

View 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)
}
}

View 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
}
}

View 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
}

View 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
}
}

View 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)
}
}
}

View 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
}

View 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")
}
}

View 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
}

View 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")
}

View 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
}

View 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)
}

View 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
}

View 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")
}
}

View 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
View 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)
}
}

Some files were not shown because too many files have changed in this diff Show More