From 821382b908c25032f3cc22efb1f42e5f0e6e6d02 Mon Sep 17 00:00:00 2001 From: Meng Wei Date: Thu, 7 Apr 2016 18:35:19 +0800 Subject: [PATCH 01/52] add doc about how to use your own certificate --- docs/How to use your own certificate.md | Bin 0 -> 19481 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/How to use your own certificate.md diff --git a/docs/How to use your own certificate.md b/docs/How to use your own certificate.md new file mode 100644 index 0000000000000000000000000000000000000000..d5714b533cbdcc4d307db36f952cfbf97e5fc317 GIT binary patch literal 19481 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 Date: Thu, 7 Apr 2016 18:43:12 +0800 Subject: [PATCH 02/52] Added files via upload From 83febcaf7f5b6b6a027a23d6c13a5d858b8d3ff7 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Thu, 7 Apr 2016 18:43:30 +0800 Subject: [PATCH 03/52] Delete How to use your own certificate.md --- docs/How to use your own certificate.md | Bin 19481 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/How to use your own certificate.md diff --git a/docs/How to use your own certificate.md b/docs/How to use your own certificate.md deleted file mode 100644 index d5714b533cbdcc4d307db36f952cfbf97e5fc317..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19481 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 Date: Thu, 7 Apr 2016 18:44:18 +0800 Subject: [PATCH 04/52] Added files via upload --- docs/How to use your own certificate.docx | Bin 0 -> 19481 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/How to use your own certificate.docx diff --git a/docs/How to use your own certificate.docx b/docs/How to use your own certificate.docx new file mode 100644 index 0000000000000000000000000000000000000000..d5714b533cbdcc4d307db36f952cfbf97e5fc317 GIT binary patch literal 19481 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 Date: Thu, 7 Apr 2016 18:44:53 +0800 Subject: [PATCH 05/52] Delete How to use your own certificate.docx --- docs/How to use your own certificate.docx | Bin 19481 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/How to use your own certificate.docx diff --git a/docs/How to use your own certificate.docx b/docs/How to use your own certificate.docx deleted file mode 100644 index d5714b533cbdcc4d307db36f952cfbf97e5fc317..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19481 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 Date: Thu, 7 Apr 2016 18:49:11 +0800 Subject: [PATCH 06/52] use your own certificate doc about how to use your own certificate in harbor --- docs/ use your own certificate | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 docs/ use your own certificate diff --git a/docs/ use your own certificate b/docs/ use your own certificate new file mode 100644 index 000000000..3c3c12779 --- /dev/null +++ b/docs/ use your own certificate @@ -0,0 +1,22 @@ + How to use your own certificate in harbor? +1. If you already have a certificate, go to step 3. +2. If not, you can generate a self-signed certificate using openSSL with following commands + 1) Generate a private key: + openssl genrsa -out prvtkey.pem 2048 + you can call it prvtkey.pem or other names you like. + 2) Generate a certificate: + openssl req -new -x509 -key prvtkey.pem -out cacert.pem -days 1095 + prvtkey.pem is what you generated in the first step, if you change the name, you should change it in the command. Also you can name cacert.pem what you like. +3. Clone harbor to your local position. Then open Deploy, and edit the harbor.cfg, make necessary configuration changes such as hostname, admin password and mail server. Refer to Installation Guide for more info. then execute ./prepare . Here, harbor generates several config files. We need to replace the original private key and certificate with your own key and certificate. +4. Following are what you should do: + a. edit docker-compose.yml, find private_key.pem replace it with your own private key as following: + b. cd config/ui, you will see private_key.pem. + c. replace private_key.pem with your private key. + d. cd ../registry, you will see root.crt. Replace it with your certificate. + e. at the same directory, you will see config.yml. We need to modify it, open it and find root.crt, then change it to your certificate. +5. After these, go back to harbor directory, execute: + docker-compose build + docker-compose up –d +6. Then you can push/pull images to see if your own certificate works. Please refer User Guide + + From 4ad154e4d90eadc18b236f3b3ee35ac561633a1e Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Thu, 7 Apr 2016 19:03:34 +0800 Subject: [PATCH 07/52] Delete use your own certificate --- docs/ use your own certificate | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 docs/ use your own certificate diff --git a/docs/ use your own certificate b/docs/ use your own certificate deleted file mode 100644 index 3c3c12779..000000000 --- a/docs/ use your own certificate +++ /dev/null @@ -1,22 +0,0 @@ - How to use your own certificate in harbor? -1. If you already have a certificate, go to step 3. -2. If not, you can generate a self-signed certificate using openSSL with following commands - 1) Generate a private key: - openssl genrsa -out prvtkey.pem 2048 - you can call it prvtkey.pem or other names you like. - 2) Generate a certificate: - openssl req -new -x509 -key prvtkey.pem -out cacert.pem -days 1095 - prvtkey.pem is what you generated in the first step, if you change the name, you should change it in the command. Also you can name cacert.pem what you like. -3. Clone harbor to your local position. Then open Deploy, and edit the harbor.cfg, make necessary configuration changes such as hostname, admin password and mail server. Refer to Installation Guide for more info. then execute ./prepare . Here, harbor generates several config files. We need to replace the original private key and certificate with your own key and certificate. -4. Following are what you should do: - a. edit docker-compose.yml, find private_key.pem replace it with your own private key as following: - b. cd config/ui, you will see private_key.pem. - c. replace private_key.pem with your private key. - d. cd ../registry, you will see root.crt. Replace it with your certificate. - e. at the same directory, you will see config.yml. We need to modify it, open it and find root.crt, then change it to your certificate. -5. After these, go back to harbor directory, execute: - docker-compose build - docker-compose up –d -6. Then you can push/pull images to see if your own certificate works. Please refer User Guide - - From 0c74c3559e4f6317b1501c565ebc2fbeed70935a Mon Sep 17 00:00:00 2001 From: Meng Wei Date: Thu, 7 Apr 2016 19:05:30 +0800 Subject: [PATCH 08/52] add file about how to use your own certificate --- docs/How to use your own certificate.md | Bin 19481 -> 0 bytes docs/img/edit_docker-compose-yml.png | Bin 0 -> 4258 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/How to use your own certificate.md create mode 100644 docs/img/edit_docker-compose-yml.png diff --git a/docs/How to use your own certificate.md b/docs/How to use your own certificate.md deleted file mode 100644 index d5714b533cbdcc4d307db36f952cfbf97e5fc317..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19481 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 NHZs3ZY~XVD{{YGBPoe+- literal 0 HcmV?d00001 From c1e203fb9a6a0060d1864e9915c6dcd0a9bb28a7 Mon Sep 17 00:00:00 2001 From: Meng Wei Date: Thu, 7 Apr 2016 19:09:36 +0800 Subject: [PATCH 09/52] add file --- ...w to use your own certificate in harbor.md | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 docs/how to use your own certificate in harbor.md diff --git a/docs/how to use your own certificate in harbor.md b/docs/how to use your own certificate in harbor.md new file mode 100644 index 000000000..c54c54fd7 --- /dev/null +++ b/docs/how to use your own certificate in harbor.md @@ -0,0 +1,23 @@ +#How to use your own certificate in harbor? +1. If you already have a certificate, go to step 3. +2. If not, you can generate a self-signed certificate using openSSL with following commands + 1) Generate a private key: + openssl genrsa -out prvtkey.pem 2048 + you can call it prvtkey.pem or other names you like. + 2) Generate a certificate: + openssl req -new -x509 -key prvtkey.pem -out cacert.pem -days 1095 + prvtkey.pem is what you generated in the first step, if you change the name, you should change it in the command. Also you can name cacert.pem what you like. +3. Clone harbor to your local position. Then open Deploy, and edit the harbor.cfg, make necessary configuration changes such as hostname, admin password and mail server. Refer to Installation Guide for more info. then execute ./prepare . Here, harbor generates several config files. We need to replace the original private key and certificate with your own key and certificate. +4. Following are what you should do: + a. edit docker-compose.yml, find private_key.pem replace it with your own private key as following: +![edit docker-compose.yml](img/edit_docker-compose-yml.png) + b. cd config/ui, you will see private_key.pem. + c. replace private_key.pem with your private key. + d. cd ../registry, you will see root.crt. Replace it with your certificate. + e. at the same directory, you will see config.yml. We need to modify it, open it and find root.crt, then change it to your certificate. +5. After these, go back to harbor directory, execute: + docker-compose build + docker-compose up d +6. Then you can push/pull images to see if your own certificate works. Please refer User Guide + + From 13e15c5fcc1f1f9f8e72d09ff7120532b0ff403c Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Thu, 7 Apr 2016 19:30:52 +0800 Subject: [PATCH 10/52] Update how to use your own certificate in harbor.md edit the file --- ...w to use your own certificate in harbor.md | 43 +++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/docs/how to use your own certificate in harbor.md b/docs/how to use your own certificate in harbor.md index c54c54fd7..329b3c12e 100644 --- a/docs/how to use your own certificate in harbor.md +++ b/docs/how to use your own certificate in harbor.md @@ -1,23 +1,50 @@ #How to use your own certificate in harbor? + 1. If you already have a certificate, go to step 3. + 2. If not, you can generate a self-signed certificate using openSSL with following commands + 1) Generate a private key: + +```sh openssl genrsa -out prvtkey.pem 2048 +``` you can call it prvtkey.pem or other names you like. + 2) Generate a certificate: + +```sh openssl req -new -x509 -key prvtkey.pem -out cacert.pem -days 1095 +``` + prvtkey.pem is what you generated in the first step, if you change the name, you should change it in the command. Also you can name cacert.pem what you like. + 3. Clone harbor to your local position. Then open Deploy, and edit the harbor.cfg, make necessary configuration changes such as hostname, admin password and mail server. Refer to Installation Guide for more info. then execute ./prepare . Here, harbor generates several config files. We need to replace the original private key and certificate with your own key and certificate. + 4. Following are what you should do: - a. edit docker-compose.yml, find private_key.pem replace it with your own private key as following: -![edit docker-compose.yml](img/edit_docker-compose-yml.png) - b. cd config/ui, you will see private_key.pem. - c. replace private_key.pem with your private key. - d. cd ../registry, you will see root.crt. Replace it with your certificate. - e. at the same directory, you will see config.yml. We need to modify it, open it and find root.crt, then change it to your certificate. + + a. edit docker-compose.yml, find private_key.pem replace it with your own private key as following: + +![edit docker-compose.yml](img/edit_docker-compose-yml.png) + + + b. cd config/ui, you will see private_key.pem. + + c. replace private_key.pem with your private key. + + d. cd ../registry, you will see root.crt. Replace it with your certificate. + + e. at the same directory, you will see config.yml. We need to modify it, open it and find root.crt, then change it to your certificate. + 5. After these, go back to harbor directory, execute: + +```sh docker-compose build - docker-compose up d -6. Then you can push/pull images to see if your own certificate works. Please refer User Guide +``` +```sh + docker-compose up –d +``` + +6. Then you can push/pull images to see if your own certificate works. Please refer [User Guide](https://github.com/vmware/harbor/blob/master/docs/user_guide.md) From 13161a1722e6a7fb9af17296a1fc8cbd2927a211 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Thu, 7 Apr 2016 19:35:04 +0800 Subject: [PATCH 11/52] Update how to use your own certificate in harbor.md edit the file --- ...w to use your own certificate in harbor.md | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/docs/how to use your own certificate in harbor.md b/docs/how to use your own certificate in harbor.md index 329b3c12e..978e6a685 100644 --- a/docs/how to use your own certificate in harbor.md +++ b/docs/how to use your own certificate in harbor.md @@ -1,17 +1,19 @@ #How to use your own certificate in harbor? -1. If you already have a certificate, go to step 3. +1.If you already have a certificate, go to step 3. -2. If not, you can generate a self-signed certificate using openSSL with following commands +2.If not, you can generate a self-signed certificate using openSSL with following commands - 1) Generate a private key: + 1)Generate a private key: ```sh openssl genrsa -out prvtkey.pem 2048 ``` + you can call it prvtkey.pem or other names you like. - 2) Generate a certificate: + + 2)Generate a certificate: ```sh openssl req -new -x509 -key prvtkey.pem -out cacert.pem -days 1095 @@ -19,24 +21,25 @@ prvtkey.pem is what you generated in the first step, if you change the name, you should change it in the command. Also you can name cacert.pem what you like. -3. Clone harbor to your local position. Then open Deploy, and edit the harbor.cfg, make necessary configuration changes such as hostname, admin password and mail server. Refer to Installation Guide for more info. then execute ./prepare . Here, harbor generates several config files. We need to replace the original private key and certificate with your own key and certificate. +3.Clone harbor to your local position. Then open Deploy, and edit the harbor.cfg, make necessary configuration changes such as hostname, admin password and mail server. Refer to Installation Guide for more info. then execute ./prepare . Here, harbor generates several config files. We need to replace the original private key and certificate with your own key and certificate. -4. Following are what you should do: +4.Following are what you should do: - a. edit docker-compose.yml, find private_key.pem replace it with your own private key as following: + a.edit docker-compose.yml, find private_key.pem replace it with your own private key as following: + ![edit docker-compose.yml](img/edit_docker-compose-yml.png) - b. cd config/ui, you will see private_key.pem. + b.cd config/ui, you will see private_key.pem. - c. replace private_key.pem with your private key. + c.replace private_key.pem with your private key. - d. cd ../registry, you will see root.crt. Replace it with your certificate. + d.cd ../registry, you will see root.crt. Replace it with your certificate. - e. at the same directory, you will see config.yml. We need to modify it, open it and find root.crt, then change it to your certificate. + e.at the same directory, you will see config.yml. We need to modify it, open it and find root.crt, then change it to your certificate. -5. After these, go back to harbor directory, execute: +5.After these, go back to harbor directory, execute: ```sh docker-compose build @@ -45,6 +48,6 @@ docker-compose up –d ``` -6. Then you can push/pull images to see if your own certificate works. Please refer [User Guide](https://github.com/vmware/harbor/blob/master/docs/user_guide.md) +6.Then you can push/pull images to see if your own certificate works. Please refer [User Guide](https://github.com/vmware/harbor/blob/master/docs/user_guide.md) From 3bf38d2195b51c43ceecf74d8eaf23e166ab35a4 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Thu, 7 Apr 2016 19:41:18 +0800 Subject: [PATCH 12/52] Update how to use your own certificate in harbor.md edit the file --- ...w to use your own certificate in harbor.md | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/docs/how to use your own certificate in harbor.md b/docs/how to use your own certificate in harbor.md index 978e6a685..3593a6630 100644 --- a/docs/how to use your own certificate in harbor.md +++ b/docs/how to use your own certificate in harbor.md @@ -3,17 +3,18 @@ 1.If you already have a certificate, go to step 3. 2.If not, you can generate a self-signed certificate using openSSL with following commands - - 1)Generate a private key: + +**1)Generate a private key:** + ```sh openssl genrsa -out prvtkey.pem 2048 ``` - - you can call it prvtkey.pem or other names you like. + +you can call it prvtkey.pem or other names you like. - 2)Generate a certificate: +**2)Generate a certificate:** ```sh openssl req -new -x509 -key prvtkey.pem -out cacert.pem -days 1095 @@ -25,19 +26,19 @@ 4.Following are what you should do: - a.edit docker-compose.yml, find private_key.pem replace it with your own private key as following: +**1)edit docker-compose.yml, find private_key.pem replace it with your own private key as following:** ![edit docker-compose.yml](img/edit_docker-compose-yml.png) - b.cd config/ui, you will see private_key.pem. +**2)cd config/ui, you will see private_key.pem.** - c.replace private_key.pem with your private key. +**3)replace private_key.pem with your private key.** - d.cd ../registry, you will see root.crt. Replace it with your certificate. +**4)cd ../registry, you will see root.crt. Replace it with your certificate.** - e.at the same directory, you will see config.yml. We need to modify it, open it and find root.crt, then change it to your certificate. +**5)at the same directory, you will see config.yml. We need to modify it, open it and find root.crt, then change it to your certificate.** 5.After these, go back to harbor directory, execute: From 6a731daa4ea3f8af07325f9542da143acf44e71e Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Thu, 7 Apr 2016 19:43:48 +0800 Subject: [PATCH 13/52] Update how to use your own certificate in harbor.md edit the file --- docs/how to use your own certificate in harbor.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/how to use your own certificate in harbor.md b/docs/how to use your own certificate in harbor.md index 3593a6630..21ab2ac03 100644 --- a/docs/how to use your own certificate in harbor.md +++ b/docs/how to use your own certificate in harbor.md @@ -20,7 +20,7 @@ you can call it prvtkey.pem or other names you like. openssl req -new -x509 -key prvtkey.pem -out cacert.pem -days 1095 ``` - prvtkey.pem is what you generated in the first step, if you change the name, you should change it in the command. Also you can name cacert.pem what you like. +prvtkey.pem is what you generated in the first step, if you change the name, you should change it in the command. Also you can name cacert.pem what you like. 3.Clone harbor to your local position. Then open Deploy, and edit the harbor.cfg, make necessary configuration changes such as hostname, admin password and mail server. Refer to Installation Guide for more info. then execute ./prepare . Here, harbor generates several config files. We need to replace the original private key and certificate with your own key and certificate. From f23ee5d0105edb4be47dbed74856e3204461578e Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Mon, 11 Apr 2016 14:42:13 +0800 Subject: [PATCH 14/52] Update and rename how to use your own certificate in harbor.md to auth.md edit file --- ...ow to use your own certificate in harbor.md => auth.md} | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) rename docs/{how to use your own certificate in harbor.md => auth.md} (66%) diff --git a/docs/how to use your own certificate in harbor.md b/docs/auth.md similarity index 66% rename from docs/how to use your own certificate in harbor.md rename to docs/auth.md index 21ab2ac03..6e17b12cc 100644 --- a/docs/how to use your own certificate in harbor.md +++ b/docs/auth.md @@ -1,4 +1,6 @@ -#How to use your own certificate in harbor? +#Customize harbor auth with your key and certificate + +By default, harbor use default private key and certificate in authentication. The auth procedure is like [Docker Registry v2 authentication](https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md). Also, you can customize your configuration with your own key and certificate. 1.If you already have a certificate, go to step 3. @@ -22,7 +24,7 @@ you can call it prvtkey.pem or other names you like. prvtkey.pem is what you generated in the first step, if you change the name, you should change it in the command. Also you can name cacert.pem what you like. -3.Clone harbor to your local position. Then open Deploy, and edit the harbor.cfg, make necessary configuration changes such as hostname, admin password and mail server. Refer to Installation Guide for more info. then execute ./prepare . Here, harbor generates several config files. We need to replace the original private key and certificate with your own key and certificate. +3.Refer to [Installation Guide](https://github.com/vmware/harbor/blob/master/docs/installation_guide.md) to install harbor. After you execute ./prepare, harbor generates several config files. We need to replace the original private key and certificate with your own key and certificate. 4.Following are what you should do: @@ -31,6 +33,7 @@ prvtkey.pem is what you generated in the first step, if you change the name, you ![edit docker-compose.yml](img/edit_docker-compose-yml.png) +![edit docker-compose.yml](img/after_edit_docker-compose-yml.png) **2)cd config/ui, you will see private_key.pem.** From 4475ce15cb8b1fef58c20bc75cb25f53c89ed915 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Mon, 11 Apr 2016 14:43:26 +0800 Subject: [PATCH 15/52] Update auth.md --- docs/auth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/auth.md b/docs/auth.md index 6e17b12cc..b4b03fea7 100644 --- a/docs/auth.md +++ b/docs/auth.md @@ -1,6 +1,6 @@ #Customize harbor auth with your key and certificate -By default, harbor use default private key and certificate in authentication. The auth procedure is like [Docker Registry v2 authentication](https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md). Also, you can customize your configuration with your own key and certificate. +By default, harbor use default private key and certificate in authentication. The auth procedure is like [Docker Registry v2 authentication](https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md). Also, you can customize your configuration with your own key and certificate with the following steps: 1.If you already have a certificate, go to step 3. From 96f5a86429fa21f197fa78c4a37a9a46ced0b368 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Mon, 11 Apr 2016 14:51:15 +0800 Subject: [PATCH 16/52] Added files via upload add png --- docs/img/after_edit_docker_compose_yml.png | Bin 0 -> 8373 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/img/after_edit_docker_compose_yml.png diff --git a/docs/img/after_edit_docker_compose_yml.png b/docs/img/after_edit_docker_compose_yml.png new file mode 100644 index 0000000000000000000000000000000000000000..b509f291279c32f3ddcf0d88777fbe7c49bf48d4 GIT binary patch literal 8373 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 YG%rpb;h)!sn7MJZ)E=o;E8B$s4}U9j?*IS* literal 0 HcmV?d00001 From 865e621f8a073185ec1486ec2607a6f76dcc5b9b Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Mon, 11 Apr 2016 14:52:17 +0800 Subject: [PATCH 17/52] Delete after_edit_docker_compose_yml.png --- docs/img/after_edit_docker_compose_yml.png | Bin 8373 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/img/after_edit_docker_compose_yml.png diff --git a/docs/img/after_edit_docker_compose_yml.png b/docs/img/after_edit_docker_compose_yml.png deleted file mode 100644 index b509f291279c32f3ddcf0d88777fbe7c49bf48d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8373 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 YG%rpb;h)!sn7MJZ)E=o;E8B$s4}U9j?*IS* From 89d424a7ef24ba87297d5735e53973646b894637 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Mon, 11 Apr 2016 14:53:02 +0800 Subject: [PATCH 18/52] Added files via upload --- docs/img/after_edit_docker-compose-yml.png | Bin 0 -> 8373 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/img/after_edit_docker-compose-yml.png diff --git a/docs/img/after_edit_docker-compose-yml.png b/docs/img/after_edit_docker-compose-yml.png new file mode 100644 index 0000000000000000000000000000000000000000..b509f291279c32f3ddcf0d88777fbe7c49bf48d4 GIT binary patch literal 8373 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 YG%rpb;h)!sn7MJZ)E=o;E8B$s4}U9j?*IS* literal 0 HcmV?d00001 From 5f4b3c6c8c2461f98883d684d9dd24dbcd53903e Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Mon, 11 Apr 2016 14:55:02 +0800 Subject: [PATCH 19/52] Delete edit_docker-compose-yml.png --- docs/img/edit_docker-compose-yml.png | Bin 4258 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/img/edit_docker-compose-yml.png diff --git a/docs/img/edit_docker-compose-yml.png b/docs/img/edit_docker-compose-yml.png deleted file mode 100644 index eaed395891046a1e053fbbcb41730ea43a210d0f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4258 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 NHZs3ZY~XVD{{YGBPoe+- From 72d5c2c58a40212bfda91697de2cccde23c01943 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Mon, 11 Apr 2016 14:55:17 +0800 Subject: [PATCH 20/52] Added files via upload --- docs/img/edit_docker-compose-yml.png | Bin 0 -> 8770 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/img/edit_docker-compose-yml.png diff --git a/docs/img/edit_docker-compose-yml.png b/docs/img/edit_docker-compose-yml.png new file mode 100644 index 0000000000000000000000000000000000000000..f2de711ac50dea560dbc8b89e7690a4d61aef38f GIT binary patch literal 8770 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 literal 0 HcmV?d00001 From 3885bd78ed1c93764aaa6a09dc7f3b8012f07ef9 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Wed, 13 Apr 2016 15:18:22 +0800 Subject: [PATCH 21/52] Update auth.md --- docs/auth.md | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/docs/auth.md b/docs/auth.md index b4b03fea7..47a520895 100644 --- a/docs/auth.md +++ b/docs/auth.md @@ -1,6 +1,6 @@ -#Customize harbor auth with your key and certificate +#Customize Harbor auth with your key and certificate -By default, harbor use default private key and certificate in authentication. The auth procedure is like [Docker Registry v2 authentication](https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md). Also, you can customize your configuration with your own key and certificate with the following steps: +By default, Harbor use default private key and certificate in authentication. The auth procedure is like [Docker Registry v2 authentication](https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md). Also, you can customize your configuration with your own key and certificate with the following steps: 1.If you already have a certificate, go to step 3. @@ -10,7 +10,7 @@ By default, harbor use default private key and certificate in authentication. T ```sh - openssl genrsa -out prvtkey.pem 2048 + openssl genrsa -out private_key.pem 2048 ``` you can call it prvtkey.pem or other names you like. @@ -19,37 +19,23 @@ you can call it prvtkey.pem or other names you like. **2)Generate a certificate:** ```sh - openssl req -new -x509 -key prvtkey.pem -out cacert.pem -days 1095 + openssl req -new -x509 -key private_key.pem -out root.crt -days 1095 ``` -prvtkey.pem is what you generated in the first step, if you change the name, you should change it in the command. Also you can name cacert.pem what you like. - -3.Refer to [Installation Guide](https://github.com/vmware/harbor/blob/master/docs/installation_guide.md) to install harbor. After you execute ./prepare, harbor generates several config files. We need to replace the original private key and certificate with your own key and certificate. +3.Refer to [Installation Guide](https://github.com/vmware/harbor/blob/master/docs/installation_guide.md) to install Harbor, After you execute ./prepare, Harbor generates several config files. We need to replace the original private key and certificate with your own key and certificate. 4.Following are what you should do: -**1)edit docker-compose.yml, find private_key.pem replace it with your own private key as following:** - - -![edit docker-compose.yml](img/edit_docker-compose-yml.png) - -![edit docker-compose.yml](img/after_edit_docker-compose-yml.png) - -**2)cd config/ui, you will see private_key.pem.** +**1)cd config/ui, you will see private_key.pem.** -**3)replace private_key.pem with your private key.** +**2)replace private_key.pem with your private_key.pem** -**4)cd ../registry, you will see root.crt. Replace it with your certificate.** +**4)cd ../registry, you will see root.crt. Replace it with your certificate root.crt** -**5)at the same directory, you will see config.yml. We need to modify it, open it and find root.crt, then change it to your certificate.** -5.After these, go back to harbor directory, execute: - -```sh - docker-compose build +5.After these, go back to the Deploy directory, you can start Harbor using following command: ``` -```sh - docker-compose up –d + docker-compose up -d ``` 6.Then you can push/pull images to see if your own certificate works. Please refer [User Guide](https://github.com/vmware/harbor/blob/master/docs/user_guide.md) From bc9f8377ca25821a0c02c1d4df9d0d0aac8b7745 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Wed, 13 Apr 2016 15:18:53 +0800 Subject: [PATCH 22/52] Update auth.md --- docs/auth.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/auth.md b/docs/auth.md index 47a520895..76d7d634b 100644 --- a/docs/auth.md +++ b/docs/auth.md @@ -30,7 +30,7 @@ you can call it prvtkey.pem or other names you like. **2)replace private_key.pem with your private_key.pem** -**4)cd ../registry, you will see root.crt. Replace it with your certificate root.crt** +**3)cd ../registry, you will see root.crt. Replace it with your certificate root.crt** 5.After these, go back to the Deploy directory, you can start Harbor using following command: From 3207a8f842bc849d0290b74137ac243c751f644e Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Wed, 13 Apr 2016 18:09:59 +0800 Subject: [PATCH 23/52] Update auth.md --- docs/auth.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/auth.md b/docs/auth.md index 76d7d634b..4798f4c0f 100644 --- a/docs/auth.md +++ b/docs/auth.md @@ -1,25 +1,24 @@ #Customize Harbor auth with your key and certificate -By default, Harbor use default private key and certificate in authentication. The auth procedure is like [Docker Registry v2 authentication](https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md). Also, you can customize your configuration with your own key and certificate with the following steps: +By default, Harbor use default private key and certificate in authentication. The auth procedure is like [Docker Registry v2 authentication](https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md). If you try to connect the registry without authorization, the registry will return `401 Unauthorized`. Then you should make a request to the authorization service for a token. The token is encrypted by the private key. After that, you make a new request with the token to the registry, registry will decrypted the token with the public key in the root.crt. The registry will check the token and authorize the client the access to push/pull images. + +Also, you can customize your configuration with your own key and certificate with the following steps: 1.If you already have a certificate, go to step 3. -2.If not, you can generate a self-signed certificate using openSSL with following commands +2.If not, you can generate a root certificate using openSSL with following commands **1)Generate a private key:** ```sh - openssl genrsa -out private_key.pem 2048 + openssl genrsa -out private_key.pem 4096 ``` - -you can call it prvtkey.pem or other names you like. - **2)Generate a certificate:** ```sh - openssl req -new -x509 -key private_key.pem -out root.crt -days 1095 + openssl req -new -x509 -key private_key.pem -out root.crt -days 3650 ``` 3.Refer to [Installation Guide](https://github.com/vmware/harbor/blob/master/docs/installation_guide.md) to install Harbor, After you execute ./prepare, Harbor generates several config files. We need to replace the original private key and certificate with your own key and certificate. @@ -30,7 +29,7 @@ you can call it prvtkey.pem or other names you like. **2)replace private_key.pem with your private_key.pem** -**3)cd ../registry, you will see root.crt. Replace it with your certificate root.crt** +**3)cd ../registry, you will see root.crt. Replace it with your root.crt** 5.After these, go back to the Deploy directory, you can start Harbor using following command: @@ -38,6 +37,6 @@ you can call it prvtkey.pem or other names you like. docker-compose up -d ``` -6.Then you can push/pull images to see if your own certificate works. Please refer [User Guide](https://github.com/vmware/harbor/blob/master/docs/user_guide.md) +6.Then you can push/pull images to see if your own certificate works. Please refer [User Guide](https://github.com/vmware/harbor/blob/master/docs/user_guide.md) for more info. From 15edf15b8874cc88d7b4f2c87432412bd0b0cd10 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Wed, 13 Apr 2016 18:16:29 +0800 Subject: [PATCH 24/52] Delete after_edit_docker-compose-yml.png --- docs/img/after_edit_docker-compose-yml.png | Bin 8373 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/img/after_edit_docker-compose-yml.png diff --git a/docs/img/after_edit_docker-compose-yml.png b/docs/img/after_edit_docker-compose-yml.png deleted file mode 100644 index b509f291279c32f3ddcf0d88777fbe7c49bf48d4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8373 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 YG%rpb;h)!sn7MJZ)E=o;E8B$s4}U9j?*IS* From b090d995f8a5bbbe409e8fe76adf29a2b08b50ab Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Wed, 13 Apr 2016 18:16:36 +0800 Subject: [PATCH 25/52] Delete edit_docker-compose-yml.png --- docs/img/edit_docker-compose-yml.png | Bin 8770 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 docs/img/edit_docker-compose-yml.png diff --git a/docs/img/edit_docker-compose-yml.png b/docs/img/edit_docker-compose-yml.png deleted file mode 100644 index f2de711ac50dea560dbc8b89e7690a4d61aef38f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8770 zcmZX4bzGBQ*goLCI=UNCkWjiry1NlZN_TfoVp76r90*7&(n#k7>5?(J6c7+Zn$h*! z@O|HZexE&`XM47D?sLv{?)$pqELKNLnGlZ-4+{&6P*p|YB^DMAG5T{05C?sKtgc>< zzGJB>$m$1T@8nqQvlxQc)F?U-i7S+kF|Rj@|8+}+3>3&@bT-XjUlsMX{b4{< z`!p_Jv7ADW=Iu79@*xaXaU>ztj`gv5Pt#G2Bv4r-`fwZzM4=K62$t#m6sJp(K&;6= zd`pzjpUT4~Ns~=4hwOIIy_9&bcBbK)TB1Q$q*Z(vX#msAWl8TZE(_d@0jT7A^n^tD*B;#~A5>e#%&+G1Ul-oTu1@DY%X)ecL76}EuIzFKvwa5y)oU{uG z`Fo(QEg5zm(s9(!jaM_R!y!3ZtYi|v>vu_fzc}Vh2Ck@EHAVHgf(@I@F*1CVTd6jX z=`U5S;_mvW=JWAObMewkpv$#QmCnlBzbAQQ&VQbK6@C|>_2lK)OHG_gHomFNSE+B6 zc&wW3;$>N&2~*o*C%O-5yZVfq!WJ@8)F1s-e<75k$AV2ZOAql{tTSyTk#(TpG4p(a zP4*ab$y+{edYh(Lkzwbqr=0>oV~f6&4&_S%p)*`-r#j{5{~?pHa4}an)0ZsMw;WRU zSkV>w968IH>~gjq<9UJ?y^@UW2F(r08aH6??C`u`CS*5V{dV2uH5f07}5Dh z08h3dGuUU|3@Ox$m#j(-f)H3Qj6zZq_tsSoheZa5`mCH4q6i`{0(f2(bZ+`TYROIVFgO{M4zcO$9w-E_Az z!)@_%lvJwTt8;l}(IBYn4!s6{0j8T2lQVb>9|z?(zJBDYdN=ggQ^=n~iAigoxvq7> z(=egDwh`UXZf9Y@f!(_1%&Vr^wQpn?1nLtz^&QA}OM?zdpJoVB2{g@eo7TI(CwO~@ zyCpl0yZZ_og*UUBmR#@Nu3LXguNG4c|3B>h0xPDu7lWg&_UviMo@`K6F6jR2ccNx_ zp8Yfc{8W{E7e2(+8l>eGl1Vdjo~co7G!6;q)qY-^NMrWOn8P zHy4?+;_d7f+`Prq1o{Iaei^{Q49M}bq%EYDe$W62gc?&hE%Gm`qDF+RZ zMQSpc+8loHX!wl%4?r^P4_+n%i2SvNiyha9Ih<1FXJ0w|WR(wAGtWA|a?nmtqpjBh zx1wq^?Vx1|!PCU{nW|jsocCXEFmAeDD`fizp%d zK+K*#hES0j-LegFoAp!|EV7i9Rj+~0pBjBi(bW>ecL$7 z4)C-GiLkNZG09IR(ZNCx_^b@=e0e6F5v^v$qXU*(Rj$KFFYfq247=s1|C{T<>QSA8 zLG@9F$?FYbhK#7Tfv0j~*H%y``|0~&q~1KUEzrthpB&$BsUew@D!bhnJ!DA=dNo~U zZlu}*&f8z)X0k2T>KHbfD0s~U!Y#ZCK`n4E1MEPI3u)D|%;8>C32cax8OR|xY1?bD zuCch;&H+R#byj!>cx^fzg%{ckt}45-q*z9$%=Q-N6*?5MU=L7WYYAHrH?m<&E}n^~X56gg5^+ltl6Gd>`zibC;g*ytstD8oSHD@-E^sbV??Uv=ipE1hyk&nn7k&2`Fc)HY@b#FI=@t?t8 zC|KIKfAi4^nQvgg#~6gZie-!YibPd94+qM;niFnKL_JNp<(knL`*7t@l9v(u@DZKC z&YIFU_;#avmQnM4J%$qlqqBCqgNXgvS$C)~0g`ekV>o(`=h&#_y?_O`XDEP?`0 zEDrt-6C*;;T%miiZA233p7AHBpt!dB7=-D(@*tg4rI@X zO6HwoKUlPWUT#$7(eyf#zJG4tRAPUY!-coDk_wlqnBJP(R&Ual zCvcFLyB-M%mQ#y5kRx2{j5c>8MdWze^_F z{d%EEteSYU!rzL1WE?)J)24MZMk~!1amYHaV=wYz`cWI$txx_U<6!cpn=KaiNyBw0 z2VPFB+*|K_-e6np5yAp8vwDSOpx~R45@*#bf(U?^?Bi5FDEaBn%Y^>lz|;M5rKX4C zC$ULk1X=#LBEME;s+WceGCX%qQ3`Mlc(l20OilsCy}yg|F(BZeOD%{uXCO>~?c8I* zJ}KV3Or>0HvizlFXD6pK7p)q49az~Qb`paX!%3=SK!oBGDo?om(TNDe!J0-cD zVy4YP-}H4Qt%A`J(_@GfiIF{iHe1DF43js(KS|=`MhI?S>u>rsf-lAHh>(%YbFRw{ zXdlbC`-&(Q!^9j-J-OpEdWc`+=J~cqbyc?ei#1-Vf zFF+LMTBRGT{}F@+r*et|rtdt;XWTO%s3bw3ILQLA%j3F`6g(yWMRO}{Vs*r)qvPUN zp#w&^V>lY1Z8w;>1}px9@&QeuO|3%5IO*4FLaZm9; zAmh-M*$pu8!M6oc>QsOoMNmagzGDZ^D zp&jGT{l(sM>YG!n>b={*ldnsX^T%HNp_rc^L-24le%v#lK70>4^@xmBJY{S%VIptE zcpPl9eT;KVePVyqaz)^6OL!15bfQ_>pwA18_V zm{Ht5iVFh-7A^$~AFO@(H`Rj&S&wbs)ELEY2uy8`^;L`&3p>JBT5Y~Vkr$@VrOI!^*2($S{;!%WY<=csV%i1UgP|{?hO72R# z<7e6`GHF|<8|a0quNIm^I@LTzd| zrUWLT_bc1krj2apDp(htL1*rS72D^y^wD%EPLO%>&t}U~dvku21|fR%YGC`pzTaoW z&Dx2$_H}oT_99Ppb?(Jz(&+Vt=A*5t$9nf8Rv&IvD%nynm3-nBD+0ZNkYp7=dpH)x zT1-VXgot3daGJ<0g-;IlQ05{UJS&2-6>+p+3-k`}*%vtq&?Xgmy$1bcrc>6f4>b=c zSNa-6;a4!_Pv>;42u#b68t<&-u}y&a$2mPj~92+c%iL6i&fuZ=8N`d`6>wq~WWA23Ce0sNm6Z zVaC1-KP@LVe`OCvZthg)Ft+W?vfutji1CL@$VMx_Kz?K;2Jbfr#|A(3B7g-}#P2WT zY1VU0y7){%`3aWs-n701>lWe?R0w?6wwBQ85`7gL9_pt24y|{=TFaG&7Ps5ya~&ZY zT^&ndNch*Iv>0uR(7gxJ<9k-Cjb<3IL|0=nAbJIy6T>aOe*;voy~aw7s*=N5JSg-c2F zGt1C?<=gr~g@)&nj;4Q=ZJ#R2P`)YW-VS6bro zP`*z5*US?K`@N2JM|p;JdBHdmA)@N1L#~9*iaK+6Rz5Bs%0wX*@gY-}k@^dwc9?lP z5<{lyj#vuM4kZHMifP%SSY5m~lzriY0D#}uOx*N`&Jvp;b+`_cSn?RZ;PqM~Dws8nQ;hpdm-MP7LmM`Y(=~269$K7m( zEit$`MVJf>QblT%8#~`TVqG-WfX#3I4|Y0W#SHiRC(fPf85l^$$Z^X3@GpmrQ`~CU zpRE5+K0idB?7ET~;kso*syZj>0Yfv+9ZQCH>Q6)#;|B-~trKNPS<3!PXu<)DnNL*- z>&{;R%vz1&*)*uGZ2z@4!m*Kj@I0IQcU@HbunT{NEq{JXuNN2+Wj7(vQYKP&Vz`_#I_hRHjbmIr=Eg`%U#^-C3J zQrTml4qOZOI4+h$OW!buY{zz*hOU@7n2VfU4LV4NE%{so?+-#d4j{yP&ps5l z^&&qfCUW|k!^+F9CLu262(oV*9;r*?ea2O=<9u&Ws2qaOQS9OCd#{5hdiAx$2mQ~{ z{+#<)6!iSpSn>wd+2(LSSPK8WaC4C$wFZLYLRrr0*ymKn!Y-u(StXE=ruzmbSF>zR z0vD9`P{2HrdeJzN@kP1n^sQI6)%eek-n~R!b>jkrNQra#TeT>bWt~?PU?p!DN2iPk zTtS-_k|hZ+NolKYoe0a1csX6{0Jpcykz)m)b=CcNYG_c29l znA_%JB?B8>j2gn6Ku)u8T(C|tMK>~EOD8g)DQa(82F=%wq!~1ablFIgL%7%zwd=G{dvVP-KyPRRg;ObIv#`2P%qlJLggT+zsuKZ%o^sukUQ! zT6Hg%$Sv;8EY^@0sRS?GAy$3Fq_U*>=NJursd{(CO}Pu)YFjbzZH zP%BsB0JbOjsM=ecV&-~LJ@IGog2T-TB4*^%dCfwH|D{>=xynanz^Y1?ir&!)NbI6R%Tsxx^dn))qHtp0VOgnkE2d(Ft|T%;N{1;dj6&2+5ArMEmLvBpXJ^iahl-v z{3YN0Q+6PqVqoZ5eN)-+w^5{jPj#M5M~&ewV0*_`%A=aUd;Jo2TXyxXr^o*C35f%K zi{9j-##L;y>$txQ0QZm5upOE~9`N56 z4!k2bt2g+!LAQz_A-AaYrK@G-`*I(rJL2$i4A;vzq}#$I%Hlqv-;*4viO-c&(1fM; ze}tv@9HjUXmREQXfcz;bu5DfyF~@OHAT3Uu$9PWIHgLu&j=~wzE3+%1CNv4stf(2N zHCBfq6$rQ6o`0#`=oeOfhopLwRZ#NgDd~tofXV*IqEW~!WP zk3=E{%=K$7=)qx~aX>?q>5lte-BDNFHRaFl#RbCiy5LatYG_Yk-~_RnwcEp?`m+g? z6#-q{y!yUl$;FtIyq@*;JRqm+2yI4%hY}8#G5mmL!sjJ;QR4^HTddnnk!+RyLLswJ zMni#9jBnnTO4TFA-YpkvwmYhysX~X2D(szZtO%ICyB!6KlCLv5@=L#8rNcMgaNkKY zKu5NAKSZI18}P0v#wm8{OF{}P59$9dB>~b-9Fj>Llt80c^`{^Dob1W^ zc2hozQirVHOcZKPu=g1Zh#=)z)j~r#z8RI1pT35sv1`3v$wqMTPSA6^2TlyHom1sq zUUpP8tg_|&U5b#5i|wOw<2y;}pJ&-Bm_)Q*)L^JHtJCPe&4!kFC>h}j-Wy@v|BauC zFQRII22RI8W$lT}L(qxVT1`vd`?Yf%Q?mij4d{hXan5_^q&C`5?5F92A*RS#HiK%= z*jrk3#BHEsvQZNC^1r}|!sqg!!k60xO>pqdr?-KRWpHi$U@OWCW$+zpMul*5TbDc| zyM#*krrQT|7=_>PeuseZt;@s0g8SixCNa7}bo_Nc$6}6cvW?(0>Xbsspf8on{?c!3 zp%V_g*Q;iqZ_caOZ=QvQoYwesoGf&7Dj)oH%;m387 zS*G=2FH|B=^rmK;aDC^ElE6#UQPHmk0{7%yq{6Wep9!tW^?l#_+9hcobk^!HYJRb1 zrv3WDMZ0z8hc>!;)jN#z)SAV@2qV8xulqnvy5iF8H zKr`kO?lOMXhLy+>lgBa_6*FHa0>Rtyi;~zp?0QFA@_0p=F~}gaSs%&f)MaMJA4}D| zSFvdGC6hkgA`}7Upi|s&zuAbQ&MhYj-dXYg7_n#3e%7s?(Rd%c@%;t+JOlXpFZuC3 z!(363v+47rdoh+Vw@7-Adc}c`v%?Je(I<;RC$5ZjC$o#FteLB=a`R)u&srf@vFsd! zw5i-I+FWeV^TTk>xEe_=I}S`z(KD$$Vi;q&p#L}*^Si zNpCR3r#{?Ms|W)$K7ey8M7=ouGAg(ha-2;{RxYLr=F&0RQFeHP;YDHW{n-T62=lF>ARs0f&Ohb@0?J~%)k}SKN=u-9UVs)9oqme_3ob|=E z2#VR!&YkqRXp>C;Veg{&P|*vXu;{>1|)WpQ|tHu`iNbWi_W){ zaXP$juf>B^Tp07hQ}uLqH71?Y^lLI)YqrA9J%$RV>rAMj^VO#AYST%!k4+baZ0|~X z(ejoI)!xIbL1`&mzJJxzn@_#>lHvztE5&kYs-uDQg02IM`QV z7{|iGzQ+6)Ky1qTm-u3#9%+8PRD(t78b<)LDhE0{p4V93Z`hLpdwKQC3$`zUmGK62*by4C`wTTYi2q9i z1puw-+(YqR8^TU{w8d39$Z_;>nT#Qj&vb28Zv;>DF%n(h%U=StHo7DC;NOsU1DN9S znb!Lu_;~IzVRCGHsPGP9-`z2+8!O*iSEeK{ZEz~s^b~*f?ik3Q)N{@ndCI>2a7Dnc zP0BAm8Z8qHNbiU>;i5WBhVDjn$oKd+T20`h3iaovcgL8r@5+)fxXrFiFGv|I%f5)p z)V`r&0#X&n5rtLJilOH?1(=>O^|cNrHD@NcH88b~CT!>wxrz&&YdkzjO iHTJuiOXJ)U=TE-WtC%{%NB=hjOI1-zp-Rs3&Hn@aKV=*M From 2809d08aadbc63365e29db7695dfd139138b9bed Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Thu, 14 Apr 2016 12:06:25 +0800 Subject: [PATCH 26/52] Update and rename auth.md to customize key for authentication.md --- docs/{auth.md => customize key for authentication.md} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename docs/{auth.md => customize key for authentication.md} (59%) diff --git a/docs/auth.md b/docs/customize key for authentication.md similarity index 59% rename from docs/auth.md rename to docs/customize key for authentication.md index 4798f4c0f..9ce9b1e8c 100644 --- a/docs/auth.md +++ b/docs/customize key for authentication.md @@ -1,12 +1,12 @@ #Customize Harbor auth with your key and certificate -By default, Harbor use default private key and certificate in authentication. The auth procedure is like [Docker Registry v2 authentication](https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md). If you try to connect the registry without authorization, the registry will return `401 Unauthorized`. Then you should make a request to the authorization service for a token. The token is encrypted by the private key. After that, you make a new request with the token to the registry, registry will decrypted the token with the public key in the root.crt. The registry will check the token and authorize the client the access to push/pull images. +Harbor requires Docker client to access the Harbor registry with a token. The procedure to generate a token is like [Docker Registry v2 authentication](https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md). Firstly, you should make a request to the token service for a token. The token is signed by the private key. After that, you make a new request with the token to the Harbor registry, Harbor registry will verify the token with the public key in the rootcert bundle. Then Harbor registry will authorize the Docker client to push/pull images. -Also, you can customize your configuration with your own key and certificate with the following steps: +By default, Harbor uses default private key and certificate in authentication. Also, you can customize your configuration with your own key and certificate with the following steps: 1.If you already have a certificate, go to step 3. -2.If not, you can generate a root certificate using openSSL with following commands +2.If not, you can generate a root certificate using openSSL with following commands: **1)Generate a private key:** @@ -15,7 +15,7 @@ Also, you can customize your configuration with your own key and certificate wit openssl genrsa -out private_key.pem 4096 ``` -**2)Generate a certificate:** +**2)Generate a certificate:** ```sh openssl req -new -x509 -key private_key.pem -out root.crt -days 3650 From 9960211abc42cd9cb7f6c706db8290ece4c4b0cc Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Tue, 19 Apr 2016 11:48:09 +0800 Subject: [PATCH 27/52] Update customize key for authentication.md --- docs/customize key for authentication.md | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/customize key for authentication.md b/docs/customize key for authentication.md index 9ce9b1e8c..96c57dae4 100644 --- a/docs/customize key for authentication.md +++ b/docs/customize key for authentication.md @@ -10,17 +10,35 @@ By default, Harbor uses default private key and certificate in authentication. A **1)Generate a private key:** - ```sh openssl genrsa -out private_key.pem 4096 ``` -**2)Generate a certificate:** +**2)Generate a certificate:** You are about to be asked to enter information that will be incorporated into your certificate request. +What you are about to enter is what is called a Distinguished Name or a DN. +There are quite a few fields but you can leave some blank +For some fields there will be a default value, +If you enter '.', the field will be left blank. Following are what you're asked to enter. + +Country Name (2 letter code) [AU]: + +State or Province Name (full name) [Some-State]: + +Locality Name (eg, city) []: + +Organization Name (eg, company) [Internet Widgits Pty Ltd]: + +Organizational Unit Name (eg, section) []: + +Common Name (eg, server FQDN or YOUR name) []: + +Email Address []: ```sh openssl req -new -x509 -key private_key.pem -out root.crt -days 3650 ``` - +After you execute these two commands, you will see private_key.pem and root.crt in the **current directory**, just type "ls", you'll see them. + 3.Refer to [Installation Guide](https://github.com/vmware/harbor/blob/master/docs/installation_guide.md) to install Harbor, After you execute ./prepare, Harbor generates several config files. We need to replace the original private key and certificate with your own key and certificate. 4.Following are what you should do: From 54aca69b19702c0cdbce2bccf39a39563395b7b0 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Tue, 19 Apr 2016 13:58:10 +0800 Subject: [PATCH 28/52] change the title --- ...ize key for authentication.md => customize token service.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename docs/{customize key for authentication.md => customize token service.md} (97%) diff --git a/docs/customize key for authentication.md b/docs/customize token service.md similarity index 97% rename from docs/customize key for authentication.md rename to docs/customize token service.md index 96c57dae4..1f9f79a1f 100644 --- a/docs/customize key for authentication.md +++ b/docs/customize token service.md @@ -1,4 +1,4 @@ -#Customize Harbor auth with your key and certificate +#Customize Harbor token service with your key and certificate Harbor requires Docker client to access the Harbor registry with a token. The procedure to generate a token is like [Docker Registry v2 authentication](https://github.com/docker/distribution/blob/master/docs/spec/auth/token.md). Firstly, you should make a request to the token service for a token. The token is signed by the private key. After that, you make a new request with the token to the Harbor registry, Harbor registry will verify the token with the public key in the rootcert bundle. Then Harbor registry will authorize the Docker client to push/pull images. From ab6bb58c3636875d6aba25aa6260687783d79164 Mon Sep 17 00:00:00 2001 From: hmwenchen Date: Fri, 22 Apr 2016 00:28:59 +0800 Subject: [PATCH 29/52] Add tag to accesslog --- Deploy/db/registry.sql | 1 + api/project.go | 3 + api/repository.go | 143 +++-------------------------- dao/accesslog.go | 22 +++-- dao/project.go | 2 +- models/accesslog.go | 1 + models/notification.go | 1 + models/repo.go | 30 ++++++ service/notification.go | 82 ++++++++++++++++- static/i18n/locale_en-US.ini | 1 + static/i18n/locale_zh-CN.ini | 3 +- static/resources/js/item-detail.js | 1 + views/item-detail.tpl | 9 +- 13 files changed, 153 insertions(+), 146 deletions(-) diff --git a/Deploy/db/registry.sql b/Deploy/db/registry.sql index 9e4a342b3..bd0644b33 100644 --- a/Deploy/db/registry.sql +++ b/Deploy/db/registry.sql @@ -94,6 +94,7 @@ create table access_log ( user_id int NOT NULL, project_id int NOT NULL, repo_name varchar (40), + repo_tag varchar (20), GUID varchar(64), operation varchar(20) NOT NULL, op_time timestamp, diff --git a/api/project.go b/api/project.go index dbc0a4ecb..2d2aa1e47 100644 --- a/api/project.go +++ b/api/project.go @@ -31,6 +31,7 @@ import ( type ProjectAPI struct { BaseAPI userID int + username string projectID int64 } @@ -183,6 +184,8 @@ func (p *ProjectAPI) FilterAccessLog() { p.CustomAbort(http.StatusInternalServerError, "Internal error.") } p.Data["json"] = accessLogList + + log.Errorf("--- accessLog first record: %v ---", accessLogList[0]) p.ServeJSON() } diff --git a/api/repository.go b/api/repository.go index 6058b3608..252cb2fbc 100644 --- a/api/repository.go +++ b/api/repository.go @@ -18,7 +18,6 @@ package api import ( "encoding/json" "net/http" - "os" "strconv" "strings" "time" @@ -27,9 +26,6 @@ import ( "github.com/vmware/harbor/models" 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" ) // RepositoryAPI handles request to /api/repositories /api/repositories/tags /api/repositories/manifests, the parm has to be put @@ -40,7 +36,6 @@ type RepositoryAPI struct { BaseAPI userID int username string - registry *registry.Registry } // Prepare will set a non existent user ID in case the request tries to view repositories under a project he doesn't has permission. @@ -58,43 +53,6 @@ func (ra *RepositoryAPI) Prepare() { } else { ra.username = username } - - var client *http.Client - - //no session, initialize a standard auth handler - if ra.userID == dao.NonExistUserID && len(ra.username) == 0 { - username, password, _ := ra.Ctx.Request.BasicAuth() - - credential := auth.NewBasicAuthCredential(username, password) - client = registry.NewClientStandardAuthHandlerEmbeded(credential) - log.Debug("initializing standard auth handler") - - } else { - // session works, initialize a username auth handler - username := ra.username - if len(username) == 0 { - user, err := dao.GetUser(models.User{ - UserID: ra.userID, - }) - if err != nil { - log.Errorf("error occurred whiling geting user for initializing a username auth handler: %v", err) - return - } - - username = user.Username - } - - client = registry.NewClientUsernameAuthHandlerEmbeded(username) - log.Debug("initializing username auth handler: %s", username) - } - - endpoint := os.Getenv("REGISTRY_URL") - r, err := registry.New(endpoint, client) - if err != nil { - log.Fatalf("error occurred while initializing auth handler for repository API: %v", err) - } - - ra.registry = r } // Get ... @@ -119,13 +77,11 @@ func (ra *RepositoryAPI) Get() { ra.RenderError(http.StatusForbidden, "") return } - repoList, err := svc_utils.GetRepoFromCache() if err != nil { log.Errorf("Failed to get repo from cache, error: %v", err) ra.RenderError(http.StatusInternalServerError, "internal sever error") } - projectName := p.Name q := ra.GetString("q") var resp []string @@ -149,92 +105,26 @@ func (ra *RepositoryAPI) Get() { ra.ServeJSON() } -// Delete ... -func (ra *RepositoryAPI) Delete() { - repoName := ra.GetString("repo_name") - if len(repoName) == 0 { - ra.CustomAbort(http.StatusBadRequest, "repo_name is nil") - } - - tags := []string{} - tag := ra.GetString("tag") - if len(tag) == 0 { - tagList, err := ra.registry.ListTag(repoName) - if err != nil { - e, ok := errors.ParseError(err) - if ok { - log.Info(e) - ra.CustomAbort(e.StatusCode, e.Message) - } else { - log.Error(err) - ra.CustomAbort(http.StatusInternalServerError, "internal error") - } - - } - tags = append(tags, tagList...) - - } else { - tags = append(tags, tag) - } - - for _, t := range tags { - if err := ra.registry.DeleteTag(repoName, t); err != nil { - e, ok := errors.ParseError(err) - if ok { - ra.CustomAbort(e.StatusCode, e.Message) - } else { - log.Error(err) - ra.CustomAbort(http.StatusInternalServerError, "internal error") - } - } - log.Infof("delete tag: %s %s", repoName, t) - } - - go func() { - log.Debug("refreshing catalog cache") - if err := svc_utils.RefreshCatalogCache(); err != nil { - log.Errorf("error occurred while refresh catalog cache: %v", err) - } - }() - -} - type tag struct { Name string `json:"name"` Tags []string `json:"tags"` } -type histroyItem struct { - V1Compatibility string `json:"v1Compatibility"` -} - -type manifest struct { - Name string `json:"name"` - Tag string `json:"tag"` - Architecture string `json:"architecture"` - SchemaVersion int `json:"schemaVersion"` - History []histroyItem `json:"history"` -} - // GetTags handles GET /api/repositories/tags func (ra *RepositoryAPI) GetTags() { var tags []string repoName := ra.GetString("repo_name") - - tags, err := ra.registry.ListTag(repoName) + result, err := svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repoName, "tags", "list"), ra.username) if err != nil { - e, ok := errors.ParseError(err) - if ok { - log.Info(e) - ra.CustomAbort(e.StatusCode, e.Message) - } else { - log.Error(err) - ra.CustomAbort(http.StatusInternalServerError, "internal error") - } + log.Errorf("Failed to get repo tags, repo name: %s, error: %v", repoName, err) + ra.RenderError(http.StatusInternalServerError, "Failed to get repo tags") + } else { + t := tag{} + json.Unmarshal(result, &t) + tags = t.Tags } - ra.Data["json"] = tags ra.ServeJSON() } @@ -246,20 +136,14 @@ func (ra *RepositoryAPI) GetManifests() { item := models.RepoItem{} - _, _, payload, err := ra.registry.PullManifest(repoName, tag, registry.ManifestVersion1) + result, err := svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repoName, "manifests", tag), ra.username) if err != nil { - e, ok := errors.ParseError(err) - if ok { - log.Info(e) - ra.CustomAbort(e.StatusCode, e.Message) - } else { - log.Error(err) - ra.CustomAbort(http.StatusInternalServerError, "internal error") - } + log.Errorf("Failed to get manifests for repo, repo name: %s, tag: %s, error: %v", repoName, tag, err) + ra.RenderError(http.StatusInternalServerError, "Internal Server Error") + return } - - mani := manifest{} - err = json.Unmarshal(payload, &mani) + mani := models.Manifest{} + err = json.Unmarshal(result, &mani) if err != nil { log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repoName, tag, err) ra.RenderError(http.StatusInternalServerError, "Internal Server Error") @@ -273,6 +157,7 @@ func (ra *RepositoryAPI) GetManifests() { ra.RenderError(http.StatusInternalServerError, "Internal Server Error") return } + item.CreatedStr = item.Created.Format("2006-01-02 15:04:05") item.DurationDays = strconv.Itoa(int(time.Since(item.Created).Hours()/24)) + " days" ra.Data["json"] = item diff --git a/dao/accesslog.go b/dao/accesslog.go index 721ac92cd..20fb20655 100644 --- a/dao/accesslog.go +++ b/dao/accesslog.go @@ -19,6 +19,7 @@ import ( "strings" "github.com/vmware/harbor/models" + "github.com/vmware/harbor/utils/log" "github.com/astaxie/beego/orm" ) @@ -27,14 +28,14 @@ import ( func AddAccessLog(accessLog models.AccessLog) error { o := orm.NewOrm() p, err := o.Raw(`insert into access_log - (user_id, project_id, repo_name, guid, operation, op_time) - values (?, ?, ?, ?, ?, now())`).Prepare() + (user_id, project_id, repo_name, repo_tag, guid, operation, op_time) + values (?, ?, ?, ?, ?, ?, now())`).Prepare() if err != nil { return err } defer p.Close() - _, err = p.Exec(accessLog.UserID, accessLog.ProjectID, accessLog.RepoName, accessLog.GUID, accessLog.Operation) + _, err = p.Exec(accessLog.UserID, accessLog.ProjectID, accessLog.RepoName, accessLog.RepoTag, accessLog.GUID, accessLog.Operation) return err } @@ -43,7 +44,7 @@ func AddAccessLog(accessLog models.AccessLog) error { func GetAccessLogs(accessLog models.AccessLog) ([]models.AccessLog, error) { o := orm.NewOrm() - sql := `select a.log_id, u.username, a.repo_name, a.operation, a.op_time + sql := `select a.log_id, u.username, a.repo_name, a.repo_tag, a.operation, a.op_time from access_log a left join user u on a.user_id = u.user_id where a.project_id = ? ` queryParam := make([]interface{}, 1) @@ -95,13 +96,16 @@ func GetAccessLogs(accessLog models.AccessLog) ([]models.AccessLog, error) { return accessLogList, nil } -// AccessLog ... -func AccessLog(username, projectName, repoName, action string) error { +// AccessLog, invoked in service/notification.go +func AccessLog(username, projectName, repoName, repoTag, action string) error { o := orm.NewOrm() - sql := "insert into access_log (user_id, project_id, repo_name, operation, op_time) " + + sql := "insert into access_log (user_id, project_id, repo_name, repo_tag, operation, op_time) " + "select (select user_id as user_id from user where username=?), " + - "(select project_id as project_id from project where name=?), ?, ?, now() " - _, err := o.Raw(sql, username, projectName, repoName, action).Exec() + "(select project_id as project_id from project where name=?), ?, ?, ?, now() " + _, err := o.Raw(sql, username, projectName, repoName, repoTag, action).Exec() + if err != nil { + log.Errorf("error in AccessLog: %v ", err) + } return err } diff --git a/dao/project.go b/dao/project.go index d2a611e9f..a0e6e6b25 100644 --- a/dao/project.go +++ b/dao/project.go @@ -60,7 +60,7 @@ func AddProject(project models.Project) error { return err } - accessLog := models.AccessLog{UserID: project.OwnerID, ProjectID: projectID, RepoName: project.Name + "/", GUID: "N/A", Operation: "create", OpTime: time.Now()} + accessLog := models.AccessLog{UserID: project.OwnerID, ProjectID: projectID, RepoName: project.Name + "/", RepoTag: "N/A", GUID: "N/A", Operation: "create", OpTime: time.Now()} err = AddAccessLog(accessLog) return err diff --git a/models/accesslog.go b/models/accesslog.go index 150f3b588..3111e3a44 100644 --- a/models/accesslog.go +++ b/models/accesslog.go @@ -25,6 +25,7 @@ type AccessLog struct { UserID int `orm:"column(user_id)" json:"UserId"` ProjectID int64 `orm:"column(project_id)" json:"ProjectId"` RepoName string `orm:"column(repo_name)"` + RepoTag string `orm:"column(repo_tag)"` GUID string `orm:"column(GUID)" json:"Guid"` Operation string `orm:"column(operation)"` OpTime time.Time `orm:"column(op_time)"` diff --git a/models/notification.go b/models/notification.go index 0f608e2c6..3f30ae7e4 100644 --- a/models/notification.go +++ b/models/notification.go @@ -40,6 +40,7 @@ type Target struct { Digest string Repository string URL string `json:"Url"` + Tag string } // Actor holds information about actor. diff --git a/models/repo.go b/models/repo.go index 6b8de742b..44abd9d9b 100644 --- a/models/repo.go +++ b/models/repo.go @@ -29,6 +29,7 @@ type RepoItem struct { ID string `json:"Id"` Parent string `json:"Parent"` Created time.Time `json:"Created"` + CreatedStr string `json:"CreatedStr"` DurationDays string `json:"Duration Days"` Author string `json:"Author"` Architecture string `json:"Architecture"` @@ -42,3 +43,32 @@ type Tag struct { Version string `json:"version"` ImageID string `json:"image_id"` } + +type Manifest struct { + SchemaVersion int `json:"schemaVersion"` + Name string `json:"name"` + Tag string `json:"tag"` + Architecture string `json:"architecture"` + FsLayers []blobSumItem `json:"fsLayers"` + History []histroyItem `json:"history"` +} + +type histroyItem struct { + V1Compatibility string `json:"v1Compatibility"` +} + +type blobSumItem struct { + BlobSum string `json:"blobSum"` +} + +type ManifestDigest struct { + MediaType string `json:"mediaType"` + SchemaVersion int `json:"schemaVersion"` + Layers []layerItem `json:"layers"` +} + +type layerItem struct { + MediaType string `json:"mediaType"` + Size int `json:"size"` + Digest string `json:"digest"` +} diff --git a/service/notification.go b/service/notification.go index beab28778..04611ec21 100644 --- a/service/notification.go +++ b/service/notification.go @@ -18,6 +18,7 @@ package service import ( "encoding/json" "regexp" + "sort" "strings" "github.com/vmware/harbor/dao" @@ -33,6 +34,11 @@ type NotificationHandler struct { beego.Controller } +type taglist struct { + Name string `json:"name"` + Tags []string `json:"tags"` +} + const manifestPattern = `^application/vnd.docker.distribution.manifest.v\d\+json` // Post handles POST request, and records audit log or refreshes cache based on event. @@ -46,7 +52,7 @@ func (n *NotificationHandler) Post() { log.Errorf("error while decoding json: %v", err) return } - var username, action, repo, project string + var username, action, repo, project, repo_tag, tag_url string var matched bool for _, e := range notification.Events { matched, err = regexp.MatchString(manifestPattern, e.Target.MediaType) @@ -58,13 +64,67 @@ func (n *NotificationHandler) Post() { username = e.Actor.Name action = e.Action repo = e.Target.Repository + tag_url = e.Target.URL + result, err1 := svc_utils.RegistryAPIGet(tag_url, username) + + if err1 != nil { + log.Errorf("Failed to get manifests for repo, repo name: %s, tag: %s, error: %v", repo, tag_url, err1) + return + } + + maniDig := models.ManifestDigest{} + err = json.Unmarshal(result, &maniDig) + if err != nil { + log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repo, tag_url, err) + return + } + + var digestLayers []string + var tagLayers []string + for _, diglayer := range maniDig.Layers { + digestLayers = append(digestLayers, diglayer.Digest) + } + + result, err = svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repo, "tags", "list"), username) + if err != nil { + log.Errorf("Failed to get repo tags, repo name: %s, error: %v", repo, err) + } else { + t := taglist{} + json.Unmarshal(result, &t) + for _, tag := range t.Tags { + result, err = svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repo, "manifests", tag), username) + if err != nil { + log.Errorf("Failed to get repo tags, repo name: %s, error: %v", repo, err) + continue + } + taginfo := models.Manifest{} + err = json.Unmarshal(result, &taginfo) + if err != nil { + log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repo, tag, err) + continue + } + for _, fslayer := range taginfo.FsLayers { + tagLayers = append(tagLayers, fslayer.BlobSum) + } + + sort.Strings(digestLayers) + sort.Strings(tagLayers) + eq := compStringArray(digestLayers, tagLayers) + if eq { + repo_tag = tag + break + } + } + } + if strings.Contains(repo, "/") { project = repo[0:strings.LastIndex(repo, "/")] } if username == "" { username = "anonymous" } - go dao.AccessLog(username, project, repo, action) + log.Debugf("repo tag is : %v ", repo_tag) + go dao.AccessLog(username, project, repo, repo_tag, action) if action == "push" { go func() { err2 := svc_utils.RefreshCatalogCache() @@ -82,3 +142,21 @@ func (n *NotificationHandler) Post() { func (n *NotificationHandler) Render() error { return nil } + +func compStringArray(a, b []string) bool { + if a == nil && b == nil { + return true + } + if a == nil || b == nil { + return false + } + if len(a) != len(b) { + return false + } + for i, v := range a { + if v != b[i] { + return false + } + } + return true +} diff --git a/static/i18n/locale_en-US.ini b/static/i18n/locale_en-US.ini index 981213cf0..e7999607d 100644 --- a/static/i18n/locale_en-US.ini +++ b/static/i18n/locale_en-US.ini @@ -59,6 +59,7 @@ repo = Repositories user = Users logs = Logs repo_name = Repository Name +repo_tag = Tag add_members = Add Members operation = Operation advance = Advanced Search diff --git a/static/i18n/locale_zh-CN.ini b/static/i18n/locale_zh-CN.ini index 90ea4fc04..3f3ef904b 100644 --- a/static/i18n/locale_zh-CN.ini +++ b/static/i18n/locale_zh-CN.ini @@ -59,6 +59,7 @@ repo = 镜像仓库 user = 用户 logs = 日志 repo_name = 镜像名称 +repo_tag = 镜像标签 add_members = 添加成员 operation = 操作 advance = 高级检索 @@ -82,4 +83,4 @@ index_desc_2 = 2. 效率: 搭建组织内部的私有容器Registry服务,可 index_desc_3 = 3. 访问控制: 提供基于角色的访问控制,可集成企业目前拥有的用户管理系统(如:AD/LDAP)。 index_desc_4 = 4. 审计: 所有访问Registry服务的操作均被记录,便于日后审计。 index_desc_5 = 5. 管理界面: 具有友好易用图形管理界面。 -index_title = 企业级 Registry 服务 \ No newline at end of file +index_title = 企业级 Registry 服务 diff --git a/static/resources/js/item-detail.js b/static/resources/js/item-detail.js index 1b6ffa771..6f445f717 100644 --- a/static/resources/js/item-detail.js +++ b/static/resources/js/item-detail.js @@ -286,6 +286,7 @@ jQuery(function(){ '' + '' + e.Username + '' + '' + e.RepoName + '' + + '' + e.RepoTag + '' + '' + e.Operation + '' + '' + moment(new Date(e.OpTime)).format("YYYY-MM-DD HH:mm:ss") + '' + ''); diff --git a/views/item-detail.tpl b/views/item-detail.tpl index a1ce83e96..e9cdb2753 100644 --- a/views/item-detail.tpl +++ b/views/item-detail.tpl @@ -159,10 +159,11 @@ - - - - + + + + + From dc96ded36a4bcc111ed58d5dc60c728a0070c868 Mon Sep 17 00:00:00 2001 From: hmwenchen Date: Fri, 22 Apr 2016 09:18:51 +0800 Subject: [PATCH 30/52] Merge with origin master --- api/project.go | 2 - api/repository.go | 127 ++++++++++++++++++++++++++++++++++++---- models/notification.go | 1 - models/repo.go | 1 - service/notification.go | 99 +++++++++++++++++++------------ 5 files changed, 176 insertions(+), 54 deletions(-) diff --git a/api/project.go b/api/project.go index 2d2aa1e47..9c1a4f678 100644 --- a/api/project.go +++ b/api/project.go @@ -31,7 +31,6 @@ import ( type ProjectAPI struct { BaseAPI userID int - username string projectID int64 } @@ -185,7 +184,6 @@ func (p *ProjectAPI) FilterAccessLog() { } p.Data["json"] = accessLogList - log.Errorf("--- accessLog first record: %v ---", accessLogList[0]) p.ServeJSON() } diff --git a/api/repository.go b/api/repository.go index 252cb2fbc..e259067a4 100644 --- a/api/repository.go +++ b/api/repository.go @@ -18,6 +18,7 @@ package api import ( "encoding/json" "net/http" + "os" "strconv" "strings" "time" @@ -26,6 +27,9 @@ import ( "github.com/vmware/harbor/models" 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" ) // RepositoryAPI handles request to /api/repositories /api/repositories/tags /api/repositories/manifests, the parm has to be put @@ -36,6 +40,7 @@ type RepositoryAPI struct { BaseAPI userID int username string + registry *registry.Registry } // Prepare will set a non existent user ID in case the request tries to view repositories under a project he doesn't has permission. @@ -53,6 +58,43 @@ func (ra *RepositoryAPI) Prepare() { } else { ra.username = username } + + var client *http.Client + + //no session, initialize a standard auth handler + if ra.userID == dao.NonExistUserID && len(ra.username) == 0 { + username, password, _ := ra.Ctx.Request.BasicAuth() + + credential := auth.NewBasicAuthCredential(username, password) + client = registry.NewClientStandardAuthHandlerEmbeded(credential) + log.Debug("initializing standard auth handler") + + } else { + // session works, initialize a username auth handler + username := ra.username + if len(username) == 0 { + user, err := dao.GetUser(models.User{ + UserID: ra.userID, + }) + if err != nil { + log.Errorf("error occurred whiling geting user for initializing a username auth handler: %v", err) + return + } + + username = user.Username + } + + client = registry.NewClientUsernameAuthHandlerEmbeded(username) + log.Debug("initializing username auth handler: %s", username) + } + + endpoint := os.Getenv("REGISTRY_URL") + r, err := registry.New(endpoint, client) + if err != nil { + log.Fatalf("error occurred while initializing auth handler for repository API: %v", err) + } + + ra.registry = r } // Get ... @@ -77,11 +119,13 @@ func (ra *RepositoryAPI) Get() { ra.RenderError(http.StatusForbidden, "") return } + repoList, err := svc_utils.GetRepoFromCache() if err != nil { log.Errorf("Failed to get repo from cache, error: %v", err) ra.RenderError(http.StatusInternalServerError, "internal sever error") } + projectName := p.Name q := ra.GetString("q") var resp []string @@ -105,6 +149,56 @@ func (ra *RepositoryAPI) Get() { ra.ServeJSON() } +// Delete ... +func (ra *RepositoryAPI) Delete() { + repoName := ra.GetString("repo_name") + if len(repoName) == 0 { + ra.CustomAbort(http.StatusBadRequest, "repo_name is nil") + } + + tags := []string{} + tag := ra.GetString("tag") + if len(tag) == 0 { + tagList, err := ra.registry.ListTag(repoName) + if err != nil { + e, ok := errors.ParseError(err) + if ok { + log.Info(e) + ra.CustomAbort(e.StatusCode, e.Message) + } else { + log.Error(err) + ra.CustomAbort(http.StatusInternalServerError, "internal error") + } + + } + tags = append(tags, tagList...) + + } else { + tags = append(tags, tag) + } + + for _, t := range tags { + if err := ra.registry.DeleteTag(repoName, t); err != nil { + e, ok := errors.ParseError(err) + if ok { + ra.CustomAbort(e.StatusCode, e.Message) + } else { + log.Error(err) + ra.CustomAbort(http.StatusInternalServerError, "internal error") + } + } + log.Infof("delete tag: %s %s", repoName, t) + } + + go func() { + log.Debug("refreshing catalog cache") + if err := svc_utils.RefreshCatalogCache(); err != nil { + log.Errorf("error occurred while refresh catalog cache: %v", err) + } + }() + +} + type tag struct { Name string `json:"name"` Tags []string `json:"tags"` @@ -116,15 +210,18 @@ func (ra *RepositoryAPI) GetTags() { var tags []string repoName := ra.GetString("repo_name") - result, err := svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repoName, "tags", "list"), ra.username) + tags, err := ra.registry.ListTag(repoName) if err != nil { - log.Errorf("Failed to get repo tags, repo name: %s, error: %v", repoName, err) - ra.RenderError(http.StatusInternalServerError, "Failed to get repo tags") - } else { - t := tag{} - json.Unmarshal(result, &t) - tags = t.Tags + e, ok := errors.ParseError(err) + if ok { + log.Info(e) + ra.CustomAbort(e.StatusCode, e.Message) + } else { + log.Error(err) + ra.CustomAbort(http.StatusInternalServerError, "internal error") + } } + ra.Data["json"] = tags ra.ServeJSON() } @@ -136,14 +233,19 @@ func (ra *RepositoryAPI) GetManifests() { item := models.RepoItem{} - result, err := svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repoName, "manifests", tag), ra.username) + _, _, payload, err := ra.registry.PullManifest(repoName, tag, registry.ManifestVersion1) if err != nil { - log.Errorf("Failed to get manifests for repo, repo name: %s, tag: %s, error: %v", repoName, tag, err) - ra.RenderError(http.StatusInternalServerError, "Internal Server Error") - return + e, ok := errors.ParseError(err) + if ok { + log.Info(e) + ra.CustomAbort(e.StatusCode, e.Message) + } else { + log.Error(err) + ra.CustomAbort(http.StatusInternalServerError, "internal error") + } } mani := models.Manifest{} - err = json.Unmarshal(result, &mani) + err = json.Unmarshal(payload, &mani) if err != nil { log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repoName, tag, err) ra.RenderError(http.StatusInternalServerError, "Internal Server Error") @@ -157,7 +259,6 @@ func (ra *RepositoryAPI) GetManifests() { ra.RenderError(http.StatusInternalServerError, "Internal Server Error") return } - item.CreatedStr = item.Created.Format("2006-01-02 15:04:05") item.DurationDays = strconv.Itoa(int(time.Since(item.Created).Hours()/24)) + " days" ra.Data["json"] = item diff --git a/models/notification.go b/models/notification.go index 3f30ae7e4..0f608e2c6 100644 --- a/models/notification.go +++ b/models/notification.go @@ -40,7 +40,6 @@ type Target struct { Digest string Repository string URL string `json:"Url"` - Tag string } // Actor holds information about actor. diff --git a/models/repo.go b/models/repo.go index 44abd9d9b..c60910b82 100644 --- a/models/repo.go +++ b/models/repo.go @@ -29,7 +29,6 @@ type RepoItem struct { ID string `json:"Id"` Parent string `json:"Parent"` Created time.Time `json:"Created"` - CreatedStr string `json:"CreatedStr"` DurationDays string `json:"Duration Days"` Author string `json:"Author"` Architecture string `json:"Architecture"` diff --git a/service/notification.go b/service/notification.go index 04611ec21..ecd19d9b8 100644 --- a/service/notification.go +++ b/service/notification.go @@ -17,6 +17,8 @@ package service import ( "encoding/json" + "net/http" + "os" "regexp" "sort" "strings" @@ -25,6 +27,8 @@ import ( "github.com/vmware/harbor/models" 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/errors" "github.com/astaxie/beego" ) @@ -32,11 +36,7 @@ import ( // NotificationHandler handles request on /service/notifications/, which listens to registry's events. type NotificationHandler struct { beego.Controller -} - -type taglist struct { - Name string `json:"name"` - Tags []string `json:"tags"` + registry *registry.Registry } const manifestPattern = `^application/vnd.docker.distribution.manifest.v\d\+json` @@ -52,8 +52,9 @@ func (n *NotificationHandler) Post() { log.Errorf("error while decoding json: %v", err) return } - var username, action, repo, project, repo_tag, tag_url string + var username, action, repo, project, repo_tag, tag_url, digest string var matched bool + var client *http.Client for _, e := range notification.Events { matched, err = regexp.MatchString(manifestPattern, e.Target.MediaType) if err != nil { @@ -65,15 +66,27 @@ func (n *NotificationHandler) Post() { action = e.Action repo = e.Target.Repository tag_url = e.Target.URL - result, err1 := svc_utils.RegistryAPIGet(tag_url, username) + digest = e.Target.Digest + client = registry.NewClientUsernameAuthHandlerEmbeded(username) + log.Debug("initializing username auth handler: %s", username) + endpoint := os.Getenv("REGISTRY_URL") + r, err1 := registry.New(endpoint, client) if err1 != nil { - log.Errorf("Failed to get manifests for repo, repo name: %s, tag: %s, error: %v", repo, tag_url, err1) + log.Fatalf("error occurred while initializing auth handler for repository API: %v", err1) + + } + n.registry = r + + _, _, payload, err2 := n.registry.PullManifest(repo, digest, registry.ManifestVersion1) + + if err2 != nil { + log.Errorf("Failed to get manifests for repo, repo name: %s, tag: %s, error: %v", repo, tag_url, err2) return } maniDig := models.ManifestDigest{} - err = json.Unmarshal(result, &maniDig) + err = json.Unmarshal(payload, &maniDig) if err != nil { log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repo, tag_url, err) return @@ -85,36 +98,48 @@ func (n *NotificationHandler) Post() { digestLayers = append(digestLayers, diglayer.Digest) } - result, err = svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repo, "tags", "list"), username) + tags, err := n.registry.ListTag(repo) if err != nil { - log.Errorf("Failed to get repo tags, repo name: %s, error: %v", repo, err) - } else { - t := taglist{} - json.Unmarshal(result, &t) - for _, tag := range t.Tags { - result, err = svc_utils.RegistryAPIGet(svc_utils.BuildRegistryURL(repo, "manifests", tag), username) - if err != nil { - log.Errorf("Failed to get repo tags, repo name: %s, error: %v", repo, err) - continue - } - taginfo := models.Manifest{} - err = json.Unmarshal(result, &taginfo) - if err != nil { - log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repo, tag, err) - continue - } - for _, fslayer := range taginfo.FsLayers { - tagLayers = append(tagLayers, fslayer.BlobSum) - } - - sort.Strings(digestLayers) - sort.Strings(tagLayers) - eq := compStringArray(digestLayers, tagLayers) - if eq { - repo_tag = tag - break - } + e, ok := errors.ParseError(err) + if ok { + log.Info(e) + } else { + log.Error(err) } + return + } + + log.Infof("tags : %v ", tags) + + for _, tag := range tags { + _, _, payload, err := n.registry.PullManifest(repo, tag, registry.ManifestVersion1) + if err != nil { + e, ok := errors.ParseError(err) + if ok { + log.Info(e) + } else { + log.Error(err) + } + continue + } + taginfo := models.Manifest{} + err = json.Unmarshal(payload, &taginfo) + if err != nil { + log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repo, tag, err) + continue + } + for _, fslayer := range taginfo.FsLayers { + tagLayers = append(tagLayers, fslayer.BlobSum) + } + + sort.Strings(digestLayers) + sort.Strings(tagLayers) + eq := compStringArray(digestLayers, tagLayers) + if eq { + repo_tag = tag + break + } + } if strings.Contains(repo, "/") { From 436acd06420b860a226386942ccfb17cea37e174 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Fri, 22 Apr 2016 13:45:38 +0800 Subject: [PATCH 31/52] update file --- docs/customize token service.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/customize token service.md b/docs/customize token service.md index 1f9f79a1f..ca358b2ae 100644 --- a/docs/customize token service.md +++ b/docs/customize token service.md @@ -11,10 +11,14 @@ By default, Harbor uses default private key and certificate in authentication. A **1)Generate a private key:** ```sh - openssl genrsa -out private_key.pem 4096 + $ openssl genrsa -out private_key.pem 4096 ``` -**2)Generate a certificate:** You are about to be asked to enter information that will be incorporated into your certificate request. +**2)Generate a certificate:** +```sh + $ openssl req -new -x509 -key private_key.pem -out root.crt -days 3650 +``` +You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, @@ -34,25 +38,21 @@ Common Name (eg, server FQDN or YOUR name) []: Email Address []: -```sh - openssl req -new -x509 -key private_key.pem -out root.crt -days 3650 -``` After you execute these two commands, you will see private_key.pem and root.crt in the **current directory**, just type "ls", you'll see them. 3.Refer to [Installation Guide](https://github.com/vmware/harbor/blob/master/docs/installation_guide.md) to install Harbor, After you execute ./prepare, Harbor generates several config files. We need to replace the original private key and certificate with your own key and certificate. -4.Following are what you should do: - -**1)cd config/ui, you will see private_key.pem.** - -**2)replace private_key.pem with your private_key.pem** - -**3)cd ../registry, you will see root.crt. Replace it with your root.crt** - +4.Replace the default key and certificate. Assume that you key and certificate are in the directory /root/cert, following are what you should do: + +``` +$ cd config/ui +$ cp /root/cert/private_key.pem private_key.pem +$ cp /root/cert/root.crt ../registry/root.crt +``` 5.After these, go back to the Deploy directory, you can start Harbor using following command: ``` - docker-compose up -d + $ docker-compose up -d ``` 6.Then you can push/pull images to see if your own certificate works. Please refer [User Guide](https://github.com/vmware/harbor/blob/master/docs/user_guide.md) for more info. From d12c6b14a8be73bca3cef6eb06a05cdfe1f34b39 Mon Sep 17 00:00:00 2001 From: wemeya Date: Fri, 22 Apr 2016 14:01:41 +0800 Subject: [PATCH 32/52] add the docker-compose.yml file for domestic user to pull images faster. --- contrib/docker-compose-daocloud.yml | 68 +++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 contrib/docker-compose-daocloud.yml diff --git a/contrib/docker-compose-daocloud.yml b/contrib/docker-compose-daocloud.yml new file mode 100644 index 000000000..e93fb42f1 --- /dev/null +++ b/contrib/docker-compose-daocloud.yml @@ -0,0 +1,68 @@ +version: '2' +services: + log: + image: daocloud.io/harbor/deploy_log:latest + volumes: + - /var/log/harbor/:/var/log/docker/ + ports: + - 1514:514 + registry: + image: daocloud.io/library/registry:2.3.0 + volumes: + - /data/registry:/storage + - ./config/registry/:/etc/registry/ + ports: + - 5001:5001 + command: + /etc/registry/config.yml + depends_on: + - log + logging: + driver: "syslog" + options: + syslog-address: "tcp://127.0.0.1:1514" + syslog-tag: "registry" + mysql: + image: daocloud.io/harbor/deploy_mysql:latest + volumes: + - /data/database:/var/lib/mysql + env_file: + - ./config/db/env + depends_on: + - log + logging: + driver: "syslog" + options: + syslog-address: "tcp://127.0.0.1:1514" + syslog-tag: "mysql" + ui: + image: daocloud.io/harbor/deploy_ui:latest + env_file: + - ./config/ui/env + volumes: + - ./config/ui/app.conf:/etc/ui/app.conf + - ./config/ui/private_key.pem:/etc/ui/private_key.pem + depends_on: + - log + logging: + driver: "syslog" + options: + syslog-address: "tcp://127.0.0.1:1514" + syslog-tag: "ui" + proxy: + image: daocloud.io/library/nginx:1.9 + volumes: + - ./config/nginx:/etc/nginx + ports: + - 80:80 + - 443:443 + depends_on: + - mysql + - registry + - ui + - log + logging: + driver: "syslog" + options: + syslog-address: "tcp://127.0.0.1:1514" + syslog-tag: "proxy" From 932814b8880fd3134c158dc2123ab3ed77e26768 Mon Sep 17 00:00:00 2001 From: wemeya Date: Fri, 22 Apr 2016 15:14:30 +0800 Subject: [PATCH 33/52] add doc for domestic user to pull images faster --- docs/fast way to pull images.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 docs/fast way to pull images.md diff --git a/docs/fast way to pull images.md b/docs/fast way to pull images.md new file mode 100644 index 000000000..ce7f2986a --- /dev/null +++ b/docs/fast way to pull images.md @@ -0,0 +1,9 @@ +### A faster way to pull images for Chinese Harbor users +By default, Harbor not only build images according to Dockerfile but also pull images from Docker Hub. For the reason we all know, it is difficult for Chinese Harbor users to pull images from the Docker Hub. We put images on daocloud.io platform, we'll put images on other platforms later. If you have difficulty to pull images from Docker Hub, or you think it wastes too much time to build images. We recommend you to use the following way to accelerate the pulling procedure(make sure you're in the harbor diectory): +``` +$ cd contrib +$ mv docker-compose-daocloud.yml docker-compose.yml +$ cp docker-compose.yml ../Deploy +$ docker-compose up -d +``` +Then you'll see docker pulling imges faster than before. \ No newline at end of file From 94422e9a716fbd381148e37513528501e4321d5f Mon Sep 17 00:00:00 2001 From: wy65701436 Date: Fri, 22 Apr 2016 02:57:39 -0700 Subject: [PATCH 34/52] add post return, add the URI to header location. --- api/base.go | 6 ++++++ api/project.go | 10 +++++++++- api/user.go | 6 +++++- dao/dao_test.go | 2 +- dao/project.go | 16 ++++++++-------- static/resources/js/register.js | 2 +- 6 files changed, 30 insertions(+), 12 deletions(-) diff --git a/api/base.go b/api/base.go index 70388009e..c44b7bec2 100644 --- a/api/base.go +++ b/api/base.go @@ -86,3 +86,9 @@ func (b *BaseAPI) ValidateUser() int { } return userID } + +// Redirect does redirection to localurl with http header status code. +// It sends http response header directly. +func (b *BaseAPI) Redirect(statusCode int, location string) { + b.Ctx.Redirect(statusCode, location) +} diff --git a/api/project.go b/api/project.go index dbc0a4ecb..d71c6d02b 100644 --- a/api/project.go +++ b/api/project.go @@ -18,6 +18,8 @@ package api import ( "fmt" "net/http" + "os" + "strings" "github.com/vmware/harbor/dao" "github.com/vmware/harbor/models" @@ -32,6 +34,7 @@ type ProjectAPI struct { BaseAPI userID int projectID int64 + HarborURL string } type projectReq struct { @@ -43,6 +46,8 @@ const projectNameMaxLen int = 30 // Prepare validates the URL and the user func (p *ProjectAPI) Prepare() { + p.HarborURL = strings.ToLower(os.Getenv("HARBOR_URL")) + p.userID = p.ValidateUser() idStr := p.Ctx.Input.Param(":id") if len(idStr) > 0 { @@ -87,11 +92,14 @@ func (p *ProjectAPI) Post() { return } project := models.Project{OwnerID: p.userID, Name: projectName, CreationTime: time.Now(), Public: public} - err = dao.AddProject(project) + projectID, err := dao.AddProject(project) if err != nil { log.Errorf("Failed to add project, error: %v", err) p.RenderError(http.StatusInternalServerError, "Failed to add project") } + + projectLocation := p.HarborURL + "/api/projects/" + strconv.FormatInt(projectID, 10) + p.Redirect(http.StatusCreated, projectLocation) } // Head ... diff --git a/api/user.go b/api/user.go index 1f4882e1c..e9d8aaae0 100644 --- a/api/user.go +++ b/api/user.go @@ -34,6 +34,7 @@ type UserAPI struct { SelfRegistration bool IsAdmin bool AuthMode string + HarborURL string } type passwordReq struct { @@ -54,6 +55,7 @@ func (ua *UserAPI) Prepare() { if selfRegistration == "on" { ua.SelfRegistration = true } + ua.HarborURL = strings.ToLower(os.Getenv("HARBOR_URL")) if ua.Ctx.Input.IsPost() { sessionUserID := ua.GetSession("userId") @@ -158,13 +160,15 @@ func (ua *UserAPI) Post() { user := models.User{} ua.DecodeJSONReq(&user) - _, err := dao.Register(user) + userID, err := dao.Register(user) if err != nil { log.Errorf("Error occurred in Register: %v", err) ua.RenderError(http.StatusInternalServerError, "Internal error.") return } + userLocation := ua.HarborURL + "/api/users/" + strconv.FormatInt(userID, 10) + ua.Redirect(http.StatusCreated, userLocation) } // Delete ... diff --git a/dao/dao_test.go b/dao/dao_test.go index 67ccef833..da0ad6993 100644 --- a/dao/dao_test.go +++ b/dao/dao_test.go @@ -372,7 +372,7 @@ func TestAddProject(t *testing.T) { OwnerName: currentUser.Username, } - err := AddProject(project) + _, err := AddProject(project) if err != nil { t.Errorf("Error occurred in AddProject: %v", err) } diff --git a/dao/project.go b/dao/project.go index d2a611e9f..5a6152029 100644 --- a/dao/project.go +++ b/dao/project.go @@ -29,41 +29,41 @@ import ( //TODO:transaction, return err // AddProject adds a project to the database along with project roles information and access log records. -func AddProject(project models.Project) error { +func AddProject(project models.Project) (int64, error) { if isIllegalLength(project.Name, 4, 30) { - return errors.New("project name is illegal in length. (greater than 4 or less than 30)") + return 0, errors.New("project name is illegal in length. (greater than 4 or less than 30)") } if isContainIllegalChar(project.Name, []string{"~", "-", "$", "\\", "[", "]", "{", "}", "(", ")", "&", "^", "%", "*", "<", ">", "\"", "'", "/", "?", "@"}) { - return errors.New("project name contains illegal characters") + return 0, errors.New("project name contains illegal characters") } o := orm.NewOrm() p, err := o.Raw("insert into project (owner_id, name, creation_time, update_time, deleted, public) values (?, ?, ?, ?, ?, ?)").Prepare() if err != nil { - return err + return 0, err } now := time.Now() r, err := p.Exec(project.OwnerID, project.Name, now, now, project.Deleted, project.Public) if err != nil { - return err + return 0, err } projectID, err := r.LastInsertId() if err != nil { - return err + return 0, err } if err = AddProjectMember(projectID, project.OwnerID, models.PROJECTADMIN); err != nil { - return err + return projectID, err } accessLog := models.AccessLog{UserID: project.OwnerID, ProjectID: projectID, RepoName: project.Name + "/", GUID: "N/A", Operation: "create", OpTime: time.Now()} err = AddAccessLog(accessLog) - return err + return projectID, err } // IsProjectPublic ... diff --git a/static/resources/js/register.js b/static/resources/js/register.js index 8f970946f..3fa2882b4 100644 --- a/static/resources/js/register.js +++ b/static/resources/js/register.js @@ -57,7 +57,7 @@ jQuery(function(){ }, complete: function(xhr, status){ $("#btnPageSignUp").prop("disabled", false); - if(xhr && xhr.status == 200){ + if(xhr && xhr.status == 201){ $("#dlgModal") .dialogModal({ "title": isAdmin == "true" ? i18n.getMessage("title_add_user") : i18n.getMessage("title_sign_up"), From b443b3fe7fa83d68577f6bd312a58cf9cd746f57 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Fri, 22 Apr 2016 17:58:31 +0800 Subject: [PATCH 35/52] Rename --- docs/{customize token service.md => customize_token_service.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename docs/{customize token service.md => customize_token_service.md} (100%) diff --git a/docs/customize token service.md b/docs/customize_token_service.md similarity index 100% rename from docs/customize token service.md rename to docs/customize_token_service.md From 7ed3f31f8b16dfac87f0b6deefb66ebc9be06190 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Fri, 22 Apr 2016 18:02:46 +0800 Subject: [PATCH 36/52] update and rename --- ...ay to pull images.md => image_pulling_chinese_user.md} | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) rename docs/{fast way to pull images.md => image_pulling_chinese_user.md} (74%) diff --git a/docs/fast way to pull images.md b/docs/image_pulling_chinese_user.md similarity index 74% rename from docs/fast way to pull images.md rename to docs/image_pulling_chinese_user.md index ce7f2986a..f16c7a4b7 100644 --- a/docs/fast way to pull images.md +++ b/docs/image_pulling_chinese_user.md @@ -2,8 +2,10 @@ By default, Harbor not only build images according to Dockerfile but also pull images from Docker Hub. For the reason we all know, it is difficult for Chinese Harbor users to pull images from the Docker Hub. We put images on daocloud.io platform, we'll put images on other platforms later. If you have difficulty to pull images from Docker Hub, or you think it wastes too much time to build images. We recommend you to use the following way to accelerate the pulling procedure(make sure you're in the harbor diectory): ``` $ cd contrib -$ mv docker-compose-daocloud.yml docker-compose.yml -$ cp docker-compose.yml ../Deploy +$ cp docker-compose.yml.daocloud ../Deploy +$ cd ../Deploy +$ mv docker-compose.yml docker-compose.yml.bak +$ mv docker-compose.yml.daocloud docker-compose.yml $ docker-compose up -d ``` -Then you'll see docker pulling imges faster than before. \ No newline at end of file +Then you'll see docker pulling imges faster than before. From b8f29fb9bca6e6b7ae91c7181bee62a098881551 Mon Sep 17 00:00:00 2001 From: wemeya <1013939285@qq.com> Date: Fri, 22 Apr 2016 18:03:40 +0800 Subject: [PATCH 37/52] Rename --- .../{docker-compose-daocloud.yml => docker-compose.yml.daocloud} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename contrib/{docker-compose-daocloud.yml => docker-compose.yml.daocloud} (100%) diff --git a/contrib/docker-compose-daocloud.yml b/contrib/docker-compose.yml.daocloud similarity index 100% rename from contrib/docker-compose-daocloud.yml rename to contrib/docker-compose.yml.daocloud From 957df50958ce113919cc8318a61bfaba95425314 Mon Sep 17 00:00:00 2001 From: hmwenchen Date: Fri, 22 Apr 2016 20:26:28 +0800 Subject: [PATCH 38/52] Minor change to comply with CI requirements --- dao/accesslog.go | 2 +- models/repo.go | 2 ++ service/notification.go | 14 +++++++------- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/dao/accesslog.go b/dao/accesslog.go index 20fb20655..dbf447353 100644 --- a/dao/accesslog.go +++ b/dao/accesslog.go @@ -96,7 +96,7 @@ func GetAccessLogs(accessLog models.AccessLog) ([]models.AccessLog, error) { return accessLogList, nil } -// AccessLog, invoked in service/notification.go +// AccessLog ... func AccessLog(username, projectName, repoName, repoTag, action string) error { o := orm.NewOrm() sql := "insert into access_log (user_id, project_id, repo_name, repo_tag, operation, op_time) " + diff --git a/models/repo.go b/models/repo.go index c60910b82..4ace8d1b6 100644 --- a/models/repo.go +++ b/models/repo.go @@ -43,6 +43,7 @@ type Tag struct { ImageID string `json:"image_id"` } +// Manifest ... type Manifest struct { SchemaVersion int `json:"schemaVersion"` Name string `json:"name"` @@ -60,6 +61,7 @@ type blobSumItem struct { BlobSum string `json:"blobSum"` } +// ManifestDigest ... type ManifestDigest struct { MediaType string `json:"mediaType"` SchemaVersion int `json:"schemaVersion"` diff --git a/service/notification.go b/service/notification.go index ecd19d9b8..f47ddd627 100644 --- a/service/notification.go +++ b/service/notification.go @@ -52,7 +52,7 @@ func (n *NotificationHandler) Post() { log.Errorf("error while decoding json: %v", err) return } - var username, action, repo, project, repo_tag, tag_url, digest string + var username, action, repo, project, repoTag, tagURL, digest string var matched bool var client *http.Client for _, e := range notification.Events { @@ -65,7 +65,7 @@ func (n *NotificationHandler) Post() { username = e.Actor.Name action = e.Action repo = e.Target.Repository - tag_url = e.Target.URL + tagURL = e.Target.URL digest = e.Target.Digest client = registry.NewClientUsernameAuthHandlerEmbeded(username) @@ -81,14 +81,14 @@ func (n *NotificationHandler) Post() { _, _, payload, err2 := n.registry.PullManifest(repo, digest, registry.ManifestVersion1) if err2 != nil { - log.Errorf("Failed to get manifests for repo, repo name: %s, tag: %s, error: %v", repo, tag_url, err2) + log.Errorf("Failed to get manifests for repo, repo name: %s, tag: %s, error: %v", repo, tagURL, err2) return } maniDig := models.ManifestDigest{} err = json.Unmarshal(payload, &maniDig) if err != nil { - log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repo, tag_url, err) + log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repo, tagURL, err) return } @@ -136,7 +136,7 @@ func (n *NotificationHandler) Post() { sort.Strings(tagLayers) eq := compStringArray(digestLayers, tagLayers) if eq { - repo_tag = tag + repoTag = tag break } @@ -148,8 +148,8 @@ func (n *NotificationHandler) Post() { if username == "" { username = "anonymous" } - log.Debugf("repo tag is : %v ", repo_tag) - go dao.AccessLog(username, project, repo, repo_tag, action) + log.Debugf("repo tag is : %v ", repoTag) + go dao.AccessLog(username, project, repo, repoTag, action) if action == "push" { go func() { err2 := svc_utils.RefreshCatalogCache() From 9c655e710b4f4d4e009da5aeebcd6508290c7883 Mon Sep 17 00:00:00 2001 From: wy65701436 Date: Sun, 24 Apr 2016 21:10:15 -0700 Subject: [PATCH 39/52] Change to get uri from http request, and response with relative path of resource. --- api/base.go | 10 ++++++---- api/project.go | 8 +------- api/user.go | 5 +---- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/api/base.go b/api/base.go index c44b7bec2..f2529b61e 100644 --- a/api/base.go +++ b/api/base.go @@ -87,8 +87,10 @@ func (b *BaseAPI) ValidateUser() int { return userID } -// Redirect does redirection to localurl with http header status code. -// It sends http response header directly. -func (b *BaseAPI) Redirect(statusCode int, location string) { - b.Ctx.Redirect(statusCode, location) +// Redirect does redirection to resource URI with http header status code. +func (b *BaseAPI) Redirect(statusCode int, resouceID string) { + requestURI := b.Ctx.Request.RequestURI + resoucreURI := requestURI + "/" + resouceID + + b.Ctx.Redirect(statusCode, resoucreURI) } diff --git a/api/project.go b/api/project.go index d71c6d02b..7e6f46e7e 100644 --- a/api/project.go +++ b/api/project.go @@ -18,8 +18,6 @@ package api import ( "fmt" "net/http" - "os" - "strings" "github.com/vmware/harbor/dao" "github.com/vmware/harbor/models" @@ -34,7 +32,6 @@ type ProjectAPI struct { BaseAPI userID int projectID int64 - HarborURL string } type projectReq struct { @@ -46,8 +43,6 @@ const projectNameMaxLen int = 30 // Prepare validates the URL and the user func (p *ProjectAPI) Prepare() { - p.HarborURL = strings.ToLower(os.Getenv("HARBOR_URL")) - p.userID = p.ValidateUser() idStr := p.Ctx.Input.Param(":id") if len(idStr) > 0 { @@ -98,8 +93,7 @@ func (p *ProjectAPI) Post() { p.RenderError(http.StatusInternalServerError, "Failed to add project") } - projectLocation := p.HarborURL + "/api/projects/" + strconv.FormatInt(projectID, 10) - p.Redirect(http.StatusCreated, projectLocation) + p.Redirect(http.StatusCreated, strconv.FormatInt(projectID, 10)) } // Head ... diff --git a/api/user.go b/api/user.go index e9d8aaae0..c9bb99800 100644 --- a/api/user.go +++ b/api/user.go @@ -34,7 +34,6 @@ type UserAPI struct { SelfRegistration bool IsAdmin bool AuthMode string - HarborURL string } type passwordReq struct { @@ -55,7 +54,6 @@ func (ua *UserAPI) Prepare() { if selfRegistration == "on" { ua.SelfRegistration = true } - ua.HarborURL = strings.ToLower(os.Getenv("HARBOR_URL")) if ua.Ctx.Input.IsPost() { sessionUserID := ua.GetSession("userId") @@ -167,8 +165,7 @@ func (ua *UserAPI) Post() { return } - userLocation := ua.HarborURL + "/api/users/" + strconv.FormatInt(userID, 10) - ua.Redirect(http.StatusCreated, userLocation) + ua.Redirect(http.StatusCreated, strconv.FormatInt(userID, 10)) } // Delete ... From 57081792de330ae53c327dbeeb9689e21d37135a Mon Sep 17 00:00:00 2001 From: Tan Jiang Date: Mon, 25 Apr 2016 19:00:36 +0800 Subject: [PATCH 40/52] adapt to other ldap servers --- auth/ldap/ldap.go | 27 +++++++++++---------------- dao/register.go | 12 ++---------- 2 files changed, 13 insertions(+), 26 deletions(-) diff --git a/auth/ldap/ldap.go b/auth/ldap/ldap.go index 53d17a174..8de4d47fb 100644 --- a/auth/ldap/ldap.go +++ b/auth/ldap/ldap.go @@ -76,31 +76,25 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) { scope := openldap.LDAP_SCOPE_SUBTREE // LDAP_SCOPE_BASE, LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE filter := "objectClass=*" - attributes := []string{"cn", "mail", "uid"} + attributes := []string{"mail"} result, err := ldap.SearchAll(baseDn, scope, filter, attributes) if err != nil { return nil, err } - if len(result.Entries()) != 1 { - log.Warningf("Found more than one entry.") - return nil, nil - } - en := result.Entries()[0] u := models.User{} - for _, attr := range en.Attributes() { - val := attr.Values()[0] - switch attr.Name() { - case "uid": - u.Username = val - case "mail": - u.Email = val - case "cn": - u.Realname = val + if len(result.Entries()) == 1 { + en := result.Entries()[0] + for _, attr := range en.Attributes() { + val := attr.Values()[0] + if attr.Name() == "mail" { + u.Email = val + } } } - log.Debug("username:", u.Username, ",email:", u.Email, ",realname:", u.Realname) + u.Username = m.Principal + log.Debug("username:", u.Username, ",email:", u.Email) exist, err := dao.UserExists(u, "username") if err != nil { @@ -114,6 +108,7 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) { } u.UserID = currentUser.UserID } else { + u.Realname = m.Principal u.Password = "12345678AbC" u.Comment = "registered from LDAP." userID, err := dao.Register(u) diff --git a/dao/register.go b/dao/register.go index f3e66cb1a..95798b380 100644 --- a/dao/register.go +++ b/dao/register.go @@ -17,7 +17,7 @@ package dao import ( "errors" - "regexp" + // "regexp" "time" "github.com/vmware/harbor/models" @@ -74,15 +74,7 @@ func validate(user models.User) error { return errors.New("Username already exists.") } - if m, _ := regexp.MatchString(`^(([^<>()[\]\\.,;:\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,}))$`, user.Email); !m { - return errors.New("Email with illegal format.") - } - - if isIllegalLength(user.Email, 0, -1) { - return errors.New("Email cannot empty.") - } - - if exist, _ := UserExists(models.User{Email: user.Email}, "email"); exist { + if exist, _ := UserExists(models.User{Email: user.Email}, "email"); len(user.Email) > 0 && exist { return errors.New("Email already exists.") } From 867b4bc352e8ed0788ab3b2af6fd53a7af8e3724 Mon Sep 17 00:00:00 2001 From: Tan Jiang Date: Tue, 26 Apr 2016 11:18:34 +0800 Subject: [PATCH 41/52] add email check --- dao/register.go | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/dao/register.go b/dao/register.go index 95798b380..6f5351504 100644 --- a/dao/register.go +++ b/dao/register.go @@ -17,7 +17,7 @@ package dao import ( "errors" - // "regexp" + "regexp" "time" "github.com/vmware/harbor/models" @@ -74,8 +74,13 @@ func validate(user models.User) error { return errors.New("Username already exists.") } - if exist, _ := UserExists(models.User{Email: user.Email}, "email"); len(user.Email) > 0 && exist { - return errors.New("Email already exists.") + if len(user.Email) > 0 { + if m, _ := regexp.MatchString(`^(([^<>()[\]\\.,;:\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,}))$`, user.Email); !m { + return errors.New("Email with illegal format.") + } + if exist, _ := UserExists(models.User{Email: user.Email}, "email"); exist { + return errors.New("Email already exists.") + } } if isIllegalLength(user.Realname, 0, 20) { From 2da163430a9412398c4b26e530564b9d070a4f8e Mon Sep 17 00:00:00 2001 From: Robin Naundorf Date: Tue, 26 Apr 2016 08:48:11 +0200 Subject: [PATCH 42/52] Fixed issue with undefined values in admin tab --- static/resources/js/project.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/resources/js/project.js b/static/resources/js/project.js index 69ab51a5f..97da2d6f9 100644 --- a/static/resources/js/project.js +++ b/static/resources/js/project.js @@ -161,8 +161,8 @@ jQuery(function(){ $("#tblUser tbody tr").remove(); $.each(data || [], function(i, e){ var row = '' + - '' + - ''; + '' + + ''; if(e.HasAdminRole == 1){ row += ''; } else { From 8f1c74e086978ea880c7896a9a368a43ef948764 Mon Sep 17 00:00:00 2001 From: xiahaoshawn Date: Tue, 26 Apr 2016 14:52:10 +0800 Subject: [PATCH 43/52] update registry to 2.4.0 --- Deploy/docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Deploy/docker-compose.yml b/Deploy/docker-compose.yml index a00421fb7..2e9147ee1 100644 --- a/Deploy/docker-compose.yml +++ b/Deploy/docker-compose.yml @@ -7,14 +7,14 @@ services: ports: - 1514:514 registry: - image: library/registry:2.3.0 + image: library/registry:2.4.0 volumes: - /data/registry:/storage - ./config/registry/:/etc/registry/ ports: - 5001:5001 command: - /etc/registry/config.yml + ["serve", "/etc/registry/config.yml"] depends_on: - log logging: From fde71eaa20dd9884794f02a85736f6826c1b3ffc Mon Sep 17 00:00:00 2001 From: Robin Naundorf Date: Tue, 26 Apr 2016 09:36:23 +0200 Subject: [PATCH 44/52] Updated admin tab layout to match the width with other tabs --- views/project.tpl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/views/project.tpl b/views/project.tpl index af8ca3b96..fae2878d1 100644 --- a/views/project.tpl +++ b/views/project.tpl @@ -42,7 +42,7 @@ - + @@ -65,9 +65,9 @@
{{i18n .Lang "username"}}{{i18n .Lang "repo_name"}}{{i18n .Lang "operation"}}{{i18n .Lang "timestamp"}}{{i18n .Lang "username"}}{{i18n .Lang "repo_name"}}{{i18n .Lang "repo_tag"}}{{i18n .Lang "operation"}}{{i18n .Lang "timestamp"}}
' + e.Username + '' + e.Email + '' + e.username + '' + e.email + '
{{i18n .Lang "project_name"}} {{i18n .Lang "creation_time"}}{{i18n .Lang "publicity"}}{{i18n .Lang "publicity"}}
- - - + + + From dc2d33a2bce50c0d10908c7307a87e32288a527f Mon Sep 17 00:00:00 2001 From: Robin Naundorf Date: Mon, 25 Apr 2016 17:35:54 +0200 Subject: [PATCH 45/52] Added german locale --- Deploy/templates/ui/app.conf | 4 +- controllers/login.go | 2 +- static/i18n/locale_de-DE.ini | 86 +++++++++++++ static/i18n/locale_en-US.ini | 1 + static/i18n/locale_messages.js | 215 ++++++++++++++++++++----------- static/i18n/locale_zh-CN.ini | 3 +- static/resources/js/common.js | 5 +- views/segment/header-content.tpl | 3 +- 8 files changed, 236 insertions(+), 83 deletions(-) create mode 100644 static/i18n/locale_de-DE.ini diff --git a/Deploy/templates/ui/app.conf b/Deploy/templates/ui/app.conf index 70dddbc89..a5cf4dfdf 100644 --- a/Deploy/templates/ui/app.conf +++ b/Deploy/templates/ui/app.conf @@ -2,8 +2,8 @@ appname = registry runmode = dev [lang] -types = en-US|zh-CN -names = en-US|zh-CN +types = en-US|zh-CN|de-DE +names = en-US|zh-CN|de-DE [dev] httpport = 80 diff --git a/controllers/login.go b/controllers/login.go index f87c3dfc3..42d324f08 100644 --- a/controllers/login.go +++ b/controllers/login.go @@ -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" { + if lang == "en-US" || lang == "zh-CN" || lang == "de-DE" { c.SetSession("lang", lang) c.Data["Lang"] = lang } diff --git a/static/i18n/locale_de-DE.ini b/static/i18n/locale_de-DE.ini new file mode 100644 index 000000000..67a926c72 --- /dev/null +++ b/static/i18n/locale_de-DE.ini @@ -0,0 +1,86 @@ +page_title_index = Harbor +page_title_sign_in = Anmelden - Harbor +page_title_project = Projekt - Harbor +page_title_item_details = Details - Harbor +page_title_registration = Registrieren - Harbor +page_title_add_user = Benutzer anlegen - Harbor +page_title_forgot_password = Passwort vergessen - Harbor +title_forgot_password = Passwort vergessen +page_title_reset_password = Passwort zurücksetzen - Harbor +title_reset_password = Passwort zurücksetzen +page_title_change_password = Passwort ändern - Harbor +title_change_password = Passwort ändern +page_title_search = Suche - Harbor +sign_in = Anmelden +sign_up = Registrieren +add_user = Benutzer anlegen +log_out = Abmelden +search_placeholder = Projekte oder Repositories +change_password = Passwort ändern +username_email = Benutzername/E-Mail +password = Passwort +forgot_password = Passwort vergessen +welcome = Willkommen +my_projects = Meine Projekte +public_projects = Öffentliche Projekte +admin_options = Admin Optionen +project_name = Projektname +creation_time = Erstellungsdatum +publicity = Öffentlich +add_project = Projekt hinzufügen +check_for_publicity = öffentliches Projekt +button_save = Speichern +button_cancel = Abbrechen +button_submit = Absenden +username = Benutzername +email = E-Mail +system_admin = System Admininistrator +dlg_button_ok = OK +dlg_button_cancel = Abbrechen +registration = Registrieren +username_description = Dies wird Ihr Benutzername sein. +email_description = Die E-Mail Adresse wird für das Zurücksetzen des Passworts genutzt. +full_name = Sollständiger Name +full_name_description = Vor- und Nachname. +password_description = Mindestens sieben Zeichen bestehend aus einem Kleinbuchstaben, einem Großbuchstaben und einer Zahl +confirm_password = Passwort bestätigen +note_to_the_admin = Kommentar +old_password = Altes Passwort +new_password = Neues Passwort +forgot_password_description = Bitte gebe die E-Mail Adresse ein, die du zur Registrierung verwendet hast. Ein Link zur Wiederherstellung wird dir per E-Mail an diese Adresse geschickt. + +projects = Projekte +repositories = Repositories +search = Suche +home = Home +project = Projekt +owner = Besitzer +repo = Repositories +user = Benutzer +logs = Logs +repo_name = Repository +add_members = Benutzer hinzufügen +operation = Aktion +advance = erweiterte Suche +all = Alle +others = Andere +start_date = Start Datum +end_date = End Datum +timestamp = Zeitstempel +role = Rolle +reset_email_hint = Bitte klicke auf diesen Link um dein Passwort zurückzusetzen +reset_email_subject = Passwort zurücksetzen +language = Deutsch +language_en-US = English +language_zh-CN = 中文 +language_de-DE = Deutsch +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. +index_desc_0 = Vorteile: +index_desc_1 = 1. Sicherheit: Halten Sie ihr geistiges Eigentum innerhalb der Organisation. +index_desc_2 = 2. Effizienz: Ein privater Registry Server innerhalb des Netzwerks ihrer Organisation kann den Traffic zu öffentlichen Services im Internet signifikant reduzieren. +index_desc_3 = 3. Zugriffskontrolle: RBAC (Role Based Access Control) wird zur Verfügung gestellt. Benutzerverwaltung kann mit bestehenden Identitätsservices wie AD/LDAP integriert werden. +index_desc_4 = 4. Audit: Jeglicher Zugriff auf die Registry wird protokolliert und kann für ein Audit verwendet werden. +index_desc_5 = 5. GUI: Benutzerfreundliche Verwaltung über eine einzige Management-Konsole +index_title = Ein Enterprise-Class Registry Server diff --git a/static/i18n/locale_en-US.ini b/static/i18n/locale_en-US.ini index 981213cf0..7a51acb6c 100644 --- a/static/i18n/locale_en-US.ini +++ b/static/i18n/locale_en-US.ini @@ -73,6 +73,7 @@ reset_email_subject = Reset your password language = English language_en-US = English language_zh-CN = 中文 +language_de-DE = Deutsch 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. diff --git a/static/i18n/locale_messages.js b/static/i18n/locale_messages.js index 93fdcaabb..d2eb902a4 100644 --- a/static/i18n/locale_messages.js +++ b/static/i18n/locale_messages.js @@ -15,254 +15,317 @@ var global_messages = { "username_is_required" : { "en-US": "Username is required.", - "zh-CN": "用户名为必填项。" + "zh-CN": "用户名为必填项。", + "de-DE": "Benutzername erforderlich." }, "username_has_been_taken" : { - "en-US": "Username has been taken.", - "zh-CN": "用户名已被占用。" + "en-US": "Username has been taken.", + "zh-CN": "用户名已被占用。", + "de-DE": "Benutzername bereits vergeben." }, "username_is_too_long" : { "en-US": "Username is too long. (maximum 20 characters)", - "zh-CN": "用户名长度超出限制。(最长为20个字符)" + "zh-CN": "用户名长度超出限制。(最长为20个字符)", + "de-DE": "Benutzername ist zu lang. (maximal 20 Zeichen)" }, "username_contains_illegal_chars": { "en-US": "Username contains illegal character(s).", - "zh-CN": "用户名包含不合法的字符。" + "zh-CN": "用户名包含不合法的字符。", + "de-DE": "Benutzername enthält ungültige Zeichen." }, "email_is_required" : { "en-US": "Email is required.", - "zh-CN": "邮箱为必填项。" + "zh-CN": "邮箱为必填项。", + "de-DE": "E-Mail Adresse erforderlich." }, "email_contains_illegal_chars" : { "en-US": "Email contains illegal character(s).", - "zh-CN": "邮箱包含不合法的字符。" + "zh-CN": "邮箱包含不合法的字符。", + "de-DE": "E-Mail Adresse enthält ungültige Zeichen." }, "email_has_been_taken" : { "en-US": "Email has been taken.", - "zh-CN": "邮箱已被占用。" + "zh-CN": "邮箱已被占用。", + "de-DE": "E-Mail Adresse wird bereits verwendet." }, "email_content_illegal" : { "en-US": "Email format is illegal.", - "zh-CN": "邮箱格式不合法。" + "zh-CN": "邮箱格式不合法。", + "de-DE": "Format der E-Mail Adresse ist ungültig." }, "email_does_not_exist" : { "en-US": "Email does not exist.", - "zh-CN": "邮箱不存在。" + "zh-CN": "邮箱不存在。", + "de-DE": "E-Mail Adresse existiert nicht." }, "realname_is_required" : { "en-US": "Full name is required.", - "zh-CN": "全名为必填项。" + "zh-CN": "全名为必填项。", + "de-DE": "Vollständiger Name erforderlich." }, "realname_is_too_long" : { "en-US": "Full name is too long. (maximum 20 characters)", - "zh-CN": "全名长度超出限制。(最长为20个字符)" + "zh-CN": "全名长度超出限制。(最长为20个字符)", + "de-DE": "Vollständiger Name zu lang. (maximal 20 Zeichen)" }, "realname_contains_illegal_chars" : { "en-US": "Full name contains illegal character(s).", - "zh-CN": "全名包含不合法的字符。" + "zh-CN": "全名包含不合法的字符。", + "de-DE": "Vollständiger Name enthält ungültige Zeichen." }, "password_is_required" : { "en-US": "Password is required.", - "zh-CN": "密码为必填项。" + "zh-CN": "密码为必填项。", + "de-DE": "Passwort erforderlich." }, "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个数字。" + "zh-CN": "密码无效。至少输入 7个字符且包含 1个小写字母,1个大写字母和 1个数字。", + "de-DE": "Passwort ungültig. Mindestens sieben Zeichen bestehend aus einem Kleinbuchstaben, einem Großbuchstaben und einer Zahl" }, "password_is_too_long" : { "en-US": "Password is too long. (maximum 20 characters)", - "zh-CN": "密码长度超出限制。(最长为20个字符)" + "zh-CN": "密码长度超出限制。(最长为20个字符)", + "de-DE": "Passwort zu lang. (maximal 20 Zeichen)" }, "password_does_not_match" : { "en-US": "Passwords do not match.", - "zh-CN": "两次密码输入不一致。" + "zh-CN": "两次密码输入不一致。", + "de-DE": "Passwörter stimmen nicht überein." }, "comment_is_too_long" : { "en-US": "Comment is too long. (maximum 20 characters)", - "zh-CN": "备注长度超出限制。(最长为20个字符)" + "zh-CN": "备注长度超出限制。(最长为20个字符)", + "de-DE": "Kommentar zu lang. (maximal 20 Zeichen)" }, "comment_contains_illegal_chars" : { "en-US": "Comment contains illegal character(s).", - "zh-CN": "备注包含不合法的字符。" + "zh-CN": "备注包含不合法的字符。", + "de-DE": "Kommentar enthält ungültige Zeichen." }, "project_name_is_required" : { "en-US": "Project name is required.", - "zh-CN": "项目名称为必填项。" + "zh-CN": "项目名称为必填项。", + "de-DE": "Projektname erforderlich." }, "project_name_is_too_short" : { "en-US": "Project name is too short. (minimum 4 characters)", - "zh-CN": "项目名称至少要求 4个字符。" + "zh-CN": "项目名称至少要求 4个字符。", + "de-DE": "Projektname zu kurz. (mindestens 4 Zeichen)" }, "project_name_is_too_long" : { "en-US": "Project name is too long. (maximum 30 characters)", - "zh-CN": "项目名称长度超出限制。(最长为30个字符)" + "zh-CN": "项目名称长度超出限制。(最长为30个字符)", + "de-DE": "Projektname zu lang. (maximal 30 Zeichen)" }, "project_name_contains_illegal_chars" : { "en-US": "Project name contains illegal character(s).", - "zh-CN": "项目名称包含不合法的字符。" + "zh-CN": "项目名称包含不合法的字符。", + "de-DE": "Projektname enthält ungültige Zeichen." }, "project_exists" : { "en-US": "Project exists.", - "zh-CN": "项目已存在。" + "zh-CN": "项目已存在。", + "de-DE": "Projekt existiert bereits." }, "delete_user" : { "en-US": "Delete User", - "zh-CN": "删除用户" + "zh-CN": "删除用户", + "de-DE": "Benutzer löschen" }, "are_you_sure_to_delete_user" : { "en-US": "Are you sure to delete ", - "zh-CN": "确认要删除用户 " + "zh-CN": "确认要删除用户 ", + "de-DE": "Sind Sie sich sicher, dass Sie folgenden Benutzer löschen möchten: " }, "input_your_username_and_password" : { "en-US": "Please input your username and password.", - "zh-CN": "请输入用户名和密码。" + "zh-CN": "请输入用户名和密码。", + "de-DE": "Bitte geben Sie ihr Benutzername und Passwort ein." }, "check_your_username_or_password" : { "en-US": "Please check your username or password.", - "zh-CN": "请输入正确的用户名或密码。" + "zh-CN": "请输入正确的用户名或密码。", + "de-DE": "Bitte überprüfen Sie ihren Benutzernamen und Passwort." }, "title_login_failed" : { "en-US": "Login Failed", - "zh-CN": "登录失败" + "zh-CN": "登录失败", + "de-DE": "Anmeldung fehlgeschlagen" }, "title_change_password" : { "en-US": "Change Password", - "zh-CN": "修改密码" + "zh-CN": "修改密码", + "de-DE": "Passwort ändern" }, "change_password_successfully" : { "en-US": "Password changed successfully.", - "zh-CN": "密码已修改。" + "zh-CN": "密码已修改。", + "de-DE": "Passwort erfolgreich geändert." }, "title_forgot_password" : { - "en-US": "Forgot Password", - "zh-CN": "忘记密码" + "en-US": "Forgot Password", + "zh-CN": "忘记密码", + "de-DE": "Passwort vergessen" }, "email_has_been_sent" : { "en-US": "Email for resetting password has been sent.", - "zh-CN": "重置密码邮件已发送。" + "zh-CN": "重置密码邮件已发送。", + "de-DE": "Eine E-Mail mit einem Wiederherstellungslink wurde an Sie gesendet." }, "send_email_failed" : { "en-US": "Failed to send Email for resetting password.", - "zh-CN": "重置密码邮件发送失败。" + "zh-CN": "重置密码邮件发送失败。", + "de-DE": "Fehler beim Senden der Wiederherstellungs-E-Mail." }, "please_login_first" : { "en-US": "Please login first.", - "zh-CN": "请先登录。" + "zh-CN": "请先登录。", + "de-DE": "Bitte melden Sie sich zuerst an." }, "old_password_is_not_correct" : { "en-US": "Old password is not correct.", - "zh-CN": "原密码输入不正确。" + "zh-CN": "原密码输入不正确。", + "de-DE": "Altes Passwort ist nicht korrekt." }, "please_input_new_password" : { "en-US": "Please input new password.", - "zh-CN": "请输入新密码。" + "zh-CN": "请输入新密码。", + "de-DE": "Bitte geben Sie ihr neues Passwort ein." }, "invalid_reset_url": { "en-US": "Invalid URL for resetting password.", - "zh-CN": "无效密码重置链接。" + "zh-CN": "无效密码重置链接。", + "de-DE": "Ungültige URL zum Passwort wiederherstellen." }, "reset_password_successfully" : { "en-US": "Reset password successfully.", - "zh-CN": "密码重置成功。" + "zh-CN": "密码重置成功。", + "de-DE": "Passwort erfolgreich wiederhergestellt." }, "internal_error": { "en-US": "Internal error.", - "zh-CN": "内部错误,请联系系统管理员。" + "zh-CN": "内部错误,请联系系统管理员。", + "de-DE": "Interner Fehler." }, "title_reset_password" : { "en-US": "Reset Password", - "zh-CN": "重置密码" + "zh-CN": "重置密码", + "de-DE": "Passwort zurücksetzen" }, "title_sign_up" : { "en-US": "Sign Up", - "zh-CN": "注册" + "zh-CN": "注册", + "de-DE": "Registrieren" }, "title_add_user": { - "en-US": "Add User", - "zh-CN": "新增用户" + "en-US": "Add User", + "zh-CN": "新增用户", + "de-DE": "Benutzer hinzufügen" }, "registered_successfully": { "en-US": "Signed up successfully.", - "zh-CN": "注册成功。" + "zh-CN": "注册成功。", + "de-DE": "Erfolgreich registriert." }, "registered_failed" : { "en-US": "Failed to sign up.", - "zh-CN": "注册失败。" + "zh-CN": "注册失败。", + "de-DE": "Registrierung fehlgeschlagen." }, "added_user_successfully": { - "en-US": "Added user successfully.", - "zh-CN": "新增用户成功。" + "en-US": "Added user successfully.", + "zh-CN": "新增用户成功。", + "de-DE": "Benutzer erfolgreich erstellt." }, "added_user_failed": { - "en-US": "Added user failed.", - "zh-CN": "新增用户失败。" + "en-US": "Adding user failed.", + "zh-CN": "新增用户失败。", + "de-DE": "Benutzer erstellen fehlgeschlagen." }, - "projects" : { + "projects": { "en-US": "Projects", - "zh-CN": "项目" + "zh-CN": "项目", + "de-DE": "Projekte" }, "repositories" : { "en-US": "Repositories", - "zh-CN": "镜像仓库" + "zh-CN": "镜像仓库", + "de-DE": "Repositories" }, - "no_repo_exists" :{ - "en-US": "No repositories found, please use 'docker push' to upload images.", - "zh-CN": "未发现镜像,请用‘docker push’命令上传镜像。" + "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." }, "tag" : { - "en-US": "Tag", - "zh-CN": "标签" + "en-US": "Tag", + "zh-CN": "标签", + "de-DE": "Tag" }, "pull_command": { "en-US": "Pull Command", - "zh-CN": "Pull 命令" + "zh-CN": "Pull 命令", + "de-DE": "Pull Befehl" }, "image_details" : { "en-US": "Image Details", - "zh-CN": "镜像详细信息" + "zh-CN": "镜像详细信息", + "de-DE": "Image Details" }, "add_members" : { "en-US": "Add Member", - "zh-CN": "添加成员" + "zh-CN": "添加成员", + "de-DE": "Mitglied hinzufügen" }, "edit_members" : { - "en-US": "Edit Member", - "zh-CN": "编辑成员" + "en-US": "Edit Members", + "zh-CN": "编辑成员", + "de-DE": "Mitglieder bearbeiten" }, "add_member_failed" : { "en-US": "Adding Member Failed", - "zh-CN": "添加成员失败" + "zh-CN": "添加成员失败", + "de-DE": "Mitglied hinzufügen fehlgeschlagen" }, "please_input_username" : { "en-US": "Please input a username.", - "zh-CN": "请输入用户名。" + "zh-CN": "请输入用户名。", + "de-DE": "Bitte geben Sie einen Benutzernamen ein." }, "please_assign_a_role_to_user" : { "en-US": "Please assign a role to the user.", - "zh-CN": "请为用户分配角色。" + "zh-CN": "请为用户分配角色。", + "de-DE": "Bitte weisen Sie dem Benutzer eine Rolle zu." }, "user_id_exists" : { "en-US": "User is already a member.", - "zh-CN": "用户已经是成员。" + "zh-CN": "用户已经是成员。", + "de-DE": "Benutzer ist bereits Mitglied." }, "user_id_does_not_exist" : { "en-US": "User does not exist.", - "zh-CN": "不存在此用户。" + "zh-CN": "不存在此用户。", + "de-DE": "Benutzer existiert nicht." }, "insufficient_privileges" : { "en-US": "Insufficient privileges.", - "zh-CN": "权限不足。" + "zh-CN": "权限不足。", + "de-DE": "Unzureichende Berechtigungen." }, "operation_failed" : { "en-US": "Operation Failed", - "zh-CN": "操作失败" + "zh-CN": "操作失败", + "de-DE": "Befehl fehlgeschlagen" }, "button_on" : { - "en-US": "On", - "zh-CN": "打开" + "en-US": "On", + "zh-CN": "打开", + "de-DE": "An" }, "button_off" : { - "en-US": "Off", - "zh-CN": "关闭" + "en-US": "Off", + "zh-CN": "关闭", + "de-DE": "Aus" } -}; \ No newline at end of file +}; diff --git a/static/i18n/locale_zh-CN.ini b/static/i18n/locale_zh-CN.ini index 90ea4fc04..9ddc12724 100644 --- a/static/i18n/locale_zh-CN.ini +++ b/static/i18n/locale_zh-CN.ini @@ -73,6 +73,7 @@ reset_email_subject = 重置您的密码 language = 中文 language_en-US = English language_zh-CN = 中文 +language_de-DE = Deutsch copyright = 版权所有 all_rights_reserved = 保留所有权利。 index_desc = Harbor是可靠的企业级Registry服务器。企业用户可使用Harbor搭建私有容器Registry服务,提高生产效率和安全度,既可应用于生产环境,也可以在开发环境中使用。 @@ -82,4 +83,4 @@ index_desc_2 = 2. 效率: 搭建组织内部的私有容器Registry服务,可 index_desc_3 = 3. 访问控制: 提供基于角色的访问控制,可集成企业目前拥有的用户管理系统(如:AD/LDAP)。 index_desc_4 = 4. 审计: 所有访问Registry服务的操作均被记录,便于日后审计。 index_desc_5 = 5. 管理界面: 具有友好易用图形管理界面。 -index_title = 企业级 Registry 服务 \ No newline at end of file +index_title = 企业级 Registry 服务 diff --git a/static/resources/js/common.js b/static/resources/js/common.js index 850d1b9ab..3b63c7f0f 100644 --- a/static/resources/js/common.js +++ b/static/resources/js/common.js @@ -68,7 +68,8 @@ AjaxUtil.prototype.exec = function(){ var SUPPORT_LANGUAGES = { "en-US": "English", - "zh-CN": "Chinese" + "zh-CN": "Chinese", + "de-DE": "German" }; var DEFAULT_LANGUAGE = "en-US"; @@ -157,4 +158,4 @@ jQuery(function(){ } $(self).modal('show'); } -}); \ No newline at end of file +}); diff --git a/views/segment/header-content.tpl b/views/segment/header-content.tpl index 6c88e0d25..464cd09aa 100644 --- a/views/segment/header-content.tpl +++ b/views/segment/header-content.tpl @@ -36,6 +36,7 @@ @@ -80,4 +81,4 @@ {{ end }} - \ No newline at end of file + From 87b213c3ae85fbf63f61a7fba25f47edc4b471d4 Mon Sep 17 00:00:00 2001 From: hmwenchen Date: Tue, 26 Apr 2016 20:06:21 +0800 Subject: [PATCH 46/52] Use registry 2.4 toget tag info from events --- models/notification.go | 1 + models/repo.go | 13 ------ service/notification.go | 81 ++------------------------------------ utils/registry/registry.go | 3 ++ 4 files changed, 7 insertions(+), 91 deletions(-) diff --git a/models/notification.go b/models/notification.go index 0f608e2c6..3f30ae7e4 100644 --- a/models/notification.go +++ b/models/notification.go @@ -40,6 +40,7 @@ type Target struct { Digest string Repository string URL string `json:"Url"` + Tag string } // Actor holds information about actor. diff --git a/models/repo.go b/models/repo.go index 4ace8d1b6..f224c902e 100644 --- a/models/repo.go +++ b/models/repo.go @@ -60,16 +60,3 @@ type histroyItem struct { type blobSumItem struct { BlobSum string `json:"blobSum"` } - -// ManifestDigest ... -type ManifestDigest struct { - MediaType string `json:"mediaType"` - SchemaVersion int `json:"schemaVersion"` - Layers []layerItem `json:"layers"` -} - -type layerItem struct { - MediaType string `json:"mediaType"` - Size int `json:"size"` - Digest string `json:"digest"` -} diff --git a/service/notification.go b/service/notification.go index f47ddd627..d307cb487 100644 --- a/service/notification.go +++ b/service/notification.go @@ -52,7 +52,7 @@ func (n *NotificationHandler) Post() { log.Errorf("error while decoding json: %v", err) return } - var username, action, repo, project, repoTag, tagURL, digest string + var username, action, repo, project, repoTag string var matched bool var client *http.Client for _, e := range notification.Events { @@ -65,82 +65,8 @@ func (n *NotificationHandler) Post() { username = e.Actor.Name action = e.Action repo = e.Target.Repository - tagURL = e.Target.URL - digest = e.Target.Digest - - client = registry.NewClientUsernameAuthHandlerEmbeded(username) - log.Debug("initializing username auth handler: %s", username) - endpoint := os.Getenv("REGISTRY_URL") - r, err1 := registry.New(endpoint, client) - if err1 != nil { - log.Fatalf("error occurred while initializing auth handler for repository API: %v", err1) - - } - n.registry = r - - _, _, payload, err2 := n.registry.PullManifest(repo, digest, registry.ManifestVersion1) - - if err2 != nil { - log.Errorf("Failed to get manifests for repo, repo name: %s, tag: %s, error: %v", repo, tagURL, err2) - return - } - - maniDig := models.ManifestDigest{} - err = json.Unmarshal(payload, &maniDig) - if err != nil { - log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repo, tagURL, err) - return - } - - var digestLayers []string - var tagLayers []string - for _, diglayer := range maniDig.Layers { - digestLayers = append(digestLayers, diglayer.Digest) - } - - tags, err := n.registry.ListTag(repo) - if err != nil { - e, ok := errors.ParseError(err) - if ok { - log.Info(e) - } else { - log.Error(err) - } - return - } - - log.Infof("tags : %v ", tags) - - for _, tag := range tags { - _, _, payload, err := n.registry.PullManifest(repo, tag, registry.ManifestVersion1) - if err != nil { - e, ok := errors.ParseError(err) - if ok { - log.Info(e) - } else { - log.Error(err) - } - continue - } - taginfo := models.Manifest{} - err = json.Unmarshal(payload, &taginfo) - if err != nil { - log.Errorf("Failed to decode json from response for manifests, repo name: %s, tag: %s, error: %v", repo, tag, err) - continue - } - for _, fslayer := range taginfo.FsLayers { - tagLayers = append(tagLayers, fslayer.BlobSum) - } - - sort.Strings(digestLayers) - sort.Strings(tagLayers) - eq := compStringArray(digestLayers, tagLayers) - if eq { - repoTag = tag - break - } - - } + repoTag = e.Target.Tag + log.Debugf("repo tag is : %v ", repoTag) if strings.Contains(repo, "/") { project = repo[0:strings.LastIndex(repo, "/")] @@ -148,7 +74,6 @@ func (n *NotificationHandler) Post() { if username == "" { username = "anonymous" } - log.Debugf("repo tag is : %v ", repoTag) go dao.AccessLog(username, project, repo, repoTag, action) if action == "push" { go func() { diff --git a/utils/registry/registry.go b/utils/registry/registry.go index e390c4c0d..b4f41131b 100644 --- a/utils/registry/registry.go +++ b/utils/registry/registry.go @@ -25,6 +25,7 @@ import ( "github.com/docker/distribution/manifest" "github.com/docker/distribution/manifest/schema1" "github.com/docker/distribution/manifest/schema2" + "github.com/vmware/harbor/utils/log" "github.com/vmware/harbor/utils/registry/errors" ) @@ -197,6 +198,8 @@ func (r *Registry) PullManifest(name, reference string, version manifest.Version } // if the registry does not support schema 2, schema 1 manifest will be returned + log.Debugf("--- Pull request headers: %v ---", req.Header) + log.Debugf("--- Pull request Accept header: %v ---", http.CanonicalHeaderKey("Accept")) req.Header.Set(http.CanonicalHeaderKey("Accept"), version.MediaType) resp, err := r.client.Do(req) From 53bb0c1e6d7c24fddc1cf775a544dbb92eab171c Mon Sep 17 00:00:00 2001 From: hmwenchen Date: Tue, 26 Apr 2016 20:43:03 +0800 Subject: [PATCH 47/52] Remove unused packages --- service/notification.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/service/notification.go b/service/notification.go index d307cb487..ceda490d0 100644 --- a/service/notification.go +++ b/service/notification.go @@ -17,10 +17,7 @@ package service import ( "encoding/json" - "net/http" - "os" "regexp" - "sort" "strings" "github.com/vmware/harbor/dao" @@ -28,7 +25,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/errors" "github.com/astaxie/beego" ) @@ -54,7 +50,6 @@ func (n *NotificationHandler) Post() { } var username, action, repo, project, repoTag string var matched bool - var client *http.Client for _, e := range notification.Events { matched, err = regexp.MatchString(manifestPattern, e.Target.MediaType) if err != nil { From b4cc422a976bff0fc029517d332e41cda2709160 Mon Sep 17 00:00:00 2001 From: hmwenchen Date: Tue, 26 Apr 2016 21:00:29 +0800 Subject: [PATCH 48/52] Remove debug info --- service/notification.go | 20 -------------------- utils/registry/registry.go | 3 --- 2 files changed, 23 deletions(-) diff --git a/service/notification.go b/service/notification.go index ceda490d0..913d45b04 100644 --- a/service/notification.go +++ b/service/notification.go @@ -24,7 +24,6 @@ import ( "github.com/vmware/harbor/models" svc_utils "github.com/vmware/harbor/service/utils" "github.com/vmware/harbor/utils/log" - "github.com/vmware/harbor/utils/registry" "github.com/astaxie/beego" ) @@ -32,7 +31,6 @@ import ( // NotificationHandler handles request on /service/notifications/, which listens to registry's events. type NotificationHandler struct { beego.Controller - registry *registry.Registry } const manifestPattern = `^application/vnd.docker.distribution.manifest.v\d\+json` @@ -87,21 +85,3 @@ func (n *NotificationHandler) Post() { func (n *NotificationHandler) Render() error { return nil } - -func compStringArray(a, b []string) bool { - if a == nil && b == nil { - return true - } - if a == nil || b == nil { - return false - } - if len(a) != len(b) { - return false - } - for i, v := range a { - if v != b[i] { - return false - } - } - return true -} diff --git a/utils/registry/registry.go b/utils/registry/registry.go index b4f41131b..e390c4c0d 100644 --- a/utils/registry/registry.go +++ b/utils/registry/registry.go @@ -25,7 +25,6 @@ import ( "github.com/docker/distribution/manifest" "github.com/docker/distribution/manifest/schema1" "github.com/docker/distribution/manifest/schema2" - "github.com/vmware/harbor/utils/log" "github.com/vmware/harbor/utils/registry/errors" ) @@ -198,8 +197,6 @@ func (r *Registry) PullManifest(name, reference string, version manifest.Version } // if the registry does not support schema 2, schema 1 manifest will be returned - log.Debugf("--- Pull request headers: %v ---", req.Header) - log.Debugf("--- Pull request Accept header: %v ---", http.CanonicalHeaderKey("Accept")) req.Header.Set(http.CanonicalHeaderKey("Accept"), version.MediaType) resp, err := r.client.Do(req) From 2da25dce5ae217480e5834303c4f4f0e565047fc Mon Sep 17 00:00:00 2001 From: kunw Date: Tue, 26 Apr 2016 23:35:12 +0800 Subject: [PATCH 49/52] update for http/https schemes support --- docs/configure_swagger.md | 4 ++++ docs/prepare-swagger.sh | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/configure_swagger.md b/docs/configure_swagger.md index 5350975c2..80acee716 100644 --- a/docs/configure_swagger.md +++ b/docs/configure_swagger.md @@ -22,6 +22,10 @@ From time to time, you may need to mannually test Harbor REST API. You can deplo ```sh vi prepare-swagger.sh ``` +* Change the SCHEME to the protocol scheme of your Harbor server. +```sh + SCHEME= +``` * Change the SERVER_IP to the IP address of your Harbor server. ```sh SERVER_ID= diff --git a/docs/prepare-swagger.sh b/docs/prepare-swagger.sh index f0fe84bc2..dee9b2e9b 100755 --- a/docs/prepare-swagger.sh +++ b/docs/prepare-swagger.sh @@ -1,5 +1,6 @@ #!/bin/bash -SERVER_IP=10.117.170.65 +SCHEME=http +SERVER_IP=reg.mydomain.com set -e echo "Doing some clean up..." rm -f *.tar.gz @@ -8,9 +9,10 @@ wget https://github.com/swagger-api/swagger-ui/archive/v2.1.4.tar.gz -O swagger. echo "Untarring Swagger UI package to the static file path..." tar -C ../static/vendors -zxf swagger.tar.gz swagger-ui-2.1.4/dist echo "Executing some processes..." -sed -i 's/http:\/\/petstore\.swagger\.io\/v2\/swagger\.json/http:\/\/'$SERVER_IP'\/static\/resources\/yaml\/swagger\.yaml/g' \ +sed -i 's/http:\/\/petstore\.swagger\.io\/v2\/swagger\.json/'$SCHEME':\/\/'$SERVER_IP'\/static\/resources\/yaml\/swagger\.yaml/g' \ ../static/vendors/swagger-ui-2.1.4/dist/index.html mkdir -p ../static/resources/yaml cp swagger.yaml ../static/resources/yaml sed -i 's/host: localhost/host: '$SERVER_IP'/g' ../static/resources/yaml/swagger.yaml +sed -i 's/ \- http$/ \- '$SCHEME'/g' ../static/resources/yaml/swagger.yaml echo "Finish preparation for the Swagger UI." From ebc6eca0b4be019ff77334042e29c622575e4c2f Mon Sep 17 00:00:00 2001 From: Robin Naundorf Date: Wed, 27 Apr 2016 06:39:37 +0200 Subject: [PATCH 50/52] Updated README to include German Added German language to the Readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9f66f175a..06dbb8cf9 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Project Harbor is an enterprise-class registry server. It extends the open sourc * **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 and Chinese languages. More languages can be added. +* **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. ### Getting Started From db15c2abc69a56378956229320635ed3f9907474 Mon Sep 17 00:00:00 2001 From: Tan Jiang Date: Wed, 27 Apr 2016 13:38:59 +0800 Subject: [PATCH 51/52] add timeout for notification in registry --- Deploy/templates/registry/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Deploy/templates/registry/config.yml b/Deploy/templates/registry/config.yml index a1b19a8ed..999488a95 100644 --- a/Deploy/templates/registry/config.yml +++ b/Deploy/templates/registry/config.yml @@ -30,6 +30,6 @@ notifications: - name: harbor disabled: false url: http://ui/service/notifications - timeout: 500 + timeout: 500ms threshold: 5 - backoff: 1000 + backoff: 1s From 5a7857b05fa365212cb2d0a37fb0ca59a7e8fe7b Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Fri, 29 Apr 2016 18:19:09 +0800 Subject: [PATCH 52/52] set cgo as the default DNS resolver --- Deploy/docker-compose.yml | 2 ++ Deploy/templates/ui/env | 1 + 2 files changed, 3 insertions(+) diff --git a/Deploy/docker-compose.yml b/Deploy/docker-compose.yml index 2e9147ee1..2dc09b620 100644 --- a/Deploy/docker-compose.yml +++ b/Deploy/docker-compose.yml @@ -11,6 +11,8 @@ services: volumes: - /data/registry:/storage - ./config/registry/:/etc/registry/ + environment: + - GODEBUG=netdns=cgo ports: - 5001:5001 command: diff --git a/Deploy/templates/ui/env b/Deploy/templates/ui/env index 383e5f15a..fe91f5965 100644 --- a/Deploy/templates/ui/env +++ b/Deploy/templates/ui/env @@ -12,3 +12,4 @@ LDAP_URL=$ldap_url LDAP_BASE_DN=$ldap_basedn SELF_REGISTRATION=$self_registration LOG_LEVEL=debug +GODEBUG=netdns=cgo \ No newline at end of file
{{i18n .Lang "username"}}{{i18n .Lang "email"}}{{i18n .Lang "system_admin"}}{{i18n .Lang "username"}}{{i18n .Lang "email"}}{{i18n .Lang "system_admin"}}