token request posted to token service directly

This commit is contained in:
Wenkai Yin 2016-06-23 12:14:26 +08:00
parent 61a888926e
commit 5fbe2c1a72
5 changed files with 49 additions and 63 deletions

View File

@ -16,14 +16,10 @@
package replication
import (
"crypto/tls"
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/vmware/harbor/models"
"github.com/vmware/harbor/utils/log"
"github.com/vmware/harbor/utils/registry"
"github.com/vmware/harbor/utils/registry/auth"
)
const (
@ -42,11 +38,20 @@ type Deleter struct {
insecure bool
dstClient *registry.Repository
logger *log.Logger
}
// NewDeleter returns a Deleter
func NewDeleter(repository string, tags []string, dstURL, dstUsr, dstPwd string, insecure bool, logger *log.Logger) *Deleter {
func NewDeleter(repository string, tags []string, dstURL, dstUsr, dstPwd string, insecure bool, logger *log.Logger) (*Deleter, error) {
dstCred := auth.NewBasicAuthCredential(dstUsr, dstPwd)
dstClient, err := newRepositoryClient(dstURL, insecure, dstCred,
repository, "repository", repository, "pull", "push", "*")
if err != nil {
return nil, err
}
deleter := &Deleter{
repository: repository,
tags: tags,
@ -54,11 +59,12 @@ func NewDeleter(repository string, tags []string, dstURL, dstUsr, dstPwd string,
dstUsr: dstUsr,
dstPwd: dstPwd,
insecure: insecure,
dstClient: dstClient,
logger: logger,
}
deleter.logger.Infof("initialization completed: repository: %s, tags: %v, destination URL: %s, destination user: %s",
deleter.repository, deleter.tags, deleter.dstURL, deleter.dstUsr)
return deleter
return deleter, nil
}
// Exit ...
@ -68,25 +74,22 @@ func (d *Deleter) Exit() error {
// Enter deletes repository or tags
func (d *Deleter) Enter() (string, error) {
url := strings.TrimRight(d.dstURL, "/") + "/api/repositories/"
// delete repository
if len(d.tags) == 0 {
u := url + "?repo_name=" + d.repository
if err := del(u, d.dstUsr, d.dstPwd, d.insecure); err != nil {
d.logger.Errorf("an error occurred while deleting repository %s on %s with user %s: %v", d.repository, d.dstURL, d.dstUsr, err)
tags, err := d.dstClient.ListTag()
if err != nil {
d.logger.Errorf("an error occurred while listing tags of repository %s on %s with user %s: %v", d.repository, d.dstURL, d.dstUsr, err)
return "", err
}
d.logger.Infof("repository %s on %s has been deleted", d.repository, d.dstURL)
return models.JobFinished, nil
d.tags = append(d.tags, tags...)
}
// delele tags
d.logger.Infof("tags %v will be deleted", d.tags)
for _, tag := range d.tags {
u := url + "?repo_name=" + d.repository + "&tag=" + tag
if err := del(u, d.dstUsr, d.dstPwd, d.insecure); err != nil {
if err := d.dstClient.DeleteTag(tag); err != nil {
d.logger.Errorf("an error occurred while deleting repository %s:%s on %s with user %s: %v", d.repository, tag, d.dstURL, d.dstUsr, err)
return "", err
}
@ -96,37 +99,3 @@ func (d *Deleter) Enter() (string, error) {
return models.JobFinished, nil
}
func del(url, username, password string, insecure bool) error {
req, err := http.NewRequest("DELETE", url, nil)
if err != nil {
return err
}
req.SetBasicAuth(username, password)
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: insecure,
},
},
}
resp, err := client.Do(req)
if err != nil {
return err
}
if resp.StatusCode == http.StatusOK {
return nil
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
return fmt.Errorf("%d %s", resp.StatusCode, string(b))
}

View File

@ -432,7 +432,7 @@ func newRepositoryClient(endpoint string, insecure bool, credential auth.Credent
}
uam := &userAgentModifier{
userAgent: "registry-client",
userAgent: "harbor-registry-client",
}
client, err := registry.NewRepositoryWithModifiers(repository, endpoint, insecure, store, uam)

View File

@ -260,12 +260,9 @@ func (sm *SM) Reset(jid int64) error {
}
func addImgTransferTransition(sm *SM) error {
// TODO read variable from config file
insecure := true
base, err := replication.InitBaseHandler(sm.Parms.Repository, sm.Parms.LocalRegURL, config.UISecret(),
sm.Parms.TargetURL, sm.Parms.TargetUsername, sm.Parms.TargetPassword,
insecure, sm.Parms.Tags, sm.Logger)
sm.Parms.Insecure, sm.Parms.Tags, sm.Logger)
if err != nil {
return err
}
@ -279,10 +276,11 @@ func addImgTransferTransition(sm *SM) error {
}
func addImgDeleteTransition(sm *SM) error {
// TODO read variable from config file
insecure := true
deleter := replication.NewDeleter(sm.Parms.Repository, sm.Parms.Tags, sm.Parms.TargetURL,
sm.Parms.TargetUsername, sm.Parms.TargetPassword, insecure, sm.Logger)
deleter, err := replication.NewDeleter(sm.Parms.Repository, sm.Parms.Tags, sm.Parms.TargetURL,
sm.Parms.TargetUsername, sm.Parms.TargetPassword, sm.Parms.Insecure, sm.Logger)
if err != nil {
return err
}
sm.AddTransition(models.JobRunning, replication.StateDelete, deleter)
sm.AddTransition(replication.StateDelete, models.JobFinished, &StatusUpdater{DummyHandler{JobID: sm.JobID}, models.JobFinished})

View File

@ -56,7 +56,7 @@ func (n *NotificationHandler) Post() {
matched = false
}
if matched && (strings.HasPrefix(e.Request.UserAgent, "docker") ||
strings.ToLower(strings.TrimSpace(e.Request.UserAgent)) == "registry-client") {
strings.ToLower(strings.TrimSpace(e.Request.UserAgent)) == "harbor-registry-client") {
username = e.Actor.Name
action = e.Action
repo = e.Target.Repository

View File

@ -22,6 +22,7 @@ import (
"io/ioutil"
"net/http"
"net/url"
"os"
"strings"
"sync"
"time"
@ -162,6 +163,8 @@ func NewStandardTokenAuthorizer(credential Credential, insecure bool, scopeType,
}
func (s *standardTokenAuthorizer) generateToken(realm, service string, scopes []string) (token string, expiresIn int, issuedAt *time.Time, err error) {
realm = tokenURL(realm)
u, err := url.Parse(realm)
if err != nil {
return
@ -223,6 +226,22 @@ func (s *standardTokenAuthorizer) generateToken(realm, service string, scopes []
return
}
// when the registry client is used inside Harbor, the token request
// can be posted to token service directly rather than going through nginx.
// this solution can resolve two problems:
// 1. performance issue
// 2. the realm field returned by registry is an IP which can not reachable
// inside Harbor
func tokenURL(realm string) string {
extEndpoint := os.Getenv("EXT_ENDPOINT")
tokenURL := os.Getenv("TOKEN_URL")
if len(extEndpoint) != 0 && len(tokenURL) != 0 &&
strings.Contains(realm, extEndpoint) {
realm = strings.TrimRight(tokenURL, "/") + "/service/token"
}
return realm
}
// Implements interface Handler
type usernameTokenAuthorizer struct {
tokenAuthorizer