Merge remote-tracking branch 'upstream/job-service' into sync_image

This commit is contained in:
Wenkai Yin 2016-05-17 13:39:52 +08:00
commit 310460fa68
18 changed files with 507 additions and 240 deletions

View File

@ -2,8 +2,8 @@ appname = registry
runmode = dev
[lang]
types = en-US|zh-CN|de-DE
names = en-US|zh-CN|de-DE
types = en-US|zh-CN|de-DE|ru-RU
names = en-US|zh-CN|de-DE|ru-RU
[dev]
httpport = 80

View File

@ -6,22 +6,21 @@
> Project Harbor is initiated by VMware China R&D as a Cloud Application Accelerator (CAA) project. CAA provides a set of tools to improve the productivity of cloud developers in China and other countries. CAA includes tools like registry server, mirror server, decentralized image distributor, etc.
Project Harbor is an enterprise-class registry server. It extends the open source Docker Registry server by adding more functionalities usually required by an enterprise. Harbor is designed to be deployed in a private environment of an organization. A private registry is important for organizations who care much about security. In addition, a private registry improves productivity by eliminating the need to download images from the public network. This is very helpful to container users who do not have a good network to the Internet.
Project Harbor is an enterprise-class registry server, which extends the open source Docker Registry server by adding the functionality usually required by an enterprise, such as security, control, and management. Harbor is primarily designed to be a private registry - providing the needed security and control that enterprises require. It also helps minimize bandwidth usage, which is helpful to both improve productivity (local network access) as well as performance (for those with poor internet connectivity).
### Features
* **Role Based Access Control**: Users and docker repositories are organized via "projects", a user can have different permission for images under a namespace.
* **Graphical user portal**: User can easily browse, search docker repositories, manage projects/namespaces.
* **AD/LDAP support**: Harbor integrates with existing AD/LDAP of the enterprise for user authentication and management.
* **Auditing**: All the operations to the repositories are tracked and can be used for auditing purpose.
* **Internationalization**: Localized for English, Chinese and German languages. More languages can be added.
* **RESTful API**: RESTful APIs are provided for most administrative operations of Harbor. The integration with other management softwares becomes easy.
* **AD/LDAP support**: Harbor integrates with existing enterprise AD/LDAP for user authentication and management.
* **Auditing**: All the operations to the repositories are tracked.
* **Internationalization**: Already Localized for English, Chinese and German. More languages can be added.
* **RESTful API**: RESTful APIs for most administrative operations, easing intergration with external management platforms.
### Getting Started
Harbor is self-contained and can be easily deployed via docker-compose. The below are quick-start steps. Refer to the [Installation and Configuration Guide](docs/installation_guide.md) for detail information.
Harbor is self-contained and can be easily deployed via docker-compose (Quick-Start steps below). Refer to the [Installation and Configuration Guide](docs/installation_guide.md) for detailed information.
**System requirements:**
Harbor only works with docker 1.10+ and docker-compose 1.6.0+ .
The host must be connected to the Internet.
Harbor only works with docker 1.10+ and docker-compose 1.6.0+, and an internet-connected host
1. Get the source code:
@ -31,7 +30,7 @@ The host must be connected to the Internet.
2. Edit the file **Deploy/harbor.cfg**, make necessary configuration changes such as hostname, admin password and mail server. Refer to [Installation and Configuration Guide](docs/installation_guide.md) for more info.
3. Install Harbor by the following commands. It may take a while for the docker-compose process to finish.
3. Install Harbor with the following commands. Note that the docker-compose process can take a while!
```sh
$ cd Deploy
@ -44,21 +43,21 @@ The host must be connected to the Internet.
$ docker-compose up
```
If everything works fine, you can open a browser to visit the admin portal at http://reg.yourdomain.com . The default administrator username and password are admin/Harbor12345 .
_If everything worked properly, you should be able to open a browser to visit the admin portal at http://reg.yourdomain.com . 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. The default port of Harbor registry server is 80:
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
```
**NOTE:**
To simplify the installation process, a pre-built installation package of Harbor is provided so that you don't need to clone the source code. By using this package, you can even install Harbor onto a host that is not connected to the Internet. For details on how to download and use this installation package, please refer to [Installation and Configuration Guide](docs/installation_guide.md) .
For those who don't want to clone the source, or need to install Harbor on a server not connected to the Internet - there is a pre-built installation package available. For details on how to download and use this installation package, please refer to [Installation and Configuration Guide](docs/installation_guide.md) .
For information on how to use Harbor, please see [User Guide](docs/user_guide.md) .
### Deploy Harbor on Kubernetes
Detailed instruction about deploying Harbor on Kubernetes is described [here](docs/kubernetes_deployment.md).
Detailed instruction about deploying Harbor on Kubernetes is available [here](docs/kubernetes_deployment.md).
### Contribution
We welcome contributions from the community. If you wish to contribute code and you have not signed our contributor license agreement (CLA), our bot will update the issue when you open a pull request. For any questions about the CLA process, please refer to our [FAQ](https://cla.vmware.com/faq).

View File

@ -29,7 +29,6 @@ import (
svc_utils "github.com/vmware/harbor/service/utils"
"github.com/vmware/harbor/utils/log"
"github.com/vmware/harbor/utils/registry"
"github.com/vmware/harbor/utils/registry/auth"
"github.com/vmware/harbor/utils/registry/errors"
)
@ -39,22 +38,12 @@ import (
// the security of registry
type RepositoryAPI struct {
BaseAPI
userID int
username string
userID int
}
// Prepare will set a non existent user ID in case the request tries to view repositories under a project he doesn't has permission.
func (ra *RepositoryAPI) Prepare() {
userID, ok := ra.GetSession("userId").(int)
if !ok {
userID = dao.NonExistUserID
}
ra.userID = userID
username, ok := ra.GetSession("username").(string)
if ok {
ra.username = username
}
ra.userID = ra.ValidateUser()
}
// Get ...
@ -250,29 +239,15 @@ func (ra *RepositoryAPI) GetManifests() {
}
func (ra *RepositoryAPI) initializeRepositoryClient(repoName string) (r *registry.Repository, err error) {
u := models.User{
UserID: ra.userID,
}
user, err := dao.GetUser(u)
if err != nil {
return nil, err
}
endpoint := os.Getenv("REGISTRY_URL")
//no session, use basic auth
if ra.userID == dao.NonExistUserID {
username, password, _ := ra.Ctx.Request.BasicAuth()
credential := auth.NewBasicAuthCredential(username, password)
return registry.NewRepositoryWithCredential(repoName, endpoint, credential)
}
//session exists, use username
if len(ra.username) == 0 {
u := models.User{
UserID: ra.userID,
}
user, err := dao.GetUser(u)
if err != nil {
return nil, err
}
ra.username = user.Username
}
return registry.NewRepositoryWithUsername(repoName, endpoint, ra.username)
return registry.NewRepositoryWithUsername(repoName, endpoint, user.Username)
}

View File

@ -69,7 +69,7 @@ func (c *CommonController) Login() {
// SwitchLanguage handles UI request to switch between different languages and re-render template based on language.
func (c *CommonController) SwitchLanguage() {
lang := c.GetString("lang")
if lang == "en-US" || lang == "zh-CN" || lang == "de-DE" {
if lang == "en-US" || lang == "zh-CN" || lang == "de-DE" || lang == "ru-RU" {
c.SetSession("lang", lang)
c.Data["Lang"] = lang
}

View File

@ -1,21 +1,28 @@
# Installation and Configuration Guide of Harbor
Harbor can be installed by two approaches:
# Installation and Configuration Guide
Harbor can be installed in one of two ways:
1. Installing from the source code, which goes through a full build process. Internet connection is required.
2. Installing via a pre-built installation package, which saves time for building the code. Further, it provides a way to install Harbor to a host that is isolated from the Internet (offline installation).
1. From source code - This goes through a full build process, _and requires an Internet connection_.
2. Pre-built installation package - This can save time (no building necessary!) as well as allows for installation on a host that is _not_ connected to the Internet.
This guide describes both approaches and their usage.
This guide describes both of these approaches
## Prerequisites of the target host
Harbor is deployed as several Docker containers. Hence, it can be deployed on any Linux distribution that supports Docker.
Before deploying Harbor, the target host requires Python, Docker, Docker Compose to be installed.
* Python should be version 2.7 or higher. Some Linux distributions (Gentoo, Arch) may not have a Python interpreter installed by default. On those systems, you need to install Python manually.
* The Docker engine should be version 1.10 or higher. For the details to install Docker engine, please refer to: https://docs.docker.com/engine/installation/
* The Docker Compose needs to be version 1.6.0 or higher. For the details to install Docker compose, please refer to: https://docs.docker.com/compose/install/
## 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/
## Installing Harbor from the source code
## Installation from source code
_Note: To install from source, the target host must be connected to the Internet!_
The steps boil down to the following
1. Get the source code
2. Configure **harbor.cfg**
3. **prepare** the configuration files
4. Start Harbor with Docker Compose
To install from the source, the target host must be connected to the Internet.
#### Getting the source code:
```sh
@ -23,30 +30,28 @@ $ git clone https://github.com/vmware/harbor
```
#### Configuring Harbor
Before installing Harbor, you should configure the parameters in the file **harbor.cfg**. You then execute the **prepare** script to generate configuration files for Harbor's containers. Finally, you use Docker Compose to start 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.
At minimum, you need to change the **hostname** attribute in **harbor.cfg**. The description of each attribute is as follows:
* **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 mnote 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
**hostname**: The hostname for a user to access the user interface and the registry service. It should be the IP address or the fully qualified domain name (FQDN) of your target machine, for example 192.168.1.10 or reg.yourdomain.com . Do NOT use localhost or 127.0.0.1 for the hostname because the registry service needs to be accessed by external clients.
**ui_url_protocol**: The protocol for accessing the user interface and the token/notification service, by default it is http. To set up the https protocol, refer to [Configuring Harbor with HTTPS Access](configure_https.md).
**Email settings**: the following 6 attributes are used to send an email to reset a user's password, they are not mandatory unless the password reset function is needed in Harbor. By default SSL connection is not enabled, if your smtp server(such as exmail.qq.com) requires SSL connection and doesn't support STARTTLS, then you should enable it by set **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 password for the administrator of Harbor, by default the password is Harbor12345, the user name is admin.
**auth_mode**: The authentication mode of Harbor. By default it is *db_auth*, i.e. the credentials are stored in a database. Please set it to *ldap_auth* if you want to verify user's credentials against an LDAP server.
**ldap_url**: The URL for LDAP endpoint, for example ldaps://ldap.mydomain.com. It is only used when **auth_mode** is set to *ldap_auth*.
**ldap_basedn**: The basedn template for verifying the user's credentials against LDAP, for example uid=%s,ou=people,dc=mydomain,dc=com. It is only used when **auth_mode** is set to *ldap_auth*.
**db_password**: The password of root user of mySQL database. Change this password for any production use.
**self_registration**: The flag to turn on or off the user self-registration function. If this flag is turned off, only an admin user can create new users in Harbor. The default value is on.
NOTE: When **auth_mode** is *ldap_auth*, the self-registration feature is always disabled, therefore, this flag is ignored.
* **harbor_admin_password**: The adminstrator's password. _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_basedn**: The basedn template for verifying the user's credentials against LDAP (e.g. `uid=%s,ou=people,dc=mydomain,dc=com`). _Only used when **auth_mode** is set to *ldap_auth* ._
* **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.
#### Building and starting Harbor
After configuring harbor.cfg, build and start Harbor by the following commands. Because it requires downloading necessary files from the Internet, it may take a while for the docker-compose process to finish.
Once **harbord.cfg** is configured, build and start Harbor as follows. Note that Note that the docker-compose process can take a while!
```sh
$ cd Deploy
@ -61,29 +66,76 @@ After configuring harbor.cfg, build and start Harbor by the following commands.
$ sudo docker-compose up -d
```
If everything works fine, you can open a browser to visit the admin portal at http://reg.yourdomain.com . The default administrator username and password are admin/Harbor12345 .
_If everything worked properly, you should be able to open a browser to visit the admin portal at http://reg.yourdomain.com . 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. The default port of Harbor registry server is 80:
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
```
**NOTE:** The default installation of Harbor uses HTTP protocol, you should add the option "--insecure-registry" to your client's Docker daemon and restart Docker service.
**NOTE:** 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
Because Harbor does not ship with any certificates, it uses HTTP by default to serve registry requests. This makes it relatively simple to configure, especially for a development or testing environment. However, it is highly recommended that security be enabled for any production environment. Refer to [Configuring Harbor with HTTPS Access](configure_https.md) if you want to enable HTTPS access to Harbor.
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)
## Installing Harbor via a pre-built installation package
#### Configuring Harbor as a local registry mirror
The Harbor runs as a local private registry by default, it can be easily configured to run as a local registry mirror, which can keep most of the redundant image fetch traffic on your local network. You just need to edit `config/registry/config.yml` after execute `./prepare`, and append a `proxy` section as follows:
A pre-built installation package of each release can be downloaded from the [release page](https://github.com/vmware/harbor/releases). After downloading the package file **harbor-&lt;version&gt;.tgz** , extract files in the package.
```
proxy:
remoteurl: https://registry-1.docker.io
```
In order to access private images on the Docker Hub, a username and password can be supplied:
```
proxy:
remoteurl: https://registry-1.docker.io
username: [username]
password: [password]
```
You will need to pass the `--registry-mirror` option to your Docker daemon on startup:
```
docker --registry-mirror=https://<my-docker-mirror-host> daemon
```
For example, if your mirror is serving on `http:/reg.yourdomain.com`, you would run:
```
docker --registry-mirror=https://reg.yourdomain.com daemon
```
Refer to the [Registry as a pull through cache](https://github.com/docker/distribution/blob/master/docs/mirror.md) for detail information.
#### Configuring storage backend
By default, the Harbor store images on your local filesystem. In production environment, you may consider using higher available storage backend instead of the local filesystem, like S3, Openstack Swift, Ceph, etc. Fortunately, the Registry supports multiple storage backend, refer to the [Registry Configuration Reference](https://docs.docker.com/registry/configuration/) for detail information. All you need to do is update the section of `storage`, and fill in the fields according to your specied backend. For example, if you use Openstack Swift as your storage backend, the file may look like this:
```
storage:
swift:
username: admin
password: ADMIN_PASS
authurl: http://keystone_addr:35357/v3
tenant: admin
domain: default
region: regionOne
container: docker_images
```
## Installation from a pre-built package
Pre-built installation packages of each release are available at [release page](https://github.com/vmware/harbor/releases).
Download the package file **harbor-&lt;version&gt;.tgz** , and then extract the files.
```
$ tar -xzvf harbor-0.1.1.tgz
$ cd harbor
```
Then configure Harbor by following instructions in Section [Configuring Harbor](#configuring-harbor). Next, run **prepare** script to generate config files and use docker compose to build Harbor's container images and eventually spin it up.
Next, configure Harbor as described earlier in [Configuring Harbor](#configuring-harbor).
Finally, run the **prepare** script to generate config files, and use docker compose to build / start Harbor.
```
@ -98,11 +150,24 @@ $ sudo docker-compose up -d
......
```
### Deploying Harbor to a host which does not have Internet access
When you run *docker-compose up* to start Harbor, it will pull base images from Docker Hub and build new images for the containers. This process requires accessing the Internet. If you want to deploy Harbor to a host that is not connected to the Internet, you need to prepare Harbor on a machine that has access to the Internet. After that, you export the images as tgz files and transfer them to the target machine. Then load the tgz file into Docker's local image repo.
### Deploying Harbor on a host which does not have Internet access
*docker-compose up* pulls the base images from Docker Hub and builds new images for the containers, which, necessarily, requires internet access. To deploy Harbor on a host that is not connected to the Internet
1. Prepare Harbor on a machine that has access to the Internet.
2. Export the images as tgz files
3. Transfer them to the target host.
4. Load the tgz file into Docker's local image repo on the host.
THese steps are detailed below
#### Building and saving images for offline installation
On a machine that is connected to the Internet, extract files from the pre-built installation package. Then run command "docker-compose build" to build the images and use the script *save_image.sh* to export them as tar files. The tar files will be stored in *images/* directory. Next, package everything in the directory *harbor/* into a tgz file and transfer it to the target machine. This can be done by executing the following commands:
On a machine that is connected to the Internet,
1. Extract the files from the pre-built installation package.
2. Then, run `docker-compose build` to build the images.
3. Use the script `save_image.sh` to export these images as tar files. Note that the tar files will be stored in the `images/` directory.
4. Package everything in the directory `harbor/` into a tgz file
5. Transfer this tgz file to the target machine.
The commands, in detail, are as follows
```
$ cd harbor
@ -123,10 +188,9 @@ $ cd ../
$ tar -cvzf harbor_offline-0.1.1.tgz harbor
```
The file **harbor_offline-0.1.1.tgz** contains the images saved by previous steps and the other files required to start Harbor.
You can use tools such as scp to transfer the file **harbor_offline-0.1.1.tgz** to the target machine that does not have Internet connection.
On the target machine, you can execute the following commands to start Harbor. Again, before running the **prepare** script,
be sure to update **harbor.cfg** to reflect the right configuration of the target machine. (Refer to Section [Configuring Harbor](#configuring-harbor) .)
The file `harbor_offline-0.1.1.tgz` contains the images and other files required to start Harbor. You can use tools such as `rsync` or `scp` to transfer the this file to the target host.
On the target host, execute the following commands to start Harbor. _Note that before running the **prepare** script, you **must** update **harbor.cfg** to reflect the right configuration of the target machine!!_ (Refer to Section [Configuring Harbor](#configuring-harbor)
```
$ tar -xzvf harbor_offline-0.1.1.tgz
$ cd harbor
@ -155,9 +219,9 @@ $ sudo docker-compose up -d
```
### Managing Harbor's lifecycle
Harbor is composed of a few containers which are deployed via docker-compose, you can use docker-compose to manage the lifecycle of the containers. Below are a few useful commands:
You can use docker-compose to manage the container lifecycle of the containers. A few useful commands are listed below:
Build and start Harbor:
*Build and start Harbor:*
```
$ sudo docker-compose up -d
Creating harbor_log_1
@ -166,7 +230,7 @@ Creating harbor_registry_1
Creating harbor_ui_1
Creating harbor_proxy_1
```
Stop Harbor:
*Stop Harbor:*
```
$ sudo docker-compose stop
Stopping harbor_proxy_1 ... done
@ -175,7 +239,7 @@ Stopping harbor_registry_1 ... done
Stopping harbor_mysql_1 ... done
Stopping harbor_log_1 ... done
```
Restart Harbor after stopping
*Restart Harbor after stopping*
```
$ sudo docker-compose start
Starting harbor_log_1
@ -184,7 +248,7 @@ Starting harbor_registry_1
Starting harbor_ui_1
Starting harbor_proxy_1
````
Remove Harbor's containers while keeping the image data and Harbor's database files on the file system:
*Remove Harbor's containers while keeping the image data and Harbor's database files on the file system: *
```
$ sudo docker-compose rm
Going to remove harbor_proxy_1, harbor_ui_1, harbor_registry_1, harbor_mysql_1, harbor_log_1
@ -195,19 +259,20 @@ Removing harbor_registry_1 ... done
Removing harbor_mysql_1 ... done
```
Remove Harbor's database and image data (for a clean re-installation):
*Remove Harbor's database and image data (for a clean re-installation):*
```sh
$ rm -r /data/database
$ rm -r /data/registry
```
[Docker Compose command-line reference](https://docs.docker.com/compose/reference/) describes the usage information for the docker-compose subcommands.
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, the data of database and image files in the registry are persisted in the directory **/data/** of the target machine. When Harbor's containers are removed and recreated, the data remain unchanged. Harbor leverages rsyslog to collect the logs of each container, by default the log files are stored in the directory **/var/log/harbor/** on Harbor's host.
By default, registry data is persisted in the target host's `/data/` of directory. This data remains unchanged even when Harbor's containers are removed and/or recreated.
In addition, Harbor users `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.
##Troubleshooting
1.When setting up Harbor behind another nginx proxy or elastic load balancing, remove the below line if the proxy already has similar settings. Be sure to edit Deploy/config/nginx/nginx.conf and remove the line under these 3 sections: "location /", "location /v2/" and "location /service/".
1.When setting up Harbor behind an nginx proxy or elastic load balancing, look for the line below, in `Deploy/config/nginx/nginx.conf` and remove it from the sections: `location /`, `location /v2/` and `location /service/`.
```
proxy_set_header X-Forwarded-Proto $scheme;
```

0
docs/user_guide.md Executable file → Normal file
View File

View File

@ -16,8 +16,6 @@ WORKDIR /harbor-migration
COPY ./ ./
COPY ./migration.cfg ./
RUN ./prepare.sh
ENTRYPOINT ["./run.sh"]

View File

@ -16,6 +16,10 @@ Migration is a module for migrating database schema between different version of
- show instruction of harbor-migration
```docker run your-image-name help```
- test mysql connection in harbor-migration
```docker run -v /data/database:/var/lib/mysql your-image-name test```
- create backup file in `/path/to/backup`
@ -33,15 +37,14 @@ Migration is a module for migrating database schema between different version of
```docker run -ti -v /data/database:/var/lib/mysql your-image-name up head```
- perform database schema downgrade(downgrade has been disabled)
```docker run -v /data/database:/var/lib/mysql your-image-name down base```
you can use `-v /etc/localtime:/etc/localtime` to sync container timezone with host timezone.
you may change `/data/database` to the mysql volumes path you set in docker-compose.yml.
###migration step
- step 1: stop and remove harbor service
```
docker-compose stop && docker-compose rm -f
docker-compose down
```
- step 2: perform migration operation
- step 3: rebuild newest harbor images and restart service

86
migration/db_meta.py Normal file
View File

@ -0,0 +1,86 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
user_id = sa.Column(sa.Integer, primary_key=True)
username = sa.Column(sa.String(15), unique=True)
email = sa.Column(sa.String(30), unique=True)
password = sa.Column(sa.String(40), nullable=False)
realname = sa.Column(sa.String(20), nullable=False)
comment = sa.Column(sa.String(30))
deleted = sa.Column(sa.Integer, nullable=False, server_default=sa.text("'0'"))
reset_uuid = sa.Column(sa.String(40))
salt = sa.Column(sa.String(40))
sysadmin_flag = sa.Column(sa.Integer)
creation_time = sa.Column(sa.DateTime)
update_time = sa.Column(sa.DateTime)
class Properties(Base):
__tablename__ = 'properties'
k = sa.Column(sa.String(64), primary_key = True)
v = sa.Column(sa.String(128), nullable = False)
class ProjectMember(Base):
__tablename__ = 'project_member'
project_id = sa.Column(sa.Integer(), primary_key = True)
user_id = sa.Column(sa.Integer(), primary_key = True)
role = sa.Column(sa.Integer(), nullable = False)
creation_time = sa.Column(sa.DateTime(), nullable = True)
update_time = sa.Column(sa.DateTime(), nullable = True)
sa.ForeignKeyConstraint(['project_id'], [u'project.project_id'], ),
sa.ForeignKeyConstraint(['role'], [u'role.role_id'], ),
sa.ForeignKeyConstraint(['user_id'], [u'user.user_id'], ),
class UserProjectRole(Base):
__tablename__ = 'user_project_role'
upr_id = sa.Column(sa.Integer(), primary_key = True)
user_id = sa.Column(sa.Integer(), sa.ForeignKey('user.user_id'))
pr_id = sa.Column(sa.Integer(), sa.ForeignKey('project_role.pr_id'))
project_role = relationship("ProjectRole")
class ProjectRole(Base):
__tablename__ = 'project_role'
pr_id = sa.Column(sa.Integer(), primary_key = True)
project_id = sa.Column(sa.Integer(), nullable = False)
role_id = sa.Column(sa.Integer(), nullable = False)
sa.ForeignKeyConstraint(['role_id'], [u'role.role_id'])
sa.ForeignKeyConstraint(['project_id'], [u'project.project_id'])
class Access(Base):
__tablename__ = 'access'
access_id = sa.Column(sa.Integer(), primary_key = True)
access_code = sa.Column(sa.String(1))
comment = sa.Column(sa.String(30))
class Role(Base):
__tablename__ = 'role'
role_id = sa.Column(sa.Integer, primary_key=True)
role_mask = sa.Column(sa.Integer, nullable=False, server_default=sa.text("'0'"))
role_code = sa.Column(sa.String(20))
name = sa.Column(sa.String(20))
class Project(Base):
__tablename__ = 'project'
project_id = sa.Column(sa.Integer, primary_key=True)
owner_id = sa.Column(sa.ForeignKey(u'user.user_id'), nullable=False, index=True)
name = sa.Column(sa.String(30), nullable=False, unique=True)
creation_time = sa.Column(sa.DateTime)
update_time = sa.Column(sa.DateTime)
deleted = sa.Column(sa.Integer, nullable=False, server_default=sa.text("'0'"))
public = sa.Column(sa.Integer, nullable=False, server_default=sa.text("'0'"))
owner = relationship(u'User')

View File

@ -27,58 +27,11 @@ branch_labels = None
depends_on = None
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import mysql
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
from datetime import datetime
from db_meta import *
Session = sessionmaker()
Base = declarative_base()
class Properties(Base):
__tablename__ = 'properties'
k = sa.Column(sa.String(64), primary_key = True)
v = sa.Column(sa.String(128), nullable = False)
class ProjectMember(Base):
__tablename__ = 'project_member'
project_id = sa.Column(sa.Integer(), primary_key = True)
user_id = sa.Column(sa.Integer(), primary_key = True)
role = sa.Column(sa.Integer(), nullable = False)
creation_time = sa.Column(sa.DateTime(), nullable = True)
update_time = sa.Column(sa.DateTime(), nullable = True)
sa.ForeignKeyConstraint(['project_id'], [u'project.project_id'], ),
sa.ForeignKeyConstraint(['role'], [u'role.role_id'], ),
sa.ForeignKeyConstraint(['user_id'], [u'user.user_id'], ),
class UserProjectRole(Base):
__tablename__ = 'user_project_role'
upr_id = sa.Column(sa.Integer(), primary_key = True)
user_id = sa.Column(sa.Integer(), sa.ForeignKey('user.user_id'))
pr_id = sa.Column(sa.Integer(), sa.ForeignKey('project_role.pr_id'))
project_role = relationship("ProjectRole")
class ProjectRole(Base):
__tablename__ = 'project_role'
pr_id = sa.Column(sa.Integer(), primary_key = True)
project_id = sa.Column(sa.Integer(), nullable = False)
role_id = sa.Column(sa.Integer(), nullable = False)
sa.ForeignKeyConstraint(['role_id'], [u'role.role_id'])
sa.ForeignKeyConstraint(['project_id'], [u'project.project_id'])
class Access(Base):
__tablename__ = 'access'
access_id = sa.Column(sa.Integer(), primary_key = True)
access_code = sa.Column(sa.String(1))
comment = sa.Column(sa.String(30))
def upgrade():
"""
update schema&data
@ -86,39 +39,60 @@ def upgrade():
bind = op.get_bind()
session = Session(bind=bind)
#delete M from table access
acc = session.query(Access).filter_by(access_id=1).first()
session.delete(acc)
#create table property
Properties.__table__.create(bind)
session.add(Properties(k='schema_version', v='0.1.1'))
#add column to table user
op.add_column('user', sa.Column('creation_time', sa.DateTime(), nullable=True))
op.add_column('user', sa.Column('sysadmin_flag', sa.Integer(), nullable=True))
op.add_column('user', sa.Column('update_time', sa.DateTime(), nullable=True))
#fill update_time data into table user
session.query(User).update({User.update_time: datetime.now()})
#init all sysadmin_flag = 0
session.query(User).update({User.sysadmin_flag: 0})
#create table project_member
ProjectMember.__table__.create(bind)
#fill data
#fill data into project_member and user
join_result = session.query(UserProjectRole).join(UserProjectRole.project_role).all()
for result in join_result:
session.add(ProjectMember(project_id=result.project_role.project_id, \
user_id=result.user_id, role=result.project_role.role_id, \
creation_time=datetime.now(), update_time=datetime.now()))
#update sysadmin_flag
sys_admin_result = session.query(UserProjectRole).\
join(UserProjectRole.project_role).filter(ProjectRole.role_id ==1).all()
for result in sys_admin_result:
session.query(User).filter(User.user_id == result.user_id).update({User.sysadmin_flag: 1})
#add column to table role
op.add_column('role', sa.Column('role_mask', sa.Integer(), server_default=sa.text(u"'0'"), nullable=False))
#drop user_project_role table before drop project_role
#because foreign key constraint
op.drop_table('user_project_role')
op.drop_table('project_role')
#delete sysadmin from table role
role = session.query(Role).filter_by(role_id=1).first()
session.delete(role)
session.query(Role).update({Role.role_id: Role.role_id - 1})
#delete M from table access
acc = session.query(Access).filter_by(access_id=1).first()
session.delete(acc)
session.query(Access).update({Access.access_id: Access.access_id - 1})
#add column to table project
op.add_column('project', sa.Column('update_time', sa.DateTime(), nullable=True))
#add column to table role
op.add_column('role', sa.Column('role_mask', sa.Integer(), server_default=sa.text(u"'0'"), nullable=False))
#add column to table user
op.add_column('user', sa.Column('creation_time', sa.DateTime(), nullable=True))
op.add_column('user', sa.Column('sysadmin_flag', sa.Integer(), nullable=True))
op.add_column('user', sa.Column('update_time', sa.DateTime(), nullable=True))
#fill update_time data into table project
session.query(Project).update({Project.update_time: datetime.now()})
session.commit()
def downgrade():

View File

@ -1,5 +1,7 @@
#!/bin/bash
export PYTHONPATH=$PYTHONPATH:/harbor-migration
source ./migration.cfg
WAITTIME=60
@ -14,6 +16,7 @@ if [[ $1 = "help" || $1 = "h" || $# = 0 ]]; then
echo "backup perform database backup"
echo "restore perform database restore"
echo "up, upgrade perform database schema upgrade"
echo "test test database connection"
echo "h, help usage help"
exit 0
fi
@ -36,7 +39,7 @@ fi
echo 'Trying to start mysql server...'
DBRUN=0
nohup mysqld 2>&1 > ./nohup.log&
nohup mysqld 2>&1 > ./mysqld.log&
for i in $(seq 1 $WAITTIME); do
echo "$(/usr/sbin/service mysql status)"
if [[ "$(/usr/sbin/service mysql status)" =~ "not running" ]]; then
@ -47,11 +50,19 @@ for i in $(seq 1 $WAITTIME); do
fi
done
if [[ $DBRUN -eq 0 ]]; then
if [[ $DBRUN -eq 0 ]]; then
echo "timeout. Can't run mysql server."
if [[ $1 = "test" ]]; then
echo "test failed."
fi
exit 1
fi
if [[ $1 = "test" ]]; then
echo "test passed."
exit 0
fi
key="$1"
case $key in
up|upgrade)

View File

@ -74,6 +74,7 @@ language = Deutsch
language_en-US = English
language_zh-CN = 中文
language_de-DE = Deutsch
language_ru-RU = Русский
copyright = Copyright
all_rights_reserved = Alle Rechte vorbehalten.
index_desc = Project Harbor ist ein zuverlässiger Enterprise-Class Registry Server. Unternehmen können ihren eigenen Registry Server aufsetzen um die Produktivität und Sicherheit zu erhöhen. Project Harbor kann für Entwicklungs- wie auch Produktiv-Umgebungen genutzt werden.

View File

@ -75,6 +75,7 @@ language = English
language_en-US = English
language_zh-CN = 中文
language_de-DE = Deutsch
language_ru-RU = Русский
copyright = Copyright
all_rights_reserved = All rights reserved.
index_desc = Project Harbor is to build an enterprise-class, reliable registry server. Enterprises can set up a private registry server in their own environment to improve productivity as well as security. Project Harbor can be used in both development and production environment.

View File

@ -16,316 +16,379 @@ var global_messages = {
"username_is_required" : {
"en-US": "Username is required.",
"zh-CN": "用户名为必填项。",
"de-DE": "Benutzername erforderlich."
"de-DE": "Benutzername erforderlich.",
"ru-RU": "Требуется ввести имя пользователя."
},
"username_has_been_taken" : {
"en-US": "Username has been taken.",
"zh-CN": "用户名已被占用。",
"de-DE": "Benutzername bereits vergeben."
"de-DE": "Benutzername bereits vergeben.",
"ru-RU": "Имя пользователя уже используется."
},
"username_is_too_long" : {
"en-US": "Username is too long. (maximum 20 characters)",
"zh-CN": "用户名长度超出限制。最长为20个字符",
"de-DE": "Benutzername ist zu lang. (maximal 20 Zeichen)"
"de-DE": "Benutzername ist zu lang. (maximal 20 Zeichen)",
"ru-RU": "Имя пользователя слишком длинное. (максимум 20 символов)"
},
"username_contains_illegal_chars": {
"en-US": "Username contains illegal character(s).",
"zh-CN": "用户名包含不合法的字符。",
"de-DE": "Benutzername enthält ungültige Zeichen."
"de-DE": "Benutzername enthält ungültige Zeichen.",
"ru-RU": "Имя пользователя содержит недопустимые символы."
},
"email_is_required" : {
"en-US": "Email is required.",
"zh-CN": "邮箱为必填项。",
"de-DE": "E-Mail Adresse erforderlich."
"de-DE": "E-Mail Adresse erforderlich.",
"ru-RU": "Требуется ввести E-mail адрес."
},
"email_contains_illegal_chars" : {
"en-US": "Email contains illegal character(s).",
"zh-CN": "邮箱包含不合法的字符。",
"de-DE": "E-Mail Adresse enthält ungültige Zeichen."
"de-DE": "E-Mail Adresse enthält ungültige Zeichen.",
"ru-RU": "E-mail адрес содержит недопеустимые символы."
},
"email_has_been_taken" : {
"en-US": "Email has been taken.",
"zh-CN": "邮箱已被占用。",
"de-DE": "E-Mail Adresse wird bereits verwendet."
"de-DE": "E-Mail Adresse wird bereits verwendet.",
"ru-RU": "Такой E-mail адрес уже используется."
},
"email_content_illegal" : {
"en-US": "Email format is illegal.",
"zh-CN": "邮箱格式不合法。",
"de-DE": "Format der E-Mail Adresse ist ungültig."
"de-DE": "Format der E-Mail Adresse ist ungültig.",
"ru-RU": "Недопустимый формат E-mail адреса."
},
"email_does_not_exist" : {
"en-US": "Email does not exist.",
"zh-CN": "邮箱不存在。",
"de-DE": "E-Mail Adresse existiert nicht."
"de-DE": "E-Mail Adresse existiert nicht.",
"ru-RU": "E-mail адрес не существует."
},
"realname_is_required" : {
"en-US": "Full name is required.",
"zh-CN": "全名为必填项。",
"de-DE": "Vollständiger Name erforderlich."
"de-DE": "Vollständiger Name erforderlich.",
"ru-RU": "Требуется ввести полное имя."
},
"realname_is_too_long" : {
"en-US": "Full name is too long. (maximum 20 characters)",
"zh-CN": "全名长度超出限制。最长为20个字符",
"de-DE": "Vollständiger Name zu lang. (maximal 20 Zeichen)"
"de-DE": "Vollständiger Name zu lang. (maximal 20 Zeichen)",
"ru-RU": "Полное имя слишком длинное. (максимум 20 символов)"
},
"realname_contains_illegal_chars" : {
"en-US": "Full name contains illegal character(s).",
"zh-CN": "全名包含不合法的字符。",
"de-DE": "Vollständiger Name enthält ungültige Zeichen."
"de-DE": "Vollständiger Name enthält ungültige Zeichen.",
"ru-RU": "Полное имя содержит недопустимые символы."
},
"password_is_required" : {
"en-US": "Password is required.",
"zh-CN": "密码为必填项。",
"de-DE": "Passwort erforderlich."
"de-DE": "Passwort erforderlich.",
"ru-RU": "Требуется ввести пароль."
},
"password_is_invalid" : {
"en-US": "Password is invalid. At least 7 characters with 1 lowercase letter, 1 capital letter and 1 numeric character.",
"zh-CN": "密码无效。至少输入 7个字符且包含 1个小写字母1个大写字母和 1个数字。",
"de-DE": "Passwort ungültig. Mindestens sieben Zeichen bestehend aus einem Kleinbuchstaben, einem Großbuchstaben und einer Zahl"
"de-DE": "Passwort ungültig. Mindestens sieben Zeichen bestehend aus einem Kleinbuchstaben, einem Großbuchstaben und einer Zahl",
"ru-RU": "Такой пароль недопустим. Парольл должен содержать Минимум 7 символов, в которых будет присутствовать по меньшей мере 1 буква нижнего регистра, 1 буква верхнего регистра и 1 цифра"
},
"password_is_too_long" : {
"en-US": "Password is too long. (maximum 20 characters)",
"zh-CN": "密码长度超出限制。最长为20个字符",
"de-DE": "Passwort zu lang. (maximal 20 Zeichen)"
"de-DE": "Passwort zu lang. (maximal 20 Zeichen)",
"ru-RU": "Пароль слишком длинный (максимум 20 символов)"
},
"password_does_not_match" : {
"en-US": "Passwords do not match.",
"zh-CN": "两次密码输入不一致。",
"de-DE": "Passwörter stimmen nicht überein."
"de-DE": "Passwörter stimmen nicht überein.",
"ru-RU": "Пароли не совпадают."
},
"comment_is_too_long" : {
"en-US": "Comment is too long. (maximum 20 characters)",
"zh-CN": "备注长度超出限制。最长为20个字符",
"de-DE": "Kommentar zu lang. (maximal 20 Zeichen)"
"de-DE": "Kommentar zu lang. (maximal 20 Zeichen)",
"ru-RU": "Комментарий слишком длинный. (максимум 20 символов)"
},
"comment_contains_illegal_chars" : {
"en-US": "Comment contains illegal character(s).",
"zh-CN": "备注包含不合法的字符。",
"de-DE": "Kommentar enthält ungültige Zeichen."
"de-DE": "Kommentar enthält ungültige Zeichen.",
"ru-RU": "Комментарий содержит недопустимые символы."
},
"project_name_is_required" : {
"en-US": "Project name is required.",
"zh-CN": "项目名称为必填项。",
"de-DE": "Projektname erforderlich."
"de-DE": "Projektname erforderlich.",
"ru-RU": "Необходимо ввести название Проекта."
},
"project_name_is_too_short" : {
"en-US": "Project name is too short. (minimum 4 characters)",
"zh-CN": "项目名称至少要求 4个字符。",
"de-DE": "Projektname zu kurz. (mindestens 4 Zeichen)"
"de-DE": "Projektname zu kurz. (mindestens 4 Zeichen)",
"ru-RU": "Название проекта слишком короткое. (миниму 4 символа)"
},
"project_name_is_too_long" : {
"en-US": "Project name is too long. (maximum 30 characters)",
"zh-CN": "项目名称长度超出限制。最长为30个字符",
"de-DE": "Projektname zu lang. (maximal 30 Zeichen)"
"de-DE": "Projektname zu lang. (maximal 30 Zeichen)",
"ru-RU": "Название проекта слишком длинное (максимум 30 символов)"
},
"project_name_contains_illegal_chars" : {
"en-US": "Project name contains illegal character(s).",
"zh-CN": "项目名称包含不合法的字符。",
"de-DE": "Projektname enthält ungültige Zeichen."
"de-DE": "Projektname enthält ungültige Zeichen.",
"ru-RU": "Название проекта содержит недопустимые символы."
},
"project_exists" : {
"en-US": "Project exists.",
"zh-CN": "项目已存在。",
"de-DE": "Projekt existiert bereits."
"de-DE": "Projekt existiert bereits.",
"ru-RU": "Такой проект уже существует."
},
"delete_user" : {
"en-US": "Delete User",
"zh-CN": "删除用户",
"de-DE": "Benutzer löschen"
"de-DE": "Benutzer löschen",
"ru-RU": "Удалить пользователя"
},
"are_you_sure_to_delete_user" : {
"en-US": "Are you sure to delete ",
"zh-CN": "确认要删除用户 ",
"de-DE": "Sind Sie sich sicher, dass Sie folgenden Benutzer löschen möchten: "
"de-DE": "Sind Sie sich sicher, dass Sie folgenden Benutzer löschen möchten: ",
"ru-RU": "Вы уверены что хотите удалить пользователя? "
},
"input_your_username_and_password" : {
"en-US": "Please input your username and password.",
"zh-CN": "请输入用户名和密码。",
"de-DE": "Bitte geben Sie ihr Benutzername und Passwort ein."
"de-DE": "Bitte geben Sie ihr Benutzername und Passwort ein.",
"ru-RU": "Введите имя пользователя и пароль."
},
"check_your_username_or_password" : {
"en-US": "Please check your username or password.",
"zh-CN": "请输入正确的用户名或密码。",
"de-DE": "Bitte überprüfen Sie ihren Benutzernamen und Passwort."
"de-DE": "Bitte überprüfen Sie ihren Benutzernamen und Passwort.",
"ru-RU": "Проверьте свои имя пользователя и пароль."
},
"title_login_failed" : {
"en-US": "Login Failed",
"zh-CN": "登录失败",
"de-DE": "Anmeldung fehlgeschlagen"
"de-DE": "Anmeldung fehlgeschlagen",
"ru-RU": "Ошибка входа"
},
"title_change_password" : {
"en-US": "Change Password",
"zh-CN": "修改密码",
"de-DE": "Passwort ändern"
"de-DE": "Passwort ändern",
"ru-RU": "Сменить пароль"
},
"change_password_successfully" : {
"en-US": "Password changed successfully.",
"zh-CN": "密码已修改。",
"de-DE": "Passwort erfolgreich geändert."
"de-DE": "Passwort erfolgreich geändert.",
"ru-RU": "Пароль успешно изменен."
},
"title_forgot_password" : {
"en-US": "Forgot Password",
"zh-CN": "忘记密码",
"de-DE": "Passwort vergessen"
"de-DE": "Passwort vergessen",
"ru-RU": "Забыли пароль?"
},
"email_has_been_sent" : {
"en-US": "Email for resetting password has been sent.",
"zh-CN": "重置密码邮件已发送。",
"de-DE": "Eine E-Mail mit einem Wiederherstellungslink wurde an Sie gesendet."
"de-DE": "Eine E-Mail mit einem Wiederherstellungslink wurde an Sie gesendet.",
"ru-RU": "На ваш E-mail было выслано письмо с инструкциями по сбросу пароля."
},
"send_email_failed" : {
"en-US": "Failed to send Email for resetting password.",
"zh-CN": "重置密码邮件发送失败。",
"de-DE": "Fehler beim Senden der Wiederherstellungs-E-Mail."
"de-DE": "Fehler beim Senden der Wiederherstellungs-E-Mail.",
"ru-RU": "Ошибка отправки сообщения."
},
"please_login_first" : {
"en-US": "Please login first.",
"zh-CN": "请先登录。",
"de-DE": "Bitte melden Sie sich zuerst an."
"de-DE": "Bitte melden Sie sich zuerst an.",
"ru-RU": "Сначала выполните вход в систему."
},
"old_password_is_not_correct" : {
"en-US": "Old password is not correct.",
"zh-CN": "原密码输入不正确。",
"de-DE": "Altes Passwort ist nicht korrekt."
"de-DE": "Altes Passwort ist nicht korrekt.",
"ru-RU": "Старый пароль введен неверно."
},
"please_input_new_password" : {
"en-US": "Please input new password.",
"zh-CN": "请输入新密码。",
"de-DE": "Bitte geben Sie ihr neues Passwort ein."
"de-DE": "Bitte geben Sie ihr neues Passwort ein.",
"ru-RU": "Пожалуйста, введите новый пароль."
},
"invalid_reset_url": {
"en-US": "Invalid URL for resetting password.",
"zh-CN": "无效密码重置链接。",
"de-DE": "Ungültige URL zum Passwort wiederherstellen."
"de-DE": "Ungültige URL zum Passwort wiederherstellen.",
"ru-RU": "Неверный URL для сброса пароля."
},
"reset_password_successfully" : {
"en-US": "Reset password successfully.",
"zh-CN": "密码重置成功。",
"de-DE": "Passwort erfolgreich wiederhergestellt."
"de-DE": "Passwort erfolgreich wiederhergestellt.",
"ru-RU": "Пароль успешно сброшен."
},
"internal_error": {
"en-US": "Internal error.",
"zh-CN": "内部错误,请联系系统管理员。",
"de-DE": "Interner Fehler."
"de-DE": "Interner Fehler.",
"ru-RU": "Внутренняя ошибка."
},
"title_reset_password" : {
"en-US": "Reset Password",
"zh-CN": "重置密码",
"de-DE": "Passwort zurücksetzen"
"de-DE": "Passwort zurücksetzen",
"ru-RU": "Сбросить пароль"
},
"title_sign_up" : {
"en-US": "Sign Up",
"zh-CN": "注册",
"de-DE": "Registrieren"
"de-DE": "Registrieren",
"ru-RU": "Регистрация"
},
"title_add_user": {
"en-US": "Add User",
"zh-CN": "新增用户",
"de-DE": "Benutzer hinzufügen"
"de-DE": "Benutzer hinzufügen",
"ru-RU": "Добавить пользователя"
},
"registered_successfully": {
"en-US": "Signed up successfully.",
"zh-CN": "注册成功。",
"de-DE": "Erfolgreich registriert."
"de-DE": "Erfolgreich registriert.",
"ru-RU": "Регистрация прошла успешно."
},
"registered_failed" : {
"en-US": "Failed to sign up.",
"zh-CN": "注册失败。",
"de-DE": "Registrierung fehlgeschlagen."
"de-DE": "Registrierung fehlgeschlagen.",
"ru-RU": "Ошибка регистрации."
},
"added_user_successfully": {
"en-US": "Added user successfully.",
"zh-CN": "新增用户成功。",
"de-DE": "Benutzer erfolgreich erstellt."
"de-DE": "Benutzer erfolgreich erstellt.",
"ru-RU": "Пользователь успешно добавлен."
},
"added_user_failed": {
"en-US": "Adding user failed.",
"zh-CN": "新增用户失败。",
"de-DE": "Benutzer erstellen fehlgeschlagen."
"de-DE": "Benutzer erstellen fehlgeschlagen.",
"ru-RU": "Ошибка добавления пользователя."
},
"projects": {
"en-US": "Projects",
"zh-CN": "项目",
"de-DE": "Projekte"
"de-DE": "Projekte",
"ru-RU": "Проекты"
},
"repositories" : {
"en-US": "Repositories",
"zh-CN": "镜像仓库",
"de-DE": "Repositories"
"de-DE": "Repositories",
"ru-RU": "Репозитории"
},
"no_repo_exists" : {
"en-US": "No repositories found, please use 'docker push' to upload images.",
"zh-CN": "未发现镜像请用docker push命令上传镜像。",
"de-DE": "Keine Repositories gefunden, bitte benutzen Sie 'docker push' um ein Image hochzuladen."
"de-DE": "Keine Repositories gefunden, bitte benutzen Sie 'docker push' um ein Image hochzuladen.",
"ru-RU": "Репозитории не найдены, используйте команду 'docker push' для добавления образов."
},
"tag" : {
"en-US": "Tag",
"zh-CN": "标签",
"de-DE": "Tag"
"de-DE": "Tag",
"ru-RU": "Метка"
},
"pull_command": {
"en-US": "Pull Command",
"zh-CN": "Pull 命令",
"de-DE": "Pull Befehl"
"de-DE": "Pull Befehl",
"ru-RU": "Команда для скачивания образа"
},
"image_details" : {
"en-US": "Image Details",
"zh-CN": "镜像详细信息",
"de-DE": "Image Details"
"de-DE": "Image Details",
"ru-RU": "Информация об образе"
},
"add_members" : {
"en-US": "Add Member",
"zh-CN": "添加成员",
"de-DE": "Mitglied hinzufügen"
"de-DE": "Mitglied hinzufügen",
"ru-RU": "Добавить Участника"
},
"edit_members" : {
"en-US": "Edit Members",
"zh-CN": "编辑成员",
"de-DE": "Mitglieder bearbeiten"
"de-DE": "Mitglieder bearbeiten",
"ru-RU": "Редактировать Участников"
},
"add_member_failed" : {
"en-US": "Adding Member Failed",
"zh-CN": "添加成员失败",
"de-DE": "Mitglied hinzufügen fehlgeschlagen"
"de-DE": "Mitglied hinzufügen fehlgeschlagen",
"ru-RU": "Ошибка при добавлении нового участника"
},
"please_input_username" : {
"en-US": "Please input a username.",
"zh-CN": "请输入用户名。",
"de-DE": "Bitte geben Sie einen Benutzernamen ein."
"de-DE": "Bitte geben Sie einen Benutzernamen ein.",
"ru-RU": "Пожалуйста, введите имя пользователя."
},
"please_assign_a_role_to_user" : {
"en-US": "Please assign a role to the user.",
"zh-CN": "请为用户分配角色。",
"de-DE": "Bitte weisen Sie dem Benutzer eine Rolle zu."
"de-DE": "Bitte weisen Sie dem Benutzer eine Rolle zu.",
"ru-RU": "Пожалуйста, назначьте роль пользователю."
},
"user_id_exists" : {
"en-US": "User is already a member.",
"zh-CN": "用户已经是成员。",
"de-DE": "Benutzer ist bereits Mitglied."
"de-DE": "Benutzer ist bereits Mitglied.",
"ru-RU": "Пользователь уже является участником."
},
"user_id_does_not_exist" : {
"en-US": "User does not exist.",
"zh-CN": "不存在此用户。",
"de-DE": "Benutzer existiert nicht."
"de-DE": "Benutzer existiert nicht.",
"ru-RU": "Пользователя с таким именем не существует."
},
"insufficient_privileges" : {
"en-US": "Insufficient privileges.",
"zh-CN": "权限不足。",
"de-DE": "Unzureichende Berechtigungen."
"de-DE": "Unzureichende Berechtigungen.",
"ru-RU": "Недостаточно прав."
},
"operation_failed" : {
"en-US": "Operation Failed",
"zh-CN": "操作失败",
"de-DE": "Befehl fehlgeschlagen"
"de-DE": "Befehl fehlgeschlagen",
"ru-RU": "Ошибка при выполнении данной операции"
},
"button_on" : {
"en-US": "On",
"zh-CN": "打开",
"de-DE": "An"
"de-DE": "An",
"ru-RU": "Вкл."
},
"button_off" : {
"en-US": "Off",
"zh-CN": "关闭",
"de-DE": "Aus"
"de-DE": "Aus",
"ru-RU": "Откл."
}
};

View File

@ -0,0 +1,88 @@
page_title_index = Harbor
page_title_sign_in = Войти - Harbor
page_title_project = Проект - Harbor
page_title_item_details = Подробнее - Harbor
page_title_registration = Регистрация - Harbor
page_title_add_user = Добавить пользователя - Harbor
page_title_forgot_password = Забыли пароль - Harbor
title_forgot_password = Забыли пароль
page_title_reset_password = Сбросить пароль - Harbor
title_reset_password = Сбросить пароль
page_title_change_password = Поменять пароль - Harbor
title_change_password = Поменять пароль
page_title_search = Поиск - Harbor
sign_in = Войти
sign_up = Регистрация
add_user = Добавить пользователя
log_out = Выйти
search_placeholder = проекты или репозитории
change_password = Сменить Пароль
username_email = Логин/Email
password = Пароль
forgot_password = Забыли пароль
welcome = Добро пожаловать
my_projects = Мои Проекты
public_projects = Общедоступные Проекты
admin_options = Административные Настройки
project_name = Название Проекта
creation_time = Время Создания
publicity = Публичность
add_project = Добавить Проект
check_for_publicity = Публичный проекта
button_save = Сохранить
button_cancel = Отмена
button_submit = Применить
username = Имя пользователя
email = Email
system_admin = Системный администратор
dlg_button_ok = OK
dlg_button_cancel = Отмена
registration = Регистрация
username_description = Ваше имя пользователя.
email_description = Email адрес, который будет использоваться для сброса пароля.
full_name = Полное Имя
full_name_description = Имя и Фамилия.
password_description = Минимум 7 символов, в которых будет присутствовать по меньшей мере 1 буква нижнего регистра, 1 буква верхнего регистра и 1 цифра.
confirm_password = Подтвердить Пароль
note_to_the_admin = Комментарии
old_password = Старый Пароль
new_password = Новый Пароль
forgot_password_description = Введите Email, который вы использовали для регистрации, вам будет выслано письмо для сброса пароля.
projects = Проекты
repositories = Репозитории
search = Поиск
home = Домой
project = Проект
owner = Владелец
repo = Репозитории
user = Пользователи
logs = Логи
repo_name = Имя Репозитория
repo_tag = Метка
add_members = Добавить Участников
operation = Операция
advance = Расширенный Поиск
all = Все
others = Другие
start_date = Дата Начала
end_date = Дата Окончания
timestamp = Временная метка
role = Роль
reset_email_hint = Нажмите на ссылку ниже для сброса вашего пароля
reset_email_subject = Сброс вашего пароля
language = Русский
language_en-US = English
language_zh-CN = 中文
language_de-DE = Deutsch
language_ru-RU = Русский
copyright = Copyright
all_rights_reserved = Все права защищены.
index_desc = Проект Harbor представляет собой надежный сервер управления docker-образами корпоративного класса. Компании могут использовать данный сервер в своей инфарструктуе для повышения производительности и безопасности . Проект Harbor может использоваться как в среде разработки так и в продуктивной среде.
index_desc_0 = Основные преимущества данного решения:
index_desc_1 = 1. Безопасность: Хранение интеллектуальной собственности внутри организации.
index_desc_2 = 2. Эффективность: сервер хранения docker образов устанавливается в рамках внутренней сети организации, и может значительно сократить расход Интернет траффика
index_desc_3 = 3. Управление доступом: реализована модель RBAC (Ролевая модель управление доступом). Управление пользователями может быть интегрировано с существующими корпоративными сервисами идентификациями такими как AD/LDAP.
index_desc_4 = 4. Аудит: Любой доступ к хранилищу логируется и может быть использован для последующего анализа.
index_desc_5 = 5. GUI-интерфейс: удобная, единая консоль управления.
index_title = Сервер управления docker-образами корпоративного класса

View File

@ -75,6 +75,7 @@ language = 中文
language_en-US = English
language_zh-CN = 中文
language_de-DE = Deutsch
language_ru-RU = Русский
copyright = 版权所有
all_rights_reserved = 保留所有权利。
index_desc = Harbor是可靠的企业级Registry服务器。企业用户可使用Harbor搭建私有容器Registry服务提高生产效率和安全度既可应用于生产环境也可以在开发环境中使用。

View File

@ -69,7 +69,8 @@ AjaxUtil.prototype.exec = function(){
var SUPPORT_LANGUAGES = {
"en-US": "English",
"zh-CN": "Chinese",
"de-DE": "German"
"de-DE": "German",
"ru-RU": "Russian"
};
var DEFAULT_LANGUAGE = "en-US";

View File

@ -37,6 +37,7 @@
<li><a href="/language?lang=en-US">{{i18n .Lang "language_en-US"}}</a></li>
<li><a href="/language?lang=zh-CN">{{i18n .Lang "language_zh-CN"}}</a></li>
<li><a href="/language?lang=de-DE">{{i18n .Lang "language_de-DE"}}</a></li>
<li><a href="/language?lang=ru-RU">{{i18n .Lang "language_ru-RU"}}</a></li>
</ul>
</li>
</ul>