Merge branch 'dev' into dev

This commit is contained in:
yhua123 2016-12-12 15:11:00 +08:00 committed by GitHub
commit 0d09379fb7
35 changed files with 874 additions and 697 deletions

View File

@ -73,7 +73,7 @@ before_script:
- sudo sqlite3 /registry.db < make/common/db/registry_sqlite.sql
script:
- sudo service mysql-5.6 stop
- sudo service mysql stop
- sudo ./tests/testprepare.sh
- docker-compose -f ./make/docker-compose.test.yml up -d
- go list ./... | grep -v -E 'vendor|tests' | xargs -L1 fgt golint

View File

@ -23,7 +23,7 @@ Guide to deploy Harbor on Kubenetes. (maintained by community)
### Developer documents
[Arthitecture Overview of Harbor](https://github.com/vmware/harbor/wiki/Architecture-Overview-of-Harbor)
[Architecture Overview of Harbor](https://github.com/vmware/harbor/wiki/Architecture-Overview-of-Harbor)
Developers read this first.
[Harbor API Specs by Swagger](configure_swagger.md)
@ -61,7 +61,7 @@ How to add your local language to Harbor.
[Overall Architecture of Harbor Registry](http://www.compare-review-information.com/overall-architecture-of-harbor-registry/)
[makeing 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/)
[Docker Private Registry Using Harbor](https://blog.imaginea.com/docker-private-registry-using-harbor-2/)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 46 KiB

BIN
docs/img/rbac.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

View File

@ -1,282 +1,273 @@
# Installation and Configuration Guide
Harbor can be installed by one of three approaches:
- **Online installer:** The installer downloads Harbor's images from Docker hub. For this reason, the installer is very small in size.
- **Offline installer:** Use this installer when the host does not have an Internet connection. The installer contains pre-built images so its size is larger.
- **Virtual Appliance:** If you are installing Harbor as the registry component of vSphere Integrated Containers (VIC), or using Harbor as a standalone registry on vSphere platform, download the OVA version of Harbor.
All installers can be downloaded from the **[official release](https://github.com/vmware/harbor/releases)** page.
To install Harbor's virtual appliance, refer to the **[Harbor Installation Guide for Virtual Appliance](installation_guide_ova.md)**.
This guide describes the steps to install and configure Harbor by using the online or offline installer. The installation processes are almost the same.
If you run a previous version of Harbor, you may need to migrate the data to fit the new database schema. For more details, please refer to **[Data Migration Guide](migration_guide.md)**.
In addition, the deployment instructions on Kubernetes has been created by the community. Refer to set up [Harbor on Kubernetes](kubernetes_deployment.md) for details.
## 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.
* Python should be version 2.7 or higher. Note that you may have to install Python on Linux distributions (Gentoo, Arch) that do not come with a Python interpreter installed by default
* Docker engine should be version 1.10 or higher. For installation instructions, please refer to: https://docs.docker.com/engine/installation/
* Docker Compose needs to be version 1.6.0 or higher. For installation instructions, please refer to: https://docs.docker.com/compose/install/
## Installation Steps
The installation steps boil down to the following
1. Download the installer;
2. Configure **harbor.cfg**;
3. Run **install.sh** to install and start Harbor;
#### Downloading the installer:
The binary of the installer can be downloaded from the [release](https://github.com/vmware/harbor/releases) page. Choose either online or offline installer. Use *tar* command to extract the package.
Online installer:
```
$ tar xvf harbor-online-installer-<version>.tgz
```
Offline installer:
```
$ tar xvf harbor-offline-installer-<version>.tgz
```
#### Configuring Harbor
Configuration parameters are located in the file **harbor.cfg**.
The parameters are described below - note that at the very least, you will need to change the **hostname** attribute.
* **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)**.
* **Email settings**: These parameters are needed for Harbor to be able to send a user a "password reset" email, and are only necessary if that functionality is needed. Also, do note that by default SSL connectivity is _not_ enabled - if your SMTP server requires SSL, but does _not_ support STARTTLS, then you should enable SSL by setting **email_ssl = true**.
* email_server = smtp.mydomain.com
* email_server_port = 25
* email_username = sample_admin@mydomain.com
* email_password = abc
* email_from = admin <sample_admin@mydomain.com>
* email_ssl = false
* **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**.
* **ldap_url**: The LDAP endpoint URL (e.g. `ldaps://ldap.mydomain.com`). _Only used when **auth_mode** is set to *ldap_auth* ._
* **ldap_searchdn**: The DN of a user who has the permission to search an LDAP/AD server (e.g. `uid=admin,ou=people,dc=mydomain,dc=com`).
* **ldap_search_pwd**: The password of the user specified by *ldap_searchdn*.
* **ldap_basedn**: The base DN to look up a user, e.g. `ou=people,dc=mydomain,dc=com`. _Only used when **auth_mode** is set to *ldap_auth* ._
* **ldap_filter**:The search filter for looking up a user, e.g. `(objectClass=person)`.
* **ldap_uid**: The attribute used to match a user during a LDAP search, it could be uid, cn, email or other attributes.
* **ldap_scope**: The scope to search for a user, 1-LDAP_SCOPE_BASE, 2-LDAP_SCOPE_ONELEVEL, 3-LDAP_SCOPE_SUBTREE. Default is 3.
* **db_password**: The root password for the MySQL database used for **db_auth**. _Change this password for any production use!_
* **self_registration**: (**on** or **off**. Default is **on**) Enable / Disable the ability for a user to register themselves. When disabled, new users can only be created by the Admin user, only an admin user can create new users in Harbor. _NOTE: When **auth_mode** is set to **ldap_auth**, self-registration feature is **always** disabled, and this flag is ignored._
* **use_compressed_js**: (**on** or **off**. Default is **on**) For production use, turn this flag to **on**. In development mode, set it to **off** so that js files can be modified separately.
* **max_job_workers**: (default value is **3**) The maximum number of replication workers in job service. For each image replication job, a worker synchronizes all tags of a repository to the remote destination. Increasing this number allows more concurrent replication jobs in the system. However, since each worker consumes a certain amount of network/CPU/IO resources, please carefully pick the value of this attribute based on the hardware resource of the host.
* **secretkey_path**: The path of key for encrypt or decrypt the password of a remote registry in a replication policy.
* **token_expiration**: The expiration time (in minutes) of a token created by token service, default is 30 minutes.
* **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)
By default, Harbor stores images on your local filesystem. In a production environment, you may consider
using other storage backend instead of the local filesystem, like S3, Openstack Swift, Ceph, etc.
What you need to update is the section of `storage` in the file `templates/registry/config.yml`.
For example, if you use Openstack Swift as your storage backend, the section may look like this:
```
storage:
swift:
username: admin
password: ADMIN_PASS
authurl: http://keystone_addr:35357/v3/auth
tenant: admin
domain: default
region: regionOne
container: docker_images
```
_NOTE: For detailed information on storage backend of a registry, refer to [Registry Configuration Reference](https://docs.docker.com/registry/configuration/) ._
#### Finishing installation and starting Harbor
Once **harbord.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.
```sh
$ sudo ./install.sh
```
If everything worked properly, you should be able to open a browser to visit the admin portal at **http://reg.yourdomain.com** (change *reg.yourdomain.com* to the hostname configured in your harbor.cfg). Note that the default administrator username/password are admin/Harbor12345 .
Log in to the admin portal and create a new project, e.g. `myproject`. You can then use docker commands to login and push images (By default, the registry server listens on port 80):
```sh
$ docker login reg.yourdomain.com
$ 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.
For information on how to use Harbor, please refer to **[User Guide of Harbor](user_guide.md)** .
#### Configuring Harbor with HTTPS access
Harbor does not ship with any certificates, and, by default, uses HTTP to serve requests. While this makes it relatively simple to set up and run - especially for a development or testing environment - it is **not** recommended for a production environment. To enable HTTPS, please refer to **[Configuring Harbor with HTTPS Access](configure_https.md)**.
### Managing Harbor's lifecycle
You can use docker-compose to manage the lifecycle of Harbor. Some useful commands are listed as follows (must run in the same directory as *docker-compose.yml*).
Stopping Harbor:
```
$ sudo docker-compose stop
# Installation and Configuration Guide
Harbor can be installed by one of three approaches:
- **Online installer:** The installer downloads Harbor's images from Docker hub. For this reason, the installer is very small in size.
- **Offline installer:** Use this installer when the host does not have an Internet connection. The installer contains pre-built images so its size is larger.
- **Virtual Appliance:** If you are installing Harbor as the registry component of vSphere Integrated Containers (VIC), or using Harbor as a standalone registry on vSphere platform, download the OVA version of Harbor.
All installers can be downloaded from the **[official release](https://github.com/vmware/harbor/releases)** page.
To install Harbor's virtual appliance, refer to the **[Harbor Installation Guide for Virtual Appliance](installation_guide_ova.md)**.
This guide describes the steps to install and configure Harbor by using the online or offline installer. The installation processes are almost the same.
If you run a previous version of Harbor, you may need to migrate the data to fit the new database schema. For more details, please refer to **[Data Migration Guide](migration_guide.md)**.
In addition, the deployment instructions on Kubernetes has been created by the community. Refer to set up [Harbor on Kubernetes](kubernetes_deployment.md) for details.
## 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.
* Python should be version 2.7 or higher. Note that you may have to install Python on Linux distributions (Gentoo, Arch) that do not come with a Python interpreter installed by default
* Docker engine should be version 1.10 or higher. For installation instructions, please refer to: https://docs.docker.com/engine/installation/
* Docker Compose needs to be version 1.6.0 or higher. For installation instructions, please refer to: https://docs.docker.com/compose/install/
## Installation Steps
The installation steps boil down to the following
1. Download the installer;
2. Configure **harbor.cfg**;
3. Run **install.sh** to install and start Harbor;
#### Downloading the installer:
The binary of the installer can be downloaded from the [release](https://github.com/vmware/harbor/releases) page. Choose either online or offline installer. Use *tar* command to extract the package.
Online installer:
```
$ tar xvf harbor-online-installer-<version>.tgz
```
Offline installer:
```
$ tar xvf harbor-offline-installer-<version>.tgz
```
#### Configuring Harbor
Configuration parameters are located in the file **harbor.cfg**.
The parameters are described below - note that at the very least, you will need to change the **hostname** attribute.
* **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)**.
* **Email settings**: These parameters are needed for Harbor to be able to send a user a "password reset" email, and are only necessary if that functionality is needed. Also, do note that by default SSL connectivity is _not_ enabled - if your SMTP server requires SSL, but does _not_ support STARTTLS, then you should enable SSL by setting **email_ssl = true**.
* email_server = smtp.mydomain.com
* email_server_port = 25
* email_username = sample_admin@mydomain.com
* email_password = abc
* email_from = admin <sample_admin@mydomain.com>
* email_ssl = false
* **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**.
* **ldap_url**: The LDAP endpoint URL (e.g. `ldaps://ldap.mydomain.com`). _Only used when **auth_mode** is set to *ldap_auth* ._
* **ldap_searchdn**: The DN of a user who has the permission to search an LDAP/AD server (e.g. `uid=admin,ou=people,dc=mydomain,dc=com`).
* **ldap_search_pwd**: The password of the user specified by *ldap_searchdn*.
* **ldap_basedn**: The base DN to look up a user, e.g. `ou=people,dc=mydomain,dc=com`. _Only used when **auth_mode** is set to *ldap_auth* ._
* **ldap_filter**:The search filter for looking up a user, e.g. `(objectClass=person)`.
* **ldap_uid**: The attribute used to match a user during a LDAP search, it could be uid, cn, email or other attributes.
* **ldap_scope**: The scope to search for a user, 1-LDAP_SCOPE_BASE, 2-LDAP_SCOPE_ONELEVEL, 3-LDAP_SCOPE_SUBTREE. Default is 3.
* **db_password**: The root password for the MySQL database used for **db_auth**. _Change this password for any production use!_
* **self_registration**: (**on** or **off**. Default is **on**) Enable / Disable the ability for a user to register themselves. When disabled, new users can only be created by the Admin user, only an admin user can create new users in Harbor. _NOTE: When **auth_mode** is set to **ldap_auth**, self-registration feature is **always** disabled, and this flag is ignored._
* **use_compressed_js**: (**on** or **off**. Default is **on**) For production use, turn this flag to **on**. In development mode, set it to **off** so that js files can be modified separately.
* **max_job_workers**: (default value is **3**) The maximum number of replication workers in job service. For each image replication job, a worker synchronizes all tags of a repository to the remote destination. Increasing this number allows more concurrent replication jobs in the system. However, since each worker consumes a certain amount of network/CPU/IO resources, please carefully pick the value of this attribute based on the hardware resource of the host.
* **secretkey_path**: The path of key for encrypt or decrypt the password of a remote registry in a replication policy.
* **token_expiration**: The expiration time (in minutes) of a token created by token service, default is 30 minutes.
* **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)
By default, Harbor stores images on your local filesystem. In a production environment, you may consider
using other storage backend instead of the local filesystem, like S3, Openstack Swift, Ceph, etc.
What you need to update is the section of `storage` in the file `common/templates/registry/config.yml`.
For example, if you use Openstack Swift as your storage backend, the section may look like this:
```
storage:
swift:
username: admin
password: ADMIN_PASS
authurl: http://keystone_addr:35357/v3/auth
tenant: admin
domain: default
region: regionOne
container: docker_images
```
_NOTE: For detailed information on storage backend of a registry, refer to [Registry Configuration Reference](https://docs.docker.com/registry/configuration/) ._
#### 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.
```sh
$ sudo ./install.sh
```
If everything worked properly, you should be able to open a browser to visit the admin portal at **http://reg.yourdomain.com** (change *reg.yourdomain.com* to the hostname configured in your harbor.cfg). Note that the default administrator username/password are admin/Harbor12345 .
Log in to the admin portal and create a new project, e.g. `myproject`. You can then use docker commands to login and push images (By default, the registry server listens on port 80):
```sh
$ docker login reg.yourdomain.com
$ 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.
For information on how to use Harbor, please refer to **[User Guide of Harbor](user_guide.md)** .
#### Configuring Harbor with HTTPS access
Harbor does not ship with any certificates, and, by default, uses HTTP to serve requests. While this makes it relatively simple to set up and run - especially for a development or testing environment - it is **not** recommended for a production environment. To enable HTTPS, please refer to **[Configuring Harbor with HTTPS Access](configure_https.md)**.
### Managing Harbor's lifecycle
You can use docker-compose to manage the lifecycle of Harbor. Some useful commands are listed as follows (must run in the same directory as *docker-compose.yml*).
Stopping Harbor:
```
$ sudo docker-compose stop
Stopping nginx ... done
Stopping harbor-jobservice ... done
Stopping harbor-ui ... done
Stopping harbor-db ... done
Stopping registry ... done
Stopping harbor-log ... done
```
Restarting Harbor after stopping:
```
$ sudo docker-compose start
Stopping harbor-log ... done
```
Restarting Harbor after stopping:
```
$ sudo docker-compose start
Starting log ... done
Starting ui ... done
Starting mysql ... done
Starting jobservice ... done
Starting registry ... done
Starting proxy ... done
```
To change Harbor's configuration, first stop existing Harbor instance, update harbor.cfg, and then run install.sh again:
```
$ sudo docker-compose down
$ vim harbor.cfg
$ sudo install.sh
```
Removing Harbor's containers while keeping the image data and Harbor's database files on the file system:
```
$ sudo docker-compose rm
Going to remove nginx, harbor-jobservice, registry, harbor-ui, harbor-db, harbor-log
Are you sure? [yN] y
Removing nginx ... done
Removing harbor-jobservice ... done
Removing registry ... done
Removing harbor-ui ... done
Removing harbor-db ... done
Removing harbor-log ... done
```
Removing Harbor's database and image data (for a clean re-installation):
```sh
$ rm -r /data/database
$ rm -r /data/registry
```
Please check the [Docker Compose command-line reference](https://docs.docker.com/compose/reference/) for more on docker-compose.
### Persistent data and log files
By default, registry data is persisted in the target host's `/data/` directory. This data remains unchanged even when Harbor's containers are removed and/or recreated.
In addition, Harbor uses *rsyslog* to collect the logs of each container. By default, these log files are stored in the directory `/var/log/harbor/` on the target host for troubleshooting.
## Configuring Harbor listening on a customized port
By default, Harbor listens on port 80(HTTP) and 443(HTTPS, if configured) for both admin portal and docker commands, you can configure it with a customized one.
### For HTTP protocol
1.Modify docker-compose.yml
Replace the first "80" to a customized port, e.g. 8888:80.
```
proxy:
image: library/nginx:1.11.5
restart: always
volumes:
- ./config/nginx:/etc/nginx
ports:
- 8888:80
- 443:443
depends_on:
- mysql
- registry
- ui
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "proxy"
```
2.Modify templates/registry/config.yml
Add the customized port, e.g. ":8888", after "$ui_url".
```
auth:
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.
```sh
$ sudo docker-compose down
$ sudo install.sh
```
### For HTTPS protocol
1.Enable HTTPS in Harbor by following this [guide](https://github.com/vmware/harbor/blob/master/docs/configure_https.md).
2.Modify docker-compose.yml
Replace the first "443" to a customized port, e.g. 4443:443.
```
proxy:
image: library/nginx:1.11.5
restart: always
volumes:
- ./config/nginx:/etc/nginx
ports:
- 80:80
- 4443:443
depends_on:
- mysql
- registry
- ui
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "proxy"
```
3.Modify templates/registry/config.yml
Add the customized port, e.g. ":4443", after "$ui_url".
```
auth:
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.
```sh
$ sudo docker-compose down
$ sudo install.sh
```
## Troubleshooting
1. When Harbor does not work properly, run the below commands to find out if all containers of Harbor are in **UP** status:
```
$ sudo docker-compose ps
Starting proxy ... done
```
To change Harbor's configuration, first stop existing Harbor instance, update harbor.cfg, and then run install.sh again:
```
$ sudo docker-compose down
$ vim harbor.cfg
$ sudo install.sh
```
Removing Harbor's containers while keeping the image data and Harbor's database files on the file system:
```
$ sudo docker-compose down
```
Removing Harbor's database and image data (for a clean re-installation):
```sh
$ rm -r /data/database
$ rm -r /data/registry
```
Please check the [Docker Compose command-line reference](https://docs.docker.com/compose/reference/) for more on docker-compose.
### Persistent data and log files
By default, registry data is persisted in the target host's `/data/` directory. This data remains unchanged even when Harbor's containers are removed and/or recreated.
In addition, Harbor uses *rsyslog* to collect the logs of each container. By default, these log files are stored in the directory `/var/log/harbor/` on the target host for troubleshooting.
## Configuring Harbor listening on a customized port
By default, Harbor listens on port 80(HTTP) and 443(HTTPS, if configured) for both admin portal and docker commands, you can configure it with a customized one.
### For HTTP protocol
1.Modify docker-compose.yml
Replace the first "80" to a customized port, e.g. 8888:80.
```
proxy:
image: library/nginx:1.11.5
restart: always
volumes:
- ./config/nginx:/etc/nginx
ports:
- 8888:80
- 443:443
depends_on:
- mysql
- registry
- ui
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "proxy"
```
2.Modify templates/registry/config.yml
Add the customized port, e.g. ":8888", after "$ui_url".
```
auth:
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.
```sh
$ sudo docker-compose down
$ sudo install.sh
```
### For HTTPS protocol
1.Enable HTTPS in Harbor by following this [guide](https://github.com/vmware/harbor/blob/master/docs/configure_https.md).
2.Modify docker-compose.yml
Replace the first "443" to a customized port, e.g. 4443:443.
```
proxy:
image: library/nginx:1.11.5
restart: always
volumes:
- ./config/nginx:/etc/nginx
ports:
- 80:80
- 4443:443
depends_on:
- mysql
- registry
- ui
- log
logging:
driver: "syslog"
options:
syslog-address: "tcp://127.0.0.1:1514"
tag: "proxy"
```
3.Modify templates/registry/config.yml
Add the customized port, e.g. ":4443", after "$ui_url".
```
auth:
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.
```sh
$ sudo docker-compose down
$ sudo install.sh
```
## Troubleshooting
1. When Harbor does not work properly, run the below commands to find out if all containers of Harbor are in **UP** status:
```
$ sudo docker-compose ps
Name Command State Ports
-----------------------------------------------------------------------------------------------------
harbor-db docker-entrypoint.sh mysqld Up 3306/tcp
@ -285,11 +276,17 @@ $ sudo install.sh
harbor-ui /harbor/harbor_ui Up
nginx nginx -g daemon off; Up 0.0.0.0:443->443/tcp, 0.0.0.0:80->80/tcp
registry /entrypoint.sh serve /etc/ ... Up 5000/tcp
```
If a container is not in **UP** state, check the log file of that container in directory ```/var/log/harbor```. For example, if the container ```harbor_ui_1``` is not running, you should look at the log file ```docker_ui.log```.
2.When setting up Harbor behind an nginx proxy or elastic load balancing, look for the line below, in `make/config/nginx/nginx.conf` and remove it from the sections if the proxy already has similar settings: `location /`, `location /v2/` and `location /service/`.
```
proxy_set_header X-Forwarded-Proto $scheme;
```
```
If a container is not in **UP** state, check the log file of that container in directory ```/var/log/harbor```. For example, if the container ```harbor-ui``` is not running, you should look at the log file ```ui.log```.
2.When setting up Harbor behind an nginx proxy or elastic load balancing, look for the line below, in `common/templates/nginx/nginx.http.conf` and remove it from the sections if the proxy already has similar settings: `location /`, `location /v2/` and `location /service/`.
```
proxy_set_header X-Forwarded-Proto $scheme;
```
And run the following commands to restart Harbor:
```sh
$ sudo docker-compose down
$ sudo ./prepare
$ sudo docker-compose up -d
```

View File

@ -1,6 +1,13 @@
# Installing and Configuring Harbor on vSphere as Virtual Appliance
This guide walks you through the steps about installing and configuring Harbor on vSphere as an virtual appliance. If you are installing Harbor on a Linux host, refer to this **[Installation Guide](installation_guide.md)**.
* [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.
@ -18,7 +25,7 @@ By default, Harbor stores user information in an internal database. Harbor can a
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.
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.
@ -68,10 +75,9 @@ For the purpose of generating a self-signed certificate, it is recommended that
* 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.
* **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.
* **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.
* **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
@ -79,8 +85,9 @@ For the purpose of generating a self-signed certificate, it is recommended that
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 Seach Password**.
* **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.
@ -103,7 +110,7 @@ For the purpose of generating a self-signed certificate, it is recommended that
* **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 enabled secure mail transmission.
* **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.
@ -119,16 +126,16 @@ For the purpose of generating a self-signed certificate, it is recommended that
![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 netowrk address and password.
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](user_guide.md).
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 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:
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.
@ -147,7 +154,7 @@ To download the certificate of Harbor's CA and import into a Docker client, foll
cp ca.crt /etc/docker/certs.d/<Harbor_IP>/
```
**Note:** If you run the above two sets of commands, Harbor can be accessed by both FQDN and IP address.
**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.
@ -165,10 +172,10 @@ If you want to change the properties of Harbor, follow the below steps:
![ova](img/ova/vapp_options.png)
4. **Power on** the VM.
4. **Power on** the VM and Harbor will reconfigure itself based on the new settings.
**Notes:**
1. The authentication mode can only be set once before the firtst boot. Subsequent modification of this option does not have any effect.
**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.

View File

@ -1309,7 +1309,45 @@ paths:
403:
description: User does not have permission of admin role.
500:
description: Unexpected internal errors.
description: Unexpected internal errors.
/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.
definitions:
Search:
type: object
@ -1741,3 +1779,22 @@ definitions:
comment:
type: string
description: The new comment.
Storage:
type: object
properties:
total:
type: integer
format: int64
description: Total volume size.
free:
type: integer
format: int64
description: Free volume size.
SystemInfo:
type: object
properties:
storage:
type: array
description: The storage of system.
items:
$ref: '#/definitions/Storage'

View File

@ -15,29 +15,48 @@ This guide walks you through the fundamentals of using Harbor. You'll learn how
##Role Based Access Control
RBAC (Role Based Access Control) is provided in Harbor and there are four roles with different privileges:
![rbac](img/rbac.png)
Harbor manages images through projects. Users can be added into one project as a member with three different 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
As a new user, you can sign up an account by going through the self-registration process. The username and email must be unique in the Harbor system. The password must contain at least 7 characters with 1 lowercase letter, 1 uppercase letter and 1 numeric character.
Harbor supports two authentication modes:
If the administrator has configured LDAP/AD as authentication source, no sign-up is required. The LDAP/AD user id can be used directly to log in to Harbor.
When you forgot your password, you can follow the below steps to reset the password:
* **Database(db_auth)**
1. Click the link "forgot password" in the sign in page.
2. Input the email used when you signed up, an email will be sent out to you.
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 "Submit".
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.
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 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. 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.
* **Private**: A private project can only be accessed by users with proper privileges.
@ -66,16 +85,21 @@ You can update or remove a member by clicking the icon on the right.
![browse project](img/new_remove_update_member.png)
##Replicating images
If you are a system administrator, you can replicate images to a remote registry, which is called destination in Harbor. Only Harbor instance is supported as a destination for now.
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.
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.
Click "Add New Policy" on the "Replication" tab, fill the necessary fields and click "OK", a policy for this project will be created. If "Enable" is chosen, the project will be replicated to the remote immediately, and 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.
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.
![browse project](img/new_create_policy.png)
You can enable or disable a policy in the policy list view, and only the policies which are disbled can be edited.
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.
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.
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.
![browse project](img/new_policy_list.png)
@ -104,7 +128,7 @@ You can list, edit, enable and disable policies in the "Replication" tab. Make s
**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 trys 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):
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
@ -155,7 +179,7 @@ $ docker push 10.117.169.182/demo/ubuntu:14.04
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 remains 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)

207
docs/user_guide_ova.md Normal file
View File

@ -0,0 +1,207 @@
#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

@ -70,6 +70,10 @@ http {
proxy_buffering off;
proxy_request_buffering off;
}
location /service/notifications {
return 404;
}
}
}

View File

@ -87,6 +87,10 @@ http {
proxy_buffering off;
proxy_request_buffering off;
}
location /service/notifications {
return 404;
}
}
server {

View File

@ -18,6 +18,8 @@ package auth
import (
"fmt"
"net/http"
"net/url"
"strings"
"time"
au "github.com/docker/distribution/registry/client/auth"
@ -37,6 +39,7 @@ type Authorizer interface {
// And it implements interface Modifier
type AuthorizerStore struct {
authorizers []Authorizer
ping *url.URL
challenges []au.Challenge
}
@ -49,15 +52,21 @@ func NewAuthorizerStore(endpoint string, insecure bool, authorizers ...Authorize
Timeout: 30 * time.Second,
}
resp, err := client.Get(buildPingURL(endpoint))
pingURL := buildPingURL(endpoint)
resp, err := client.Get(pingURL)
if err != nil {
return nil, err
}
defer resp.Body.Close()
challenges := ParseChallengeFromResponse(resp)
ping, err := url.Parse(pingURL)
if err != nil {
return nil, err
}
return &AuthorizerStore{
authorizers: authorizers,
ping: ping,
challenges: challenges,
}, nil
}
@ -68,6 +77,23 @@ func buildPingURL(endpoint string) string {
// Modify adds authorization to the request
func (a *AuthorizerStore) Modify(req *http.Request) error {
//only handle the requests sent to registry
v2Index := strings.Index(req.URL.Path, "/v2/")
if v2Index == -1 {
return nil
}
ping := url.URL{
Host: req.URL.Host,
Scheme: req.URL.Scheme,
Path: req.URL.Path[:v2Index+4],
}
if ping.Host != a.ping.Host || ping.Scheme != a.ping.Scheme ||
ping.Path != a.ping.Path {
return nil
}
for _, challenge := range a.challenges {
for _, authorizer := range a.authorizers {
if authorizer.Scheme() == challenge.Scheme {

View File

@ -17,6 +17,7 @@ package auth
import (
"net/http"
"net/url"
"strings"
"testing"
@ -64,12 +65,17 @@ func TestModify(t *testing.T) {
Scheme: "bearer",
}
ping, err := url.Parse("http://example.com/v2/")
if err != nil {
t.Fatalf("failed to parse URL: %v", err)
}
as := &AuthorizerStore{
authorizers: []Authorizer{authorizer},
ping: ping,
challenges: []auth.Challenge{challenge},
}
req, err := http.NewRequest("GET", "http://example.com", nil)
req, err := http.NewRequest("GET", "http://example.com/v2/ubuntu/manifests/14.04", nil)
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
@ -86,4 +92,18 @@ func TestModify(t *testing.T) {
if !strings.HasPrefix(header, "Bearer") {
t.Fatal("\"Authorization\" header does not start with \"Bearer\"")
}
req, err = http.NewRequest("GET", "http://example.com", nil)
if err != nil {
t.Fatalf("failed to create request: %v", err)
}
if err = as.Modify(req); err != nil {
t.Fatalf("failed to modify request: %v", err)
}
header = req.Header.Get("Authorization")
if len(header) != 0 {
t.Fatal("\"Authorization\" header should not be added")
}
}

View File

@ -164,15 +164,15 @@ func (ra *RepositoryAPI) Delete() {
}
for _, t := range tags {
if err := rc.DeleteTag(t); err != nil {
if err = rc.DeleteTag(t); err != nil {
if regErr, ok := err.(*registry_error.Error); ok {
if regErr.StatusCode != http.StatusNotFound {
ra.CustomAbort(regErr.StatusCode, regErr.Detail)
if regErr.StatusCode == http.StatusNotFound {
continue
}
} else {
log.Errorf("error occurred while deleting tag %s:%s: %v", repoName, t, err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
ra.CustomAbort(regErr.StatusCode, regErr.Detail)
}
log.Errorf("error occurred while deleting tag %s:%s: %v", repoName, t, err)
ra.CustomAbort(http.StatusInternalServerError, "internal error")
}
log.Infof("delete tag: %s:%s", repoName, t)
go TriggerReplicationByRepository(repoName, []string{t}, models.RepOpDelete)

View File

@ -73,6 +73,7 @@ func (sia *SystemInfoAPI) GetVolumeInfo() {
func (sia *SystemInfoAPI) GetCert() {
if sia.isAdmin {
if _, err := os.Stat(defaultRootCert); !os.IsNotExist(err) {
sia.Ctx.Output.Header("Content-Type", "application/octet-stream")
sia.Ctx.Output.Header("Content-Disposition", "attachment; filename=ca.crt")
http.ServeFile(sia.Ctx.ResponseWriter, sia.Ctx.Request, defaultRootCert)
} else {
@ -80,5 +81,5 @@ func (sia *SystemInfoAPI) GetCert() {
sia.CustomAbort(http.StatusNotFound, "No certificate found.")
}
}
sia.CustomAbort(http.StatusUnauthorized, "")
sia.CustomAbort(http.StatusForbidden, "")
}

View File

@ -188,14 +188,13 @@
return directive;
function link(scope, element, attrs, ctrl) {
$(document).on('click', clickHandler);
function clickHandler(e) {
$('[data-toggle="popover"]').each(function () {
if (!$(this).is(e.target) &&
$(this).has(e.target).length === 0 &&
$('.popover').has(e.target).length === 0) {
$(this).parent().popover('hide');
$('[data-toggle="popover"],[data-original-title]').each(function () {
if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
(($(this).popover('hide').data('bs.popover')||{}).inState||{}).click = false;
}
});
var targetId = $(e.target).attr('id');

View File

@ -1,17 +1,3 @@
<!--
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.
-->
<a role="button" tab-index="0" data-trigger="focus" data-toggle="popover" data-placement="right" data-title="//vm.helpTitle//">
<a href="javascript:void(0);" role="button" tabindex="0" data-trigger="focus" data-toggle="popover" data-placement="right">
<span class="glyphicon glyphicon-info-sign"></span>
</a>

View File

@ -29,6 +29,7 @@
'helpTitle': '@',
'content': '@'
},
'replace': true,
'link': link,
'controller': InlineHelpController,
'controllerAs': 'vm',

View File

@ -1,3 +1,17 @@
<!--
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.
-->
<nav aria-label="Page navigation" class="pull-left">
<ul class="pagination" style="margin: 0 0 0 10px;">
<li ng-class="vm.disabledFirst" ng-show="vm.visible">

View File

@ -1,3 +1,17 @@
/*
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.
*/
(function() {
'use strict';
@ -210,245 +224,7 @@
togglePrevious(tc.canDecrement());
toggleNext(tc.canIncrement());
}
(function() {
'use strict';
angular
.module('harbor.paginator')
.directive('paginator', paginator);
PaginatorController.$inject = [];
function PaginatorController() {
var vm = this;
}
paginator.$inject = [];
function paginator() {
var directive = {
'restrict': 'E',
'templateUrl': '/static/resources/js/components/paginator/paginator.directive.html',
'scope': {
'totalCount': '@',
'pageSize': '@',
'page': '=',
'displayCount': '@'
},
'link': link,
'controller': PaginatorController,
'controllerAs': 'vm',
'bindToController': true
};
return directive;
function link(scope, element, attrs, ctrl) {
scope.$watch('vm.page', function(current) {
if(current) {
ctrl.page = current;
togglePageButton();
}
});
var tc;
scope.$watch('vm.totalCount', function(current) {
if(current) {
var totalCount = current;
tc = new TimeCounter();
console.log('Total Count:' + totalCount + ', Page Size:' + ctrl.pageSize + ', Display Count:' + ctrl.displayCount + ', Page:' + ctrl.page);
ctrl.buttonCount = Math.ceil(totalCount / ctrl.pageSize);
if(ctrl.buttonCount <= ctrl.displayCount) {
tc.setMaximum(1);
ctrl.visible = false;
}else{
tc.setMaximum(Math.ceil(ctrl.buttonCount / ctrl.displayCount));
ctrl.visible = true;
}
ctrl.gotoFirst = gotoFirst;
ctrl.gotoLast = gotoLast;
if(ctrl.buttonCount < ctrl.page) {
ctrl.page = ctrl.buttonCount;
}
ctrl.previous = previous;
ctrl.next = next;
drawButtons(tc.getTime());
togglePrevious(tc.canDecrement());
toggleNext(tc.canIncrement());
toggleFirst();
toggleLast();
togglePageButton();
}
});
var TimeCounter = function() {
this.time = 0;
this.minimum = 0;
this.maximum = 0;
};
TimeCounter.prototype.setMaximum = function(maximum) {
this.maximum = maximum;
};
TimeCounter.prototype.getMaximum = function() {
return this.maximum;
};
TimeCounter.prototype.increment = function() {
if(this.time < this.maximum) {
++this.time;
if((ctrl.page % ctrl.displayCount) != 0) {
ctrl.page = this.time * ctrl.displayCount;
}
++ctrl.page;
}
};
TimeCounter.prototype.canIncrement = function() {
if(this.time + 1 < this.maximum) {
return true;
}
return false;
};
TimeCounter.prototype.decrement = function() {
if(this.time > this.minimum) {
if(this.time === 0) {
ctrl.page = ctrl.displayCount;
}else{
ctrl.page = this.time * ctrl.displayCount;
}
--this.time;
}
};
TimeCounter.prototype.canDecrement = function() {
if(this.time > this.minimum) {
return true;
}
return false;
};
TimeCounter.prototype.getTime = function() {
return this.time;
};
TimeCounter.prototype.setTime = function(time) {
this.time = time;
};
function drawButtons(time) {
element.find('li[tag="pagination-button"]').remove();
var buttons = [];
for(var i = 1; i <= ctrl.displayCount; i++) {
var displayNumber = ctrl.displayCount * time + i;
if(displayNumber <= ctrl.buttonCount) {
buttons.push('<li tag="pagination-button"><a href="javascript:void(0)" page="' + displayNumber + '">' + displayNumber + '<span class="sr-only"></span></a></li>');
}
}
$(buttons.join(''))
.insertAfter(element.find('ul li:eq(' + (ctrl.visible ? 1 : 0) + ')')).end()
.on('click', buttonClickHandler);
}
function togglePrevious(status) {
ctrl.disabledPrevious = status ? '' : 'disabled';
toggleFirst();
toggleLast();
}
function toggleNext(status) {
ctrl.disabledNext = status ? '' : 'disabled';
toggleFirst();
toggleLast();
}
function toggleFirst() {
ctrl.disabledFirst = (ctrl.page > 1) ? '' : 'disabled';
}
function toggleLast() {
ctrl.disabledLast = (ctrl.page < ctrl.buttonCount) ? '' : 'disabled';
}
function buttonClickHandler(e) {
ctrl.page = $(e.target).attr('page');
togglePageButton();
togglePrevious(tc.canDecrement());
toggleNext(tc.canIncrement());
scope.$apply();
}
function togglePageButton() {
element.find('li[tag="pagination-button"]').removeClass('active');
element.find('li[tag="pagination-button"] a[page="' + ctrl.page + '"]').parent().addClass('active');
}
function previous() {
if(tc.canDecrement()) {
tc.decrement();
drawButtons(tc.getTime());
togglePageButton();
togglePrevious(tc.canDecrement());
toggleNext(tc.canIncrement());
}
}
function gotoFirst() {
ctrl.page = 1;
tc.setTime(0);
drawButtons(0);
toggleFirst();
toggleLast();
togglePageButton();
togglePrevious(tc.canDecrement());
toggleNext(tc.canIncrement());
}
function next() {
if(tc.canIncrement()) {
tc.increment();
drawButtons(tc.getTime());
togglePageButton();
togglePrevious(tc.canDecrement());
toggleNext(tc.canIncrement());
}
}
function gotoLast() {
ctrl.page = ctrl.buttonCount;
tc.setTime(Math.ceil(ctrl.buttonCount / ctrl.displayCount) - 1);
drawButtons(tc.getTime());
toggleFirst();
toggleLast();
togglePageButton();
togglePrevious(tc.canDecrement());
toggleNext(tc.canIncrement());
}
}
}
})();
function next() {
if(tc.canIncrement()) {
tc.increment();

View File

@ -1,3 +1,17 @@
/*
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.
*/
(function() {
'use strict';

View File

@ -1,4 +1,3 @@
<a href="javascript:void(0)">
<span class="glyphicon glyphicon-info-sign" role="button" data-trigger="click" data-toggle="popover" data-placement="right">
</span>
<a href="javascript:void(0);" role="button" tabindex="0" data-trigger="click" data-toggle="popover" data-placement="right">
<span class="glyphicon glyphicon-info-sign"></span>
</a>

View File

@ -27,7 +27,7 @@
}
popupDetails.$inject = ['ListManifestService', '$filter', 'dateLFilter'];
function popupDetails(ListManifestService, $filter, dateLFilter) {
var directive = {
'restrict': 'E',
@ -46,6 +46,7 @@
return directive;
function link(scope, element, attrs, ctrl) {
element
.popover({
'template': '<div class="popover" role="tooltip"><div class="arrow"></div><div class="popover-title"></div><div class="popover-content"></div></div>',
@ -68,16 +69,16 @@
ctrl.manifest['created'] = $filter('dateL')(ctrl.manifest['created'], 'YYYY-MM-DD HH:mm:ss');
}
})
.on('inserted.bs.popover', function(e){
var self = jQuery(this);
.on('inserted.bs.popover', function(e){
var self = jQuery(this);
$('[type="text"]:input', self.parent())
.on('click', function() {
.on('click', function(e) {
$(this).select();
});
self.parent().find('.glyphicon.glyphicon-remove-circle').on('click', function() {
element.trigger('click');
self.trigger('click');
});
});
});
function generateContent() {
var content = '<form class="form-horizontal" width="100%">' +

View File

@ -0,0 +1,71 @@
/*
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.
*/
(function() {
'use strict';
angular
.module('harbor.validator')
.directive('charsLength', charsLength);
charsLength.$inject = ['ASCII_CHARS'];
function charsLength(ASCII_CHARS) {
var directive = {
'require': 'ngModel',
'scope': {
min: '@',
max: '@'
},
'link': link
};
return directive;
function link(scope, element, attrs, ctrl) {
ctrl.$validators.charsLength = validator;
function validator(modelValue, viewValue) {
if(ctrl.$isEmpty(modelValue)) {
return true;
}
var actualLength = 0;
if(ASCII_CHARS.test(modelValue)) {
actualLength = modelValue.length;
}else{
for(var i = 0; i < modelValue.length; i++) {
ASCII_CHARS.test(modelValue[i]) ? actualLength += 1 : actualLength += 2;
}
}
if(attrs.min && actualLength < attrs.min) {
return false;
}
if(attrs.max && actualLength > attrs.max) {
return false;
}
return true;
}
}
}
})();

View File

@ -39,14 +39,11 @@
ctrl.$validators.userExists = validator;
function validator(modelValue, viewValue) {
console.log('modelValue:' + modelValue + ', viewValue:' + viewValue);
if(ctrl.$isEmpty(modelValue)) {
console.log('Model value is empty.');
return true;
}
UserExistService(attrs.target, modelValue)
.success(userExistSuccess)
.error(userExistFailed);

View File

@ -21,6 +21,7 @@
.constant('INVALID_CHARS', [",","~","#", "$", "%"])
.constant('PASSWORD_REGEXP', /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?!.*\s).{8,20}$/)
.constant('PROJECT_REGEXP', /^[a-z0-9](?:-*[a-z0-9])*(?:[._][a-z0-9](?:-*[a-z0-9])*)*$/)
.constant('EMAIL_REGEXP', /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/);
.constant('EMAIL_REGEXP', /^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/)
.constant('ASCII_CHARS', /^[\000-\177]*$/);
})();

View File

@ -42,11 +42,11 @@
<div class="form-group">
<label for="fullName" class="col-sm-3 control-label">// 'full_name' | tr //:</label>
<div class="col-sm-7">
<input type="text" class="form-control" id="fullName" ng-model="user.realname" name="uFullName" required maxlength="20" invalid-chars>
<input type="text" class="form-control" id="fullName" ng-model="user.realname" name="uFullName" required chars-length max="20" invalid-chars>
<div class="error-message" ng-messages="form.uFullName.$touched && form.uFullName.$error">
<span ng-message="required">// 'full_name_is_required' | tr //</span>
<span ng-message="invalidChars">// 'full_name_contains_illegal_chars' | tr //</span>
<span ng-message="maxlength">// 'full_name_is_too_long' | tr //</span>
<span ng-message="charsLength">// 'full_name_is_too_long' | tr //</span>
</div>
</div>
<div class="col-sm-2">
@ -56,9 +56,9 @@
<div class="form-group">
<label for="comments" class="col-sm-3 control-label">// 'comments' | tr //:</label>
<div class="col-sm-7">
<input type="text" class="form-control" id="comments" ng-model="user.comment" name="uComments" maxlength="20">
<input type="text" class="form-control" id="comments" ng-model="user.comment" name="uComments" chars-length max="20">
<div class="error-message" ng-messages="form.uComments.$touched && form.uComments.$error">
<span ng-show="maxlength">// 'comment_is_too_long' | tr //</span>
<span ng-message="charsLength">// 'comment_is_too_long' | tr //</span>
</div>
</div>
</div>

View File

@ -131,6 +131,7 @@
<script src="/static/resources/js/components/validator/invalid-chars.validator.js"></script>
<script src="/static/resources/js/components/validator/project-name.validator.js"></script>
<script src="/static/resources/js/components/validator/email.validator.js"></script>
<script src="/static/resources/js/components/validator/chars-length.validator.js"></script>
<script src="/static/resources/js/components/search/search.module.js"></script>
<script src="/static/resources/js/components/search/search.directive.js"></script>

View File

@ -30,12 +30,12 @@
<div class="form-group">
<label for="username" class="col-sm-3 control-label">// 'username' | tr //:</label>
<div class="col-sm-7">
<input type="text" class="form-control" id="username" ng-model="user.username" name="uUsername" ng-model-options="{ updateOn: 'blur' }" required maxlength="20" invalid-chars user-exists data-target="username">
<input type="text" class="form-control" id="username" ng-model="user.username" name="uUsername" required invalid-chars user-exists data-target="username" maxlength="20">
<div class="error-message" ng-messages="(form.$submitted || form.uUsername.$touched) && form.uUsername.$error" >
<span ng-message="required">// 'username_is_required' | tr //</span>
<span ng-message="maxlength">// 'username_is_too_long' | tr //</span>
<span ng-message="invalidChars">// 'username_contains_illegal_chars' | tr //</span>
<span ng-message="userExists">// 'username_has_been_taken' | tr //</span>
<span ng-message="invalidChars">// 'username_contains_illegal_chars' | tr //</span>
</div>
</div>
<div class="col-sm-2">
@ -45,7 +45,7 @@
<div class="form-group">
<label for="email" class="col-sm-3 control-label">// 'email' | tr //:</label>
<div class="col-sm-7">
<input type="text" class="form-control" id="email" ng-model="user.email" name="uEmail" ng-model-options="{ updateOn: 'blur' }" required user-exists data-target="email" email>
<input type="text" class="form-control" id="email" ng-model="user.email" name="uEmail" required user-exists data-target="email" email>
<div class="error-message" ng-messages="(form.$submitted || form.uEmail.$touched) && form.uEmail.$error">
<span ng-message="required">// 'email_is_required' | tr //</span>
<span ng-message="email">// 'email_content_illegal' | tr //</span>
@ -60,11 +60,11 @@
<div class="form-group">
<label for="fullName" class="col-sm-3 control-label">// 'full_name' | tr //:</label>
<div class="col-sm-7">
<input type="text" class="form-control" id="fullName" ng-model="user.fullName" name="uFullName" ng-model-options="{ updateOn: 'blur' }" required maxlength="20" invalid-chars>
<input type="text" class="form-control" id="fullName" ng-model="user.fullName" name="uFullName" required chars-length max="20" invalid-chars>
<div class="error-message" ng-messages="(form.$submitted || form.uFullName.$touched) && form.uFullName.$error">
<span ng-message="required">// 'full_name_is_required' | tr //</span>
<span ng-message="invalidChars">// 'full_name_contains_illegal_chars' | tr //</span>
<span ng-message="maxlength">// 'full_name_is_too_long' | tr //</span>
<span ng-message="charsLength">// 'full_name_is_too_long' | tr //</span>
</div>
<p class="help-block small-size-fonts">// 'full_name_desc' | tr //</p>
</div>
@ -75,7 +75,7 @@
<div class="form-group">
<label for="password" class="col-sm-3 control-label">// 'password' | tr //:</label>
<div class="col-sm-7">
<input type="password" class="form-control" id="password" ng-model="user.password" name="uPassword" ng-model-options="{ updateOn: 'blur' }" required password>
<input type="password" class="form-control" id="password" ng-model="user.password" name="uPassword" required password>
<div class="error-message" ng-messages="(form.$submitted || form.uPassword.$touched) && form.uPassword.$error">
<span ng-message="required">// 'password_is_required' | tr //</span>
<span ng-message="password">// 'password_is_invalid' | tr //</span>
@ -89,7 +89,7 @@
<div class="form-group">
<label for="confirmPassword" class="col-sm-3 control-label">// 'confirm_password' | tr //:</label>
<div class="col-sm-7">
<input type="password" class="form-control" id="confirmPassword" ng-model="user.confirmPassword" name="uConfirmPassword" ng-model-options="{ updateOn: 'blur' }" compare-to="user.password">
<input type="password" class="form-control" id="confirmPassword" ng-model="user.confirmPassword" name="uConfirmPassword" compare-to="user.password">
<div class="error-message" ng-messages="(form.$submitted || form.uConfirmPassword.$touched) && form.uConfirmPassword.$error">
<span ng-message="compareTo">// 'password_does_not_match' | tr //</span>
</div>
@ -101,9 +101,9 @@
<div class="form-group">
<label for="comments" class="col-sm-3 control-label">// 'comments' | tr //:</label>
<div class="col-sm-7">
<input type="text" class="form-control" id="comments" ng-model="user.comment" name="uComments" ng-model-options="{ updateOn: 'blur' }" maxlength="20">
<input type="text" class="form-control" id="comments" ng-model="user.comment" name="uComments" chars-length max="20">
<div class="error-message" ng-messages="(form.$submitted || form.uComments.$touched) && form.uComments.$error">
<span ng-show="maxlength">// 'comment_is_too_long' | tr //</span>
<span ng-message="charsLength">// 'comment_is_too_long' | tr //</span>
</div>
</div>
</div>

View File

@ -1,6 +1,8 @@
#!/bin/bash
dir=harbor_logs
outputdir=/tmp
outputfolder=harbor_logs
dir=$outputdir/$outputfolder
mkdir -p $dir
echo "Version" >> $dir/docker
@ -15,7 +17,29 @@ docker ps >> $dir/docker
docker-compose version >> $dir/docker-compose
base_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cp -r $base_dir/../harbor/common $dir/
cp -r $base_dir/../script $dir/
cp $base_dir/../harbor/harbor.cfg $dir/
cp -r /var/log/harbor $dir/
tar --remove-files -zcf $dir.tar.gz $dir
properties=(
email_server
email_server_port
email_username
email_password
email_from
harbor_admin_password
ldap_url
ldap_searchdn
ldap_search_pwd
ldap_basedn
db_password
)
for property in "${properties[@]}"
do
sed -i -r "s%#?$property\s*=\s*.*%$property = %" $dir/harbor.cfg
done
tar --remove-files -zcf $outputfolder.tar.gz -C $outputdir $outputfolder
echo "$outputfolder.tar.gz is generated in current directory."

View File

@ -10,9 +10,6 @@ function down {
function up {
base_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
$base_dir/start_harbor.sh
echo "Resetting DNS and hostname using vami_ovf_process..."
/opt/vmware/share/vami/vami_ovf_process --setnetwork || true
}
#Configure Harbor
@ -21,18 +18,25 @@ function configure {
$base_dir/config.sh
}
function getRegistryVersion {
registry_version=""
base_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
registry_version=$(sed -n -e 's|.*library/registry:||p' $base_dir/../harbor/docker-compose.yml)
if [ -z registry_version ]
then
registry_version="latest"
fi
}
#Garbage collectoin
function gc {
echo "======================= $(date)====================="
getRegistryVersion
#the registry image
image=$1
base_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
docker run --name gc --rm --volume /data/registry:/storage \
--volume $base_dir/../harbor/common/config/registry/:/etc/registry/ \
$image garbage-collect /etc/registry/config.yml
registry:$registry_version garbage-collect /etc/registry/config.yml
echo "===================================================="
}
@ -88,55 +92,16 @@ function configureHarborCfg {
if [ -n "$cfg_key" ]
then
sed -i -r s%"#?$cfg_key\s*=\s*.*"%"$cfg_key = $cfg_value"% $cfg_file
cfg_value=$(echo "$cfg_value" | sed -r -e 's%[\/&%]%\\&%g')
sed -i -r "s%#?$cfg_key\s*=\s*.*%$cfg_key = $cfg_value%" $cfg_file
fi
}
function configureDockerDNS {
echo "Resetting DNS using vami_ovf_process..."
/opt/vmware/share/vami/vami_ovf_process --setnetwork || true
sed -n -e 's/^nameserver //p' /etc/resolv.conf > /tmp/dns
readarray dns < /tmp/dns
opts=""
for d in "${dns[@]}"
do
if [ -n "$d" ]
then
opts="$opts --dns=$d"
fi
done
rm /tmp/dns
domain=$(sed -n -e 's/^domain //p' /etc/resolv.conf)
if [ -n "$domain" ]
then
opts="$opts --dns-search=$domain"
fi
search=$(sed -n -e 's/^search //p' /etc/resolv.conf)
if [ -n "$search" ]
then
searcharray=($search)
for s in "${searcharray[@]}"
do
if [ -n "$s" ]
then
opts="$opts --dns-search=$s"
fi
done
fi
echo Setting docker: $opts
echo DOCKER_OPTS=$opts > /etc/default/docker
systemctl restart docker
}
function pushPhoton {
set +e
basedir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
registry_version=$(sed -n -e 's|.*library/registry:||p' $basedir/../harbor/docker-compose.yml)
getRegistryVersion
docker run -d --name photon_pusher -v /data/registry:/var/lib/registry -p 5000:5000 registry:$registry_version
docker tag photon:1.0 127.0.0.1:5000/library/photon:1.0
sleep 5

View File

@ -132,15 +132,6 @@ function secure {
}
function detectHostname {
#echo "Read attribute using ovfenv: [ vami.domain.Harbor ]"
#hostname=$(ovfenv -k vami.domain.Harbor)
#if [ -n $hostname ]
#then
# echo "Get hostname from ovfenv: $hostname"
# return
#fi
echo "Resetting hostname using vami_ovf_process..."
/opt/vmware/share/vami/vami_ovf_process --setnetwork || true
hostname=$(hostname --fqdn) || true
if [ -n $hostname ]
then
@ -166,7 +157,7 @@ fi
if [ -n "$hostname" ]
then
echo "Hostname: $hostname"
configureHarborCfg hostname $hostname
configureHarborCfg "hostname" "$hostname"
else
echo "Failed to get the hostname"
exit 1
@ -193,16 +184,11 @@ do
echo "Read attribute using ovfenv: [ $attr ]"
value=$(ovfenv -k $attr)
#ldap search password and email password can be null
if [ -n "$value" ] || [ "$attr" = "ldap_search_pwd" ] \
|| [ "$attr" = "email_password" ]
then
#if [ "$attr" = ldap_search_pwd ] \
# || [ "$attr" = email_password ]
#then
# bs=$(echo $value | base64)
# value={base64}$bs
#fi
configureHarborCfg $attr $value
fi
#if [ "$attr" = ldap_search_pwd ] \
# || [ "$attr" = email_password ]
#then
# bs=$(echo $value | base64)
# value={base64}$bs
#fi
configureHarborCfg "$attr" "$value"
done

View File

@ -13,7 +13,7 @@ value=$(ovfenv -k root_pwd)
if [ -n "$value" ]
then
echo "Resetting root password..."
printf "$value\n$value\n" | passwd root
printf "%s\n%s\n" "$value" "$value" | passwd root
fi
#configure SSH
@ -25,10 +25,8 @@ addIptableRules
echo "Installing docker compose..."
installDockerCompose
#echo "Starting docker service..."
#systemctl start docker
echo "Configuring docker..."
configureDockerDNS
echo "Starting docker service..."
systemctl start docker
echo "Uncompress Harbor offline instaler tar..."
tar -zxvf $base_dir/../harbor-offline-installer*.tgz -C $base_dir/../

View File

@ -9,7 +9,7 @@ echo "Read attribute using ovfenv: [ auth_mode ]"
auth_mode=$(ovfenv -k auth_mode)
if [ -n "$auth_mode" ]
then
configureHarborCfg auth_mode $auth_mode
configureHarborCfg "auth_mode" "$auth_mode"
fi
#Configure password of Harbor administrator
@ -17,7 +17,7 @@ echo "Read attribute using ovfenv: [ harbor_admin_password ]"
adm_pwd=$(ovfenv -k harbor_admin_password)
if [ -n "$adm_pwd" ]
then
configureHarborCfg harbor_admin_password $adm_pwd
configureHarborCfg "harbor_admin_password" "$adm_pwd"
fi
#Configure password of database
@ -25,7 +25,7 @@ echo "Read attribute using ovfenv: [ db_password ]"
db_pwd=$(ovfenv -k db_password)
if [ -n "$db_pwd" ]
then
configureHarborCfg db_password $db_pwd
configureHarborCfg "db_password" "$db_pwd"
fi
#Configure other attrs

View File

@ -24,7 +24,7 @@ then
echo "GC enabled, starting garbage collection..."
#If the registry contains no images, the gc will fail.
#So append a true to avoid failure.
gc registry:2.5.0 2>&1 >> /var/log/harbor/gc.log || true
gc 2>&1 >> /var/log/harbor/gc.log || true
else
echo "GC disabled, skip garbage collection"
fi
@ -33,9 +33,6 @@ fi
echo "Configuring Harbor..."
configure
echo "Configuring docker..."
configureDockerDNS
#Start Harbor
echo "Starting Harbor..."
up