From 8ee342117624a9eb68279f63ff960c6cb5eebc7c Mon Sep 17 00:00:00 2001 From: Wenkai Yin Date: Tue, 7 Apr 2020 23:36:38 +0800 Subject: [PATCH] Fix replication failure in kubernetes with hairpin mode disabled Fixes #11480 Fixes #11461 Fix replication failure in kubernetes with hairpin mode disabled Signed-off-by: Wenkai Yin --- .../adapter/harbor/base/adapter.go | 12 ++++-- .../adapter/harbor/base/chart_registry.go | 12 +++--- src/replication/adapter/harbor/base/client.go | 37 ++++++++++++++----- src/replication/adapter/harbor/v1/client.go | 6 +-- src/replication/adapter/harbor/v2/client.go | 6 +-- 5 files changed, 48 insertions(+), 25 deletions(-) diff --git a/src/replication/adapter/harbor/base/adapter.go b/src/replication/adapter/harbor/base/adapter.go index 81ba23f29..b1804b7ee 100644 --- a/src/replication/adapter/harbor/base/adapter.go +++ b/src/replication/adapter/harbor/base/adapter.go @@ -17,6 +17,7 @@ package base import ( "errors" "net/http" + "os" "strconv" "strings" @@ -32,7 +33,7 @@ import ( // New creates an instance of the base adapter func New(registry *model.Registry) (*Adapter, error) { - if isLocalHarbor(registry) { + if isLocalHarbor(registry.URL) { authorizer := common_http_auth.NewSecretAuthorizer(registry.Credential.AccessSecret) httpClient := common_http.NewClient(&http.Client{ Transport: common_http.GetHTTPTransport(common_http.SecureTransport), @@ -266,6 +267,11 @@ type Project struct { Metadata map[string]interface{} `json:"metadata"` } -func isLocalHarbor(registry *model.Registry) bool { - return registry.Type == model.RegistryTypeHarbor && registry.Name == "Local" +func isLocalHarbor(url string) bool { + return url == os.Getenv("CORE_URL") +} + +// check whether the current process is running inside core +func isInCore() bool { + return len(os.Getenv("EXT_ENDPOINT")) > 0 } diff --git a/src/replication/adapter/harbor/base/chart_registry.go b/src/replication/adapter/harbor/base/chart_registry.go index 28ffdacd4..b262b73d6 100644 --- a/src/replication/adapter/harbor/base/chart_registry.go +++ b/src/replication/adapter/harbor/base/chart_registry.go @@ -54,7 +54,7 @@ func (a *Adapter) FetchCharts(filters []*model.Filter) ([]*model.Resource, error resources := []*model.Resource{} for _, project := range projects { - url := fmt.Sprintf("%s/api/chartrepo/%s/charts", a.url, project.Name) + url := fmt.Sprintf("%s/api/chartrepo/%s/charts", a.Client.GetURL(), project.Name) repositories := []*model.Repository{} if err := a.httpClient.Get(url, &repositories); err != nil { return nil, err @@ -72,7 +72,7 @@ func (a *Adapter) FetchCharts(filters []*model.Filter) ([]*model.Resource, error for _, repository := range repositories { name := strings.SplitN(repository.Name, "/", 2)[1] - url := fmt.Sprintf("%s/api/chartrepo/%s/charts/%s", a.url, project.Name, name) + url := fmt.Sprintf("%s/api/chartrepo/%s/charts/%s", a.Client.GetURL(), project.Name, name) versions := []*chartVersion{} if err := a.httpClient.Get(url, &versions); err != nil { return nil, err @@ -134,7 +134,7 @@ func (a *Adapter) getChartInfo(name, version string) (*chartVersionDetail, error if err != nil { return nil, err } - url := fmt.Sprintf("%s/api/chartrepo/%s/charts/%s/%s", a.url, project, name, version) + url := fmt.Sprintf("%s/api/chartrepo/%s/charts/%s/%s", a.Client.GetURL(), project, name, version) info := &chartVersionDetail{} if err = a.httpClient.Get(url, info); err != nil { return nil, err @@ -158,7 +158,7 @@ func (a *Adapter) DownloadChart(name, version string) (io.ReadCloser, error) { if err != nil { return nil, err } - url = fmt.Sprintf("%s/chartrepo/%s/%s", a.url, project, url) + url = fmt.Sprintf("%s/chartrepo/%s/%s", a.Client.GetURL(), project, url) } req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { @@ -196,7 +196,7 @@ func (a *Adapter) UploadChart(name, version string, chart io.Reader) error { } w.Close() - url := fmt.Sprintf("%s/api/chartrepo/%s/charts", a.url, project) + url := fmt.Sprintf("%s/api/chartrepo/%s/charts", a.Client.GetURL(), project) req, err := http.NewRequest(http.MethodPost, url, buf) if err != nil { @@ -228,7 +228,7 @@ func (a *Adapter) DeleteChart(name, version string) error { if err != nil { return err } - url := fmt.Sprintf("%s/api/chartrepo/%s/charts/%s/%s", a.url, project, name, version) + url := fmt.Sprintf("%s/api/chartrepo/%s/charts/%s/%s", a.Client.GetURL(), project, name, version) return a.httpClient.Delete(url) } diff --git a/src/replication/adapter/harbor/base/client.go b/src/replication/adapter/harbor/base/client.go index 4f740ed00..0f16871e8 100644 --- a/src/replication/adapter/harbor/base/client.go +++ b/src/replication/adapter/harbor/base/client.go @@ -48,7 +48,7 @@ func (c *Client) GetAPIVersion() (string, error) { version := &struct { Version string `json:"version"` }{} - err := c.C.Get(c.URL+"/api/version", version) + err := c.C.Get(c.GetURL()+"/api/version", version) if err == nil { return version.Version, nil } @@ -64,7 +64,7 @@ func (c *Client) ChartRegistryEnabled() (bool, error) { sys := &struct { ChartRegistryEnabled bool `json:"with_chartmuseum"` }{} - if err := c.C.Get(c.BaseURL()+"/systeminfo", sys); err != nil { + if err := c.C.Get(c.BasePath()+"/systeminfo", sys); err != nil { return false, err } return sys.ChartRegistryEnabled, nil @@ -75,7 +75,7 @@ func (c *Client) ListLabels() ([]string, error) { labels := []*struct { Name string `json:"name"` }{} - err := c.C.Get(c.BaseURL()+"/labels?scope=g", &labels) + err := c.C.Get(c.BasePath()+"/labels?scope=g", &labels) if err == nil { var lbs []string for _, label := range labels { @@ -99,13 +99,13 @@ func (c *Client) CreateProject(name string, metadata map[string]interface{}) err Name: name, Metadata: metadata, } - return c.C.Post(c.BaseURL()+"/projects", project) + return c.C.Post(c.BasePath()+"/projects", project) } // ListProjects lists projects func (c *Client) ListProjects(name string) ([]*Project, error) { projects := []*Project{} - url := fmt.Sprintf("%s/projects?name=%s", c.BaseURL(), name) + url := fmt.Sprintf("%s/projects?name=%s", c.BasePath(), name) if err := c.C.GetAndIteratePagination(url, &projects); err != nil { return nil, err } @@ -126,10 +126,27 @@ func (c *Client) GetProject(name string) (*Project, error) { return nil, nil } -// BaseURL returns the base URL of APIs -func (c *Client) BaseURL() string { - if len(c.APIVersion) == 0 { - return fmt.Sprintf("%s/api", c.URL) +// BasePath returns the API base path that contains version part +func (c *Client) BasePath() string { + path := fmt.Sprintf("%s/api", c.GetURL()) + if len(c.APIVersion) > 0 { + path = fmt.Sprintf("%s/%s", path, c.APIVersion) } - return fmt.Sprintf("%s/api/%s", c.URL, c.APIVersion) + return path +} + +// GetURL returns the URL of the registry that the client is for +func (c *Client) GetURL() string { + if !isLocalHarbor(c.URL) || !isInCore() { + return c.URL + } + // if the adapter is created for local Harbor and the process is running + // inside core, returns the "127.0.0.1" as URL to avoid the issue: + // https://github.com/goharbor/harbor-helm/issues/222 + // when harbor is deployed on Kubernetes with hairpin mode disabled + url := "http://127.0.0.1:8080" + if common_http.InternalTLSEnabled() { + url = "https://127.0.0.1:8443" + } + return url } diff --git a/src/replication/adapter/harbor/v1/client.go b/src/replication/adapter/harbor/v1/client.go index 763347967..72e78cc2e 100644 --- a/src/replication/adapter/harbor/v1/client.go +++ b/src/replication/adapter/harbor/v1/client.go @@ -28,7 +28,7 @@ type client struct { func (c *client) listRepositories(project *base.Project) ([]*model.Repository, error) { repositories := []*models.RepoRecord{} - url := fmt.Sprintf("%s/repositories?project_id=%d", c.BaseURL(), project.ID) + url := fmt.Sprintf("%s/repositories?project_id=%d", c.BasePath(), project.ID) if err := c.C.GetAndIteratePagination(url, &repositories); err != nil { return nil, err } @@ -43,7 +43,7 @@ func (c *client) listRepositories(project *base.Project) ([]*model.Repository, e } func (c *client) listArtifacts(repository string) ([]*model.Artifact, error) { - url := fmt.Sprintf("%s/repositories/%s/tags", c.BaseURL(), repository) + url := fmt.Sprintf("%s/repositories/%s/tags", c.BasePath(), repository) tags := []*struct { Name string `json:"name"` Labels []*struct { @@ -68,6 +68,6 @@ func (c *client) listArtifacts(repository string) ([]*model.Artifact, error) { } func (c *client) deleteManifest(repository, reference string) error { - url := fmt.Sprintf("%s/repositories/%s/tags/%s", c.BaseURL(), repository, reference) + url := fmt.Sprintf("%s/repositories/%s/tags/%s", c.BasePath(), repository, reference) return c.C.Delete(url) } diff --git a/src/replication/adapter/harbor/v2/client.go b/src/replication/adapter/harbor/v2/client.go index f9a585ca3..5affb3bff 100644 --- a/src/replication/adapter/harbor/v2/client.go +++ b/src/replication/adapter/harbor/v2/client.go @@ -31,7 +31,7 @@ type client struct { func (c *client) listRepositories(project *base.Project) ([]*model.Repository, error) { repositories := []*models.RepoRecord{} - url := fmt.Sprintf("%s/projects/%s/repositories", c.BaseURL(), project.Name) + url := fmt.Sprintf("%s/projects/%s/repositories", c.BasePath(), project.Name) if err := c.C.GetAndIteratePagination(url, &repositories); err != nil { return nil, err } @@ -49,7 +49,7 @@ func (c *client) listArtifacts(repository string) ([]*model.Artifact, error) { project, repository := utils.ParseRepository(repository) repository = url.PathEscape(url.PathEscape(repository)) url := fmt.Sprintf("%s/projects/%s/repositories/%s/artifacts?with_label=true", - c.BaseURL(), project, repository) + c.BasePath(), project, repository) artifacts := []*artifact.Artifact{} if err := c.C.GetAndIteratePagination(url, &artifacts); err != nil { return nil, err @@ -75,6 +75,6 @@ func (c *client) deleteTag(repository, tag string) error { project, repository := utils.ParseRepository(repository) repository = url.PathEscape(url.PathEscape(repository)) url := fmt.Sprintf("%s/projects/%s/repositories/%s/artifacts/%s/tags/%s", - c.BaseURL(), project, repository, tag, tag) + c.BasePath(), project, repository, tag, tag) return c.C.Delete(url) }