This commit is contained in:
Fuhui Peng (c) 2017-11-17 16:34:15 +08:00
commit 6fb9068034
79 changed files with 286 additions and 115 deletions

View File

@ -19,7 +19,7 @@ env:
MYSQL_PWD: root123
MYSQL_DATABASE: registry
SQLITE_FILE: /tmp/registry.db
ADMIN_SERVER_URL: http://127.0.0.1:8888
ADMINSERVER_URL: http://127.0.0.1:8888
DOCKER_COMPOSE_VERSION: 1.7.1
HARBOR_ADMIN: admin
HARBOR_ADMIN_PASSWD: Harbor12345

Binary file not shown.

Before

Width:  |  Height:  |  Size: 163 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 105 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -70,14 +70,28 @@ You can create a project after you signed in. Check on the "Access Level" checkb
![create project](img/new_create_project.png)
After the project is created, you can browse repositories, users and logs using the navigation tab.
After the project is created, you can browse repositories, members, logs, replication and configuration 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/log_search_advanced.png)
![browse project](img/new_project_log.png)
Project properties can be changed by clicking "Configuration".
* To make all repositories under the project accessible to everyone, select the `Public` checkbox.
* To prevent un-signed images under the project from being pulled, select the `Enable content trust` checkbox.
* To prevent vulnerable images under the project from being pulled, select the `Prevent vulnerable images from running` checkbox and change the severity level of vulnerabilities. Images cannot be pulled if their level equals to or higher than the currently selected level.
* To activate an immediate vulnerability scan on new images that are pushed to the project, select the `Automatically scan images on push` checkbox.
![browse project](img/project_configuration.png)
## Managing members of a project
### Adding members
You can add members with different roles to an existing project.
@ -98,7 +112,7 @@ There may be a bit of delay during replication according to the situation of the
**Note:** The replication feature is incompatible between Harbor instance before version 0.3.5(included) and after version 0.3.5.
Start replication by creating a rule. Click "Add Replication Rule" on the "Replication" tab, fill in the necessary fields, if there is no endpoint in the list, you need to create one, and then click "OK", a rule for this project will be created. If "Enable" is chosen, the project will be replicated to the remote immediately.
Replication can be configured by creating a rule. Click "Add Replication Rule" on the "Replication" tab and fill in the necessary fields. If there is no endpoint available in the list, you need to create one. Uncheck "Verify Remote Cert" if the remote registry uses a self-signed or an untrusted certificate. Click "OK" to create a replication rule for this project. If "Enable" is chosen, the project will be replicated to the remote registry immediately.
![browse project](img/new_create_rule.png)
@ -145,10 +159,6 @@ Use the **Project Creation** drop-down menu to set which users can create projec
You can manage whether a user can sign up for a new account. This option is not available if you use LDAP authentication.
![browse project](img/new_self_reg.png)
### Managing verification of remote certificate
You can choose whether to verify remote endpoint's certification. You may need to disable certificate verification if the remote registry uses a self-signed or an untrusted certificate.
![browse project](img/new_remote_cert.png)
### Managing email settings
You can change Harbor's email settings, the mail server is used to send out responses to users who request to reset their password.
![browse project](img/new_config_email.png)

View File

@ -2,7 +2,7 @@ FROM vmware/photon:1.0
#The Docker Daemon has to be running with storage backend btrfs when building the image
RUN tdnf distro-sync -y || echo \
RUN tdnf distro-sync -y \
&& tdnf install -y sed shadow procps-ng gawk gzip sudo net-tools \
&& groupadd -r -g 10000 mysql && useradd --no-log-init -r -g 10000 -u 10000 mysql \
&& tdnf install -y mariadb-server mariadb \

View File

@ -1,13 +1,13 @@
FROM vmware/photon:1.0
RUN tdnf distro-sync -y || echo \
RUN tdnf distro-sync -y \
&& tdnf install -y nginx \
&& ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log \
&& mkdir -p /var/run \
&& tdnf clean all
EXPOSE 80
VOLUME /var/cache/nginx /var/log/nginx /run
STOPSIGNAL SIGQUIT
CMD ["nginx", "-g", "daemon off;"]

View File

@ -3,7 +3,7 @@ FROM vmware/photon:1.0
ENV PGDATA /var/lib/postgresql/data
RUN touch /etc/localtime.bak \
&& tdnf distro-sync -y || echo \
&& tdnf distro-sync -y \
&& tdnf install -y sed shadow gzip postgresql\
&& groupadd -r postgres --gid=999 \
&& useradd -r -g postgres --uid=999 postgres \

View File

@ -1,3 +1,4 @@
PORT=8080
LOG_LEVEL=debug
EXT_ENDPOINT=$ui_url
AUTH_MODE=$auth_mode
@ -42,5 +43,5 @@ RESET=false
UAA_ENDPOINT=$uaa_endpoint
UAA_CLIENTID=$uaa_clientid
UAA_CLIENTSECRET=$uaa_clientsecret
UI_URL=http://ui
JOBSERVICE_URL=http://jobservice
UI_URL=http://ui:8080
JOBSERVICE_URL=http://jobservice:8080

View File

@ -22,4 +22,4 @@ clair:
attempts: 3
renotifyinterval: 2h
http:
endpoint: http://ui/service/notifications/clair
endpoint: http://ui:8080/service/notifications/clair

View File

@ -2,4 +2,4 @@ appname = jobservice
runmode = dev
[dev]
httpport = 80
httpport = 8080

View File

@ -2,4 +2,5 @@ LOG_LEVEL=debug
CONFIG_PATH=/etc/jobservice/app.conf
UI_SECRET=$ui_secret
JOBSERVICE_SECRET=$jobservice_secret
ADMINSERVER_URL=http://adminserver:8080
GODEBUG=netdns=cgo

View File

@ -18,7 +18,7 @@ http {
}
upstream ui {
server ui:80;
server ui:8080;
}
log_format timed_combined '$$remote_addr - '

View File

@ -18,7 +18,7 @@ http {
}
upstream ui {
server ui:80;
server ui:8080;
}
log_format timed_combined '$$remote_addr - '

View File

@ -29,7 +29,7 @@ notifications:
endpoints:
- name: harbor
disabled: false
url: http://ui/service/notifications
url: http://ui:8080/service/notifications
timeout: 3000ms
threshold: 5
backoff: 1s

View File

@ -3,4 +3,4 @@ runmode = dev
enablegzip = true
[dev]
httpport = 80
httpport = 8080

View File

@ -3,4 +3,5 @@ CONFIG_PATH=/etc/ui/app.conf
UI_SECRET=$ui_secret
JOBSERVICE_SECRET=$jobservice_secret
GODEBUG=netdns=cgo
ADMINSERVER_URL=http://adminserver:8080
UAA_CA_ROOT=/etc/ui/certificates/uaa_ca.pem

View File

@ -16,8 +16,6 @@ services:
- harbor-notary
volumes:
- ./common/config/notary:/config
entrypoint: /usr/bin/env sh
command: -c "/migrations/migrate.sh && notary-server -config=/config/server-config.json -logf=logfmt"
depends_on:
- notary-db
- notary-signer
@ -39,8 +37,6 @@ services:
- ./common/config/notary:/config
env_file:
- ./common/config/notary/signer_env
entrypoint: /usr/bin/env sh
command: -c "/migrations/migrate.sh && notary-signer -config=/config/signer-config.json -logf=logfmt"
depends_on:
- notary-db
logging:

View File

@ -1,11 +1,14 @@
FROM vmware/photon:1.0
RUN tdnf erase vim -y \
&& tdnf distro-sync -y || echo \
&& tdnf distro-sync -y \
&& tdnf install -y sudo \
&& tdnf clean all \
&& groupadd -r -g 10000 harbor && useradd --no-log-init -r -g 10000 -u 10000 harbor \
&& mkdir /harbor/
COPY ./make/dev/adminserver/harbor_adminserver /harbor/
COPY ./make/dev/adminserver/harbor_adminserver ./make/photon/adminserver/start.sh /harbor/
HEALTHCHECK CMD curl -s -o /dev/null -w "%{http_code}" 127.0.0.1:8080/api/configurations|grep 401
RUN chmod u+x /harbor/harbor_adminserver
RUN chmod u+x /harbor/harbor_adminserver /harbor/start.sh
WORKDIR /harbor/
ENTRYPOINT ["/harbor/harbor_adminserver"]
ENTRYPOINT ["/harbor/start.sh"]

View File

@ -0,0 +1,5 @@
#!/bin/sh
if [ -d /etc/adminserver ]; then
chown -R 10000:10000 /etc/adminserver
fi
sudo -E -u \#10000 "/harbor/harbor_adminserver"

View File

@ -1,5 +1,6 @@
FROM vmware/photon:1.0
RUN tdnf distro-sync -y \
&& tdnf erase vim -y \
&& tdnf install -y git shadow sudo bzr rpm xz python-xml \
@ -9,11 +10,20 @@ RUN tdnf distro-sync -y \
&& useradd --no-log-init -m -r -g 10000 -u 10000 clair
COPY clair /clair2.0.1/
COPY docker-entrypoint.sh /docker-entrypoint.sh
COPY dumb-init /dumb-init
VOLUME /config
EXPOSE 6060 6061
RUN chown -R 10000:10000 /clair2.0.1 \
&& chmod u+x /clair2.0.1/clair \
&& chmod u+x /docker-entrypoint.sh
&& chmod u+x /docker-entrypoint.sh \
&& chmod +x /dumb-init
HEALTHCHECK --interval=30s --timeout=10s --retries=3 CMD curl -sS 127.0.0.1:6061/health || exit 1
USER clair
ENTRYPOINT ["/docker-entrypoint.sh"]

View File

@ -1,4 +1,4 @@
#!/bin/bash
set -e
/clair2.0.1/clair -config /config/config.yaml
/dumb-init -- /clair2.0.1/clair -config /config/config.yaml
set +e

BIN
make/photon/clair/dumb-init Executable file

Binary file not shown.

View File

@ -1,10 +1,14 @@
FROM vmware/photon:1.0
RUN mkdir /harbor/ \
&& tdnf distro-sync -y || echo \
&& tdnf clean all
COPY ./make/dev/jobservice/harbor_jobservice /harbor/
&& tdnf distro-sync -y \
&& tdnf install sudo -y \
&& tdnf clean all \
&& groupadd -r -g 10000 harbor && useradd --no-log-init -r -g 10000 -u 10000 harbor
HEALTHCHECK CMD curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/api/jobs/replication/1/log|grep 401
RUN chmod u+x /harbor/harbor_jobservice
COPY ./make/photon/jobservice/start.sh ./make/dev/jobservice/harbor_jobservice /harbor/
RUN chmod u+x /harbor/harbor_jobservice /harbor/start.sh
WORKDIR /harbor/
ENTRYPOINT ["/harbor/harbor_jobservice"]
ENTRYPOINT ["/harbor/start.sh"]

View File

@ -0,0 +1,9 @@
#!/bin/sh
if [ -d /etc/jobservice/ ]; then
chown -R 10000:10000 /etc/jobservice/
fi
if [ -d /var/log/jobs ]; then
chown -R 10000:10000 /var/log/jobs/
fi
sudo -E -u \#10000 "/harbor/harbor_jobservice"

View File

@ -1,6 +1,6 @@
FROM vmware/photon:1.0
RUN tdnf distro-sync -y || echo \
RUN tdnf distro-sync -y \
&& tdnf install -y cronie rsyslog logrotate shadow tar gzip sudo net-tools\
&& mkdir /etc/rsyslog.d/ \
&& mkdir /var/spool/rsyslog \
@ -17,7 +17,7 @@ RUN mv /etc/cron.daily/logrotate /etc/cron.hourly/logrotate
COPY start.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/start.sh && \
chown -R 10000:10000 /run
chown -R 10000:10000 /etc/rsyslog.conf /etc/rsyslog.d/ /run
HEALTHCHECK CMD netstat -ltu|grep 10514

View File

@ -35,7 +35,7 @@ cur=$PWD
# the temp folder to store notary source code...
TEMP=`mktemp -d /$TMPDIR/notary.XXXXXX`
git clone -b $VERSION https://github.com/docker/notary.git $TEMP
git clone -b $VERSION https://github.com/theupdateframework/notary.git $TEMP
echo 'build the notary binary bases on the golang:1.7.3...'
cp binary.Dockerfile $TEMP
@ -56,4 +56,4 @@ docker build -f server.Dockerfile -t $SERVER_PHOTONIMAGE .
docker build -f signer.Dockerfile -t $SIGNER_PHOTONIMAGE .
echo 'Push image to docker hub.'
../../pushimage.sh $PHOTONIMAGE $USERNAME $PASSWORD
../../pushimage.sh $PHOTONIMAGE $USERNAME $PASSWORD

View File

@ -0,0 +1,3 @@
#!/bin/sh
chown 10000:10000 -R /config
sudo -E -u \#10000 sh -c "/usr/bin/env /migrations/migrate.sh && /bin/notary-server -config=/config/server-config.json -logf=logfmt"

View File

@ -2,10 +2,15 @@ FROM vmware/photon:1.0
RUN tdnf distro-sync -y \
&& tdnf erase vim -y \
&& tdnf clean all
&& tdnf install -y shadow sudo \
&& tdnf clean all \
&& groupadd -r -g 10000 notary \
&& useradd --no-log-init -r -g 10000 -u 10000 notary
COPY ./binary/notary-server /bin/notary-server
COPY ./migrate /bin/migrate
COPY ./migrations/ /migrations/
COPY ./server-start.sh /bin/server-start.sh
RUN chmod u+x /bin/notary-server /migrations/migrate.sh /bin/migrate /bin/server-start.sh
ENV SERVICE_NAME=notary_server
ENTRYPOINT [ "notary-server" ]
ENTRYPOINT [ "/bin/server-start.sh" ]

View File

@ -0,0 +1,3 @@
#!/bin/sh
chown 10000:10000 -R /config
sudo -E -u \#10000 sh -c "/usr/bin/env && /migrations/migrate.sh && /bin/notary-signer -config=/config/signer-config.json -logf=logfmt"

View File

@ -2,10 +2,15 @@ FROM vmware/photon:1.0
RUN tdnf distro-sync -y \
&& tdnf erase vim -y \
&& tdnf clean all
&& tdnf install -y shadow sudo \
&& tdnf clean all \
&& groupadd -r -g 10000 notary \
&& useradd --no-log-init -r -g 10000 -u 10000 notary
COPY ./binary/notary-signer /bin/notary-signer
COPY ./migrate /bin/migrate
COPY ./migrations/ /migrations/
COPY ./signer-start.sh /bin/signer-start.sh
RUN chmod u+x /bin/notary-signer /migrations/migrate.sh /bin/migrate /bin/signer-start.sh
ENV SERVICE_NAME=notary_signer
ENTRYPOINT [ "notary-signer" ]
ENTRYPOINT [ "/bin/signer-start.sh" ]

View File

@ -2,16 +2,17 @@ FROM vmware/photon:1.0
RUN tdnf distro-sync -y \
&& tdnf erase vim -y \
&& tdnf install sudo -y \
&& tdnf clean all \
&& groupadd -r -g 10000 harbor && useradd --no-log-init -r -g 10000 -u 10000 harbor \
&& mkdir /harbor/
COPY ./make/dev/ui/harbor_ui /harbor/
HEALTHCHECK CMD curl -s -o /dev/null -w "%{http_code}" 127.0.0.1:8080/api/systeminfo|grep 200
COPY ./make/dev/ui/harbor_ui ./src/favicon.ico ./make/photon/ui/start.sh ./VERSION /harbor/
COPY ./src/ui/views /harbor/views
COPY ./src/ui/static /harbor/static
COPY ./src/favicon.ico /harbor/favicon.ico
COPY ./VERSION /harbor/VERSION
RUN chmod u+x /harbor/harbor_ui
RUN chmod u+x /harbor/start.sh /harbor/harbor_ui
WORKDIR /harbor/
ENTRYPOINT ["/harbor/harbor_ui"]
ENTRYPOINT ["/harbor/start.sh"]

6
make/photon/ui/start.sh Normal file
View File

@ -0,0 +1,6 @@
#!/bin/sh
if [ -d /etc/ui/ ]; then
chown -R 10000:10000 /etc/ui/
fi
sudo -E -u \#10000 "/harbor/harbor_ui"

View File

@ -72,8 +72,8 @@ func TestMain(t *testing.T) {
}
defer server.Close()
if err := os.Setenv("ADMIN_SERVER_URL", server.URL); err != nil {
t.Fatalf("failed to set env %s: %v", "ADMIN_SERVER_URL", err)
if err := os.Setenv("ADMINSERVER_URL", server.URL); err != nil {
t.Fatalf("failed to set env %s: %v", "ADMINSERVER_URL", err)
}
secretKeyPath := "/tmp/secretkey"

View File

@ -36,7 +36,7 @@ import (
)
var (
notaryCachePath = "/root/notary"
notaryCachePath = "/etc/ui/notary-cache"
trustPin trustpinning.TrustPinConfig
mockRetriever notary.PassRetriever
)

View File

@ -47,7 +47,7 @@ func TestMain(m *testing.M) {
panic(err)
}
defer adminServer.Close()
if err := os.Setenv("ADMIN_SERVER_URL", adminServer.URL); err != nil {
if err := os.Setenv("ADMINSERVER_URL", adminServer.URL); err != nil {
panic(err)
}
if err := config.Init(); err != nil {

View File

@ -45,7 +45,7 @@ func Init() error {
//init key provider
initKeyProvider()
adminServerURL := os.Getenv("ADMIN_SERVER_URL")
adminServerURL := os.Getenv("ADMINSERVER_URL")
if len(adminServerURL) == 0 {
adminServerURL = "http://adminserver"
}
@ -163,7 +163,7 @@ func ExtEndpoint() (string, error) {
// InternalTokenServiceEndpoint ...
func InternalTokenServiceEndpoint() string {
return "http://ui/service/token"
return LocalUIURL() + "/service/token"
}
// ClairEndpoint returns the end point of clair instance, by default it's the one deployed within Harbor.

View File

@ -30,8 +30,8 @@ func TestConfig(t *testing.T) {
}
defer server.Close()
if err := os.Setenv("ADMIN_SERVER_URL", server.URL); err != nil {
t.Fatalf("failed to set env %s: %v", "ADMIN_SERVER_URL", err)
if err := os.Setenv("ADMINSERVER_URL", server.URL); err != nil {
t.Fatalf("failed to set env %s: %v", "ADMINSERVER_URL", err)
}
secretKeyPath := "/tmp/secretkey"

View File

@ -55,8 +55,8 @@ func TestMain(m *testing.M) {
log.Fatalf("failed to create a mock admin server: %v", err)
}
defer server.Close()
if err := os.Setenv("ADMIN_SERVER_URL", server.URL); err != nil {
log.Fatalf("failed to set env %s: %v", "ADMIN_SERVER_URL", err)
if err := os.Setenv("ADMINSERVER_URL", server.URL); err != nil {
log.Fatalf("failed to set env %s: %v", "ADMINSERVER_URL", err)
}
secretKeyPath := "/tmp/secretkey"
_, err = test.GenerateKey(secretKeyPath)

View File

@ -290,6 +290,7 @@ func (c *Checker) createProject(project *models.Project) error {
}
req.SetBasicAuth(c.dstUsr, c.dstPwd)
req.Header.Set(http.CanonicalHeaderKey("content-type"), "application/json")
client := &http.Client{
Transport: &http.Transport{

View File

@ -71,8 +71,8 @@ func TestMain(t *testing.T) {
}
defer server.Close()
if err := os.Setenv("ADMIN_SERVER_URL", server.URL); err != nil {
t.Fatalf("failed to set env %s: %v", "ADMIN_SERVER_URL", err)
if err := os.Setenv("ADMINSERVER_URL", server.URL); err != nil {
t.Fatalf("failed to set env %s: %v", "ADMINSERVER_URL", err)
}
secretKeyPath := "/tmp/secretkey"

View File

@ -33,8 +33,8 @@ func TestGetClient(t *testing.T) {
}
defer server.Close()
if err := os.Setenv("ADMIN_SERVER_URL", server.URL); err != nil {
t.Fatalf("failed to set env %s: %v", "ADMIN_SERVER_URL", err)
if err := os.Setenv("ADMINSERVER_URL", server.URL); err != nil {
t.Fatalf("failed to set env %s: %v", "ADMINSERVER_URL", err)
}
err = config.Init()
if err != nil {

View File

@ -62,7 +62,7 @@ func Init() error {
//init key provider
initKeyProvider()
adminServerURL := os.Getenv("ADMIN_SERVER_URL")
adminServerURL := os.Getenv("ADMINSERVER_URL")
if len(adminServerURL) == 0 {
adminServerURL = "http://adminserver"
}

View File

@ -29,8 +29,8 @@ func TestConfig(t *testing.T) {
}
defer server.Close()
if err := os.Setenv("ADMIN_SERVER_URL", server.URL); err != nil {
t.Fatalf("failed to set env %s: %v", "ADMIN_SERVER_URL", err)
if err := os.Setenv("ADMINSERVER_URL", server.URL); err != nil {
t.Fatalf("failed to set env %s: %v", "ADMINSERVER_URL", err)
}
secretKeyPath := "/tmp/secretkey"

View File

@ -40,7 +40,7 @@ func TestMain(m *testing.M) {
panic(err)
}
defer adminServer.Close()
if err := os.Setenv("ADMIN_SERVER_URL", adminServer.URL); err != nil {
if err := os.Setenv("ADMINSERVER_URL", adminServer.URL); err != nil {
panic(err)
}
if err := config.Init(); err != nil {
@ -129,7 +129,7 @@ func TestPMSPolicyChecker(t *testing.T) {
panic(err)
}
defer adminServer.Close()
if err := os.Setenv("ADMIN_SERVER_URL", adminServer.URL); err != nil {
if err := os.Setenv("ADMINSERVER_URL", adminServer.URL); err != nil {
panic(err)
}
if err := config.Init(); err != nil {

View File

@ -41,7 +41,7 @@ func TestMain(m *testing.M) {
}
defer server.Close()
if err := os.Setenv("ADMIN_SERVER_URL", server.URL); err != nil {
if err := os.Setenv("ADMINSERVER_URL", server.URL); err != nil {
panic(err)
}
if err := config.Init(); err != nil {

View File

@ -1,6 +1,6 @@
{
"name": "harbor-ui",
"version": "0.4.0",
"version": "0.5.0",
"description": "Harbor shared UI components based on Clarity and Angular4",
"scripts": {
"start": "ng serve --host 0.0.0.0 --port 4500 --proxy-config proxy.config.json",

View File

@ -1,6 +1,6 @@
{
"name": "harbor-ui",
"version": "0.4.0",
"version": "0.5.9",
"description": "Harbor shared UI components based on Clarity and Angular4",
"author": "VMware",
"module": "index.js",

View File

@ -11,22 +11,22 @@ export const PROJECT_POLICY_CONFIG_TEMPLATE = `
</div>
</div>
</div>
<div class="form-group">
<div class="form-group" *ngIf="withNotary || withClair">
<label for="projectPolicyForm">{{ 'PROJECT_CONFIG.SECURITY' | translate }}</label>
<div class="form-content">
<div>
<div *ngIf="withNotary">
<clr-checkbox [(ngModel)]="projectPolicy.ContentTrust" name="content-trust"
[clrDisabled]="!hasProjectAdminRole">{{ 'PROJECT_CONFIG.CONTENT_TRUST_TOGGLE' | translate }}</clr-checkbox>
<div class="chk-explain"><label> {{ 'PROJECT_CONFIG.CONTENT_TRUST_POLCIY' | translate }} </label></div>
</div>
<div>
<div *ngIf="withClair">
<clr-checkbox [(ngModel)]="projectPolicy.PreventVulImg" name="prevent-vulenrability-image" [clrDisabled]="!hasProjectAdminRole">{{ 'PROJECT_CONFIG.PREVENT_VULNERABLE_TOGGLE' | translate }}</clr-checkbox>
<div class="chk-explain">
<label>
<div id="severity-blk">
<div>{{ 'PROJECT_CONFIG.PREVENT_VULNERABLE_1' | translate }}</div>
<div class="select">
<select id="severity" name="severity" [(ngModel)]="projectPolicy.PreventVulImgServerity" [disabled]="!projectPolicy.PreventVulImg">
<select id="severity" name="severity" [(ngModel)]="projectPolicy.PreventVulImgSeverity" [disabled]="!projectPolicy.PreventVulImg">
<option *ngFor='let s of severityOptions' [ngValue]="s.severity">{{ s.severityLevel | translate | uppercase }}</option>
</select>
</div>
@ -37,7 +37,7 @@ export const PROJECT_POLICY_CONFIG_TEMPLATE = `
</div>
</div>
</div>
<div class="form-group">
<div class="form-group" *ngIf="withClair">
<label for="projectPolicyForm">{{ 'PROJECT_CONFIG.SCAN' | translate }}</label>
<div class="form-content">
<clr-checkbox [(ngModel)]="projectPolicy.ScanImgOnPush" name="scan-image-on-push" [clrDisabled]="!hasProjectAdminRole">{{ 'PROJECT_CONFIG.AUTOSCAN_TOGGLE' | translate }}</clr-checkbox>

View File

@ -1,3 +1,4 @@
import { SystemInfoService, SystemInfoDefaultService } from './../service/system-info.service';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ErrorHandler } from '../error-handler/error-handler';
import { ConfirmationDialogComponent } from '../confirmation-dialog/confirmation-dialog.component';
@ -5,13 +6,88 @@ import { ProjectPolicyConfigComponent } from './project-policy-config.component'
import { SharedModule } from '../shared/shared.module';
import { ProjectService, ProjectDefaultService} from '../service/project.service';
import { SERVICE_CONFIG, IServiceConfig} from '../service.config';
import { SystemInfo } from '../service/interface';
import { Project } from './project';
describe('ProjectPolicyConfigComponent', () => {
let systemInfoService: SystemInfoService;
let projectPolicyService: ProjectService;
let spySystemInfo: jasmine.Spy;
let spyProjectPolicies: jasmine.Spy;
let mockSystemInfo: SystemInfo[] = [
{
'with_clair': true,
'with_notary': true,
'with_admiral': false,
'admiral_endpoint': 'NA',
'auth_mode': 'db_auth',
'registry_url': '10.112.122.56',
'project_creation_restriction': 'everyone',
'self_registration': true,
'has_ca_root': false,
'harbor_version': 'v1.1.1-rc1-160-g565110d'
},
{
'with_clair': false,
'with_notary': false,
'with_admiral': false,
'admiral_endpoint': 'NA',
'auth_mode': 'db_auth',
'registry_url': '10.112.122.56',
'project_creation_restriction': 'everyone',
'self_registration': true,
'has_ca_root': false,
'harbor_version': 'v1.1.1-rc1-160-g565110d'
}
];
let mockPorjectPolicies: Project[] | any[] = [
{
'project_id': 1,
'owner_id': 1,
'name': 'library',
'creation_time': '2017-11-03T02:37:24Z',
'update_time': '2017-11-03T02:37:24Z',
'deleted': 0,
'owner_name': '',
'togglable': false,
'current_user_role_id': 0,
'repo_count': 0,
'metadata': {
'public': 'true'
}
},
{
'project_id': 2,
'owner_id': 1,
'name': 'test',
'creation_time': '2017-11-03T02:37:24Z',
'update_time': '2017-11-03T02:37:24Z',
'deleted': 0,
'owner_name': '',
'togglable': false,
'current_user_role_id': 0,
'repo_count': 0,
'metadata': {
'auto_scan': 'true',
'enable_content_trust': 'true',
'prevent_vul': 'true',
'public': 'true',
'severity': 'low'
}
}
];
let component: ProjectPolicyConfigComponent;
let fixture: ComponentFixture<ProjectPolicyConfigComponent>;
let config: IServiceConfig = {
projectPolicyEndpoint: '/api/projects/testing/:id/'
projectPolicyEndpoint: '/api/projects/testing',
systemInfoEndpoint: '/api/systeminfo/testing',
};
beforeEach(async(() => {
@ -25,7 +101,8 @@ describe('ProjectPolicyConfigComponent', () => {
providers: [
ErrorHandler,
{ provide: SERVICE_CONFIG, useValue: config },
{ provide: ProjectService, useClass: ProjectDefaultService }
{ provide: ProjectService, useClass: ProjectDefaultService },
{ provide: SystemInfoService, useClass: SystemInfoDefaultService}
]
})
.compileComponents();
@ -36,6 +113,13 @@ describe('ProjectPolicyConfigComponent', () => {
component = fixture.componentInstance;
component.projectId = 1;
component.hasProjectAdminRole = true;
systemInfoService = fixture.debugElement.injector.get(SystemInfoService);
projectPolicyService = fixture.debugElement.injector.get(ProjectService);
spySystemInfo = spyOn(systemInfoService, 'getSystemInfo').and.returnValues(Promise.resolve(mockSystemInfo[0]));
spyProjectPolicies = spyOn(projectPolicyService, 'getProject').and.returnValues(Promise.resolve(mockPorjectPolicies[0]));
fixture.detectChanges();
});

View File

@ -14,19 +14,20 @@ import { ConfirmationAcknowledgement } from '../confirmation-dialog/confirmation
import { TranslateService } from '@ngx-translate/core';
import { Project } from './project';
import {SystemInfo, SystemInfoService} from '../service/index';
export class ProjectPolicy {
Public: boolean;
ContentTrust: boolean;
PreventVulImg: boolean;
PreventVulImgServerity: string;
PreventVulImgSeverity: string;
ScanImgOnPush: boolean;
constructor() {
this.Public = false;
this.ContentTrust = false;
this.PreventVulImg = false;
this.PreventVulImgServerity = 'low';
this.PreventVulImgSeverity = 'low';
this.ScanImgOnPush = false;
}
@ -34,7 +35,7 @@ export class ProjectPolicy {
this.Public = pro.metadata.public === 'true' ? true : false;
this.ContentTrust = pro.metadata.enable_content_trust === 'true' ? true : false;
this.PreventVulImg = pro.metadata.prevent_vul === 'true' ? true : false;
if (pro.metadata.severity) { this.PreventVulImgServerity = pro.metadata.severity; };
if (pro.metadata.severity) { this.PreventVulImgSeverity = pro.metadata.severity; };
this.ScanImgOnPush = pro.metadata.auto_scan === 'true' ? true : false;
};
}
@ -42,7 +43,7 @@ export class ProjectPolicy {
@Component({
selector: 'hbr-project-policy-config',
template: PROJECT_POLICY_CONFIG_TEMPLATE,
styles: [PROJECT_POLICY_CONFIG_STYLE]
styles: [PROJECT_POLICY_CONFIG_STYLE],
})
export class ProjectPolicyConfigComponent implements OnInit {
onGoing = false;
@ -54,6 +55,7 @@ export class ProjectPolicyConfigComponent implements OnInit {
@ViewChild('cfgConfirmationDialog') confirmationDlg: ConfirmationDialogComponent;
systemInfo: SystemInfo;
orgProjectPolicy = new ProjectPolicy();
projectPolicy = new ProjectPolicy();
@ -68,25 +70,41 @@ export class ProjectPolicyConfigComponent implements OnInit {
private errorHandler: ErrorHandler,
private translate: TranslateService,
private projectService: ProjectService,
private systemInfoService: SystemInfoService,
) {}
ngOnInit(): void {
// assert if project id exist
if (!this.projectId) {
this.errorHandler.error('Project ID cannot be unset.');
return;
}
// get system info
toPromise<SystemInfo>(this.systemInfoService.getSystemInfo())
.then(systemInfo => this.systemInfo = systemInfo)
.catch(error => this.errorHandler.error(error));
// retrive project level policy data
this.retrieve();
}
public get withNotary(): boolean {
return this.systemInfo ? this.systemInfo.with_notary : false;
}
public get withClair(): boolean {
return this.systemInfo ? this.systemInfo.with_clair : false;
}
retrieve(state?: State): any {
toPromise<Project>(this.projectService.
getProject(this.projectId))
.then(
response => {
this.orgProjectPolicy.initByProject(response);
this.projectPolicy.initByProject(response);
})
.catch(error => this.errorHandler.error(error));
toPromise<Project>(this.projectService.getProject(this.projectId))
.then(
response => {
this.orgProjectPolicy.initByProject(response);
this.projectPolicy.initByProject(response);
})
.catch(error => this.errorHandler.error(error));
}
updateProjectPolicy(projectId: string|number, pp: ProjectPolicy) {
@ -99,7 +117,7 @@ export class ProjectPolicyConfigComponent implements OnInit {
isValid() {
let flag = false;
if (!this.projectPolicy.PreventVulImg || this.severityOptions.some(x => x.severity === this.projectPolicy.PreventVulImgServerity)) {
if (!this.projectPolicy.PreventVulImg || this.severityOptions.some(x => x.severity === this.projectPolicy.PreventVulImgSeverity)) {
flag = true;
}
return flag;
@ -115,18 +133,18 @@ export class ProjectPolicyConfigComponent implements OnInit {
}
this.onGoing = true;
toPromise<any>(this.projectService.updateProjectPolicy(this.projectId, this.projectPolicy))
.then(() => {
this.onGoing = false;
.then(() => {
this.onGoing = false;
this.translate.get('CONFIG.SAVE_SUCCESS').subscribe((res: string) => {
this.errorHandler.info(res);
});
this.refresh();
})
.catch(error => {
this.onGoing = false;
this.errorHandler.error(error);
this.translate.get('CONFIG.SAVE_SUCCESS').subscribe((res: string) => {
this.errorHandler.info(res);
});
this.refresh();
})
.catch(error => {
this.onGoing = false;
this.errorHandler.error(error);
});
}
cancel(): void {

View File

@ -2,12 +2,11 @@ export class Project {
project_id: number;
owner_id: number;
name: string;
creation_time: Date;
creation_time_str: string;
creation_time: Date | string;
deleted: number;
owner_name: string;
togglable: boolean;
update_time: Date;
update_time: Date | string;
current_user_role_id: number;
repo_count: number;
has_project_admin_role: boolean;

View File

@ -74,7 +74,7 @@ export class ProjectDefaultService extends ProjectService {
'public': projectPolicy.Public ? 'true' : 'false',
'enable_content_trust': projectPolicy.ContentTrust ? 'true' : 'false',
'prevent_vul': projectPolicy.PreventVulImg ? 'true' : 'false',
'severity': projectPolicy.PreventVulImgServerity,
'severity': projectPolicy.PreventVulImgSeverity,
'auto_scan': projectPolicy.ScanImgOnPush ? 'true' : 'false'
} }, HTTP_JSON_OPTIONS)
.map(response => response.status)

View File

@ -31,7 +31,7 @@
"clarity-icons": "^0.9.8",
"clarity-ui": "^0.9.8",
"core-js": "^2.4.1",
"harbor-ui": "0.5.8",
"harbor-ui": "0.5.9",
"intl": "^1.2.5",
"mutationobserver-shim": "^0.3.2",
"ngx-cookie": "^1.0.0",

View File

@ -33,4 +33,4 @@ services:
- /data/secretkey:/etc/adminserver/key
- /data/:/data/
ports:
- 8888:80
- 8888:8080

View File

@ -161,12 +161,13 @@ Do Log Advanced Search
#others
Click Element xpath=//audit-log//clr-dropdown/button
Click Element xpath=//audit-log//clr-dropdown//a[contains(.,"Others")]
Sleep 1
Click element xpath=//audit-log//hbr-filter//clr-icon
Input Text xpath = //audit-log//hbr-filter//input harbor
Sleep 1
${c} = Get Matching Xpath Count //audit-log//clr-dg-row
Should be equal as integers ${c} 0
Click Element xpath=//audit-log//hbr-filter//clr-icon
Input Text xpath=//audit-log//hbr-filter//input harbor
Sleep 1
Capture Page Screenshot LogAdvancedSearch2.png
${rc} = Get Matching Xpath Count //audit-log//clr-dg-row
Should Be Equal As Integers ${rc} 0
Expand Repo
[Arguments] ${projectname}

View File

@ -1,7 +1,7 @@
FROM vmware/mariadb-photon:10.2.8
RUN tdnf distro-sync || echo \
&& tdnf install -y mariadb-devel python2 python2-devel python-pip gcc\
RUN tdnf distro-sync -y \
&& tdnf install -y mariadb-devel python2 python2-devel python-pip gcc \
linux-api-headers glibc-devel binutils zlib-devel openssl-devel \
&& pip install mysqlclient alembic \
&& tdnf clean all \

View File

@ -39,6 +39,11 @@ def upgrade():
bind = op.get_bind()
session = Session(bind=bind)
# This is to solve the legacy issue when upgrade from 1.2.0rc1 to 1.3.0 refered by #3077
username_coloumn = session.execute("show columns from user where field='username'").fetchone()
if username_coloumn[1] != 'varchar(255)':
op.alter_column('user', 'username', type_=sa.String(255))
# create table project_metadata
ProjectMetadata.__table__.create(bind)

View File

@ -40,7 +40,7 @@ if [[ ( $1 = "up" || $1 = "upgrade" ) && ${SKIP_CONFIRM} != "y" ]]; then
fi
echo 'Trying to start mysql server...'
DBRUN=0
chown -R 10000:10000 /var/lib/mysql
mysqld &
for i in {60..0}; do
mysqladmin -u$DB_USR -p$DB_PWD processlist >/dev/null 2>&1