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 <yinw@vmware.com>
This commit is contained in:
Wenkai Yin 2020-04-07 23:36:38 +08:00
parent bf6c4ff1f1
commit 8ee3421176
5 changed files with 48 additions and 25 deletions

View File

@ -17,6 +17,7 @@ package base
import ( import (
"errors" "errors"
"net/http" "net/http"
"os"
"strconv" "strconv"
"strings" "strings"
@ -32,7 +33,7 @@ import (
// New creates an instance of the base adapter // New creates an instance of the base adapter
func New(registry *model.Registry) (*Adapter, error) { func New(registry *model.Registry) (*Adapter, error) {
if isLocalHarbor(registry) { if isLocalHarbor(registry.URL) {
authorizer := common_http_auth.NewSecretAuthorizer(registry.Credential.AccessSecret) authorizer := common_http_auth.NewSecretAuthorizer(registry.Credential.AccessSecret)
httpClient := common_http.NewClient(&http.Client{ httpClient := common_http.NewClient(&http.Client{
Transport: common_http.GetHTTPTransport(common_http.SecureTransport), Transport: common_http.GetHTTPTransport(common_http.SecureTransport),
@ -266,6 +267,11 @@ type Project struct {
Metadata map[string]interface{} `json:"metadata"` Metadata map[string]interface{} `json:"metadata"`
} }
func isLocalHarbor(registry *model.Registry) bool { func isLocalHarbor(url string) bool {
return registry.Type == model.RegistryTypeHarbor && registry.Name == "Local" 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
} }

View File

@ -54,7 +54,7 @@ func (a *Adapter) FetchCharts(filters []*model.Filter) ([]*model.Resource, error
resources := []*model.Resource{} resources := []*model.Resource{}
for _, project := range projects { 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{} repositories := []*model.Repository{}
if err := a.httpClient.Get(url, &repositories); err != nil { if err := a.httpClient.Get(url, &repositories); err != nil {
return nil, err return nil, err
@ -72,7 +72,7 @@ func (a *Adapter) FetchCharts(filters []*model.Filter) ([]*model.Resource, error
for _, repository := range repositories { for _, repository := range repositories {
name := strings.SplitN(repository.Name, "/", 2)[1] 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{} versions := []*chartVersion{}
if err := a.httpClient.Get(url, &versions); err != nil { if err := a.httpClient.Get(url, &versions); err != nil {
return nil, err return nil, err
@ -134,7 +134,7 @@ func (a *Adapter) getChartInfo(name, version string) (*chartVersionDetail, error
if err != nil { if err != nil {
return nil, err 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{} info := &chartVersionDetail{}
if err = a.httpClient.Get(url, info); err != nil { if err = a.httpClient.Get(url, info); err != nil {
return nil, err return nil, err
@ -158,7 +158,7 @@ func (a *Adapter) DownloadChart(name, version string) (io.ReadCloser, error) {
if err != nil { if err != nil {
return nil, err 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) req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil { if err != nil {
@ -196,7 +196,7 @@ func (a *Adapter) UploadChart(name, version string, chart io.Reader) error {
} }
w.Close() 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) req, err := http.NewRequest(http.MethodPost, url, buf)
if err != nil { if err != nil {
@ -228,7 +228,7 @@ func (a *Adapter) DeleteChart(name, version string) error {
if err != nil { if err != nil {
return err 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) return a.httpClient.Delete(url)
} }

View File

@ -48,7 +48,7 @@ func (c *Client) GetAPIVersion() (string, error) {
version := &struct { version := &struct {
Version string `json:"version"` 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 { if err == nil {
return version.Version, nil return version.Version, nil
} }
@ -64,7 +64,7 @@ func (c *Client) ChartRegistryEnabled() (bool, error) {
sys := &struct { sys := &struct {
ChartRegistryEnabled bool `json:"with_chartmuseum"` 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 false, err
} }
return sys.ChartRegistryEnabled, nil return sys.ChartRegistryEnabled, nil
@ -75,7 +75,7 @@ func (c *Client) ListLabels() ([]string, error) {
labels := []*struct { labels := []*struct {
Name string `json:"name"` 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 { if err == nil {
var lbs []string var lbs []string
for _, label := range labels { for _, label := range labels {
@ -99,13 +99,13 @@ func (c *Client) CreateProject(name string, metadata map[string]interface{}) err
Name: name, Name: name,
Metadata: metadata, Metadata: metadata,
} }
return c.C.Post(c.BaseURL()+"/projects", project) return c.C.Post(c.BasePath()+"/projects", project)
} }
// ListProjects lists projects // ListProjects lists projects
func (c *Client) ListProjects(name string) ([]*Project, error) { func (c *Client) ListProjects(name string) ([]*Project, error) {
projects := []*Project{} 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 { if err := c.C.GetAndIteratePagination(url, &projects); err != nil {
return nil, err return nil, err
} }
@ -126,10 +126,27 @@ func (c *Client) GetProject(name string) (*Project, error) {
return nil, nil return nil, nil
} }
// BaseURL returns the base URL of APIs // BasePath returns the API base path that contains version part
func (c *Client) BaseURL() string { func (c *Client) BasePath() string {
if len(c.APIVersion) == 0 { path := fmt.Sprintf("%s/api", c.GetURL())
return fmt.Sprintf("%s/api", c.URL) 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
} }

View File

@ -28,7 +28,7 @@ type client struct {
func (c *client) listRepositories(project *base.Project) ([]*model.Repository, error) { func (c *client) listRepositories(project *base.Project) ([]*model.Repository, error) {
repositories := []*models.RepoRecord{} 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 { if err := c.C.GetAndIteratePagination(url, &repositories); err != nil {
return nil, err 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) { 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 { tags := []*struct {
Name string `json:"name"` Name string `json:"name"`
Labels []*struct { Labels []*struct {
@ -68,6 +68,6 @@ func (c *client) listArtifacts(repository string) ([]*model.Artifact, error) {
} }
func (c *client) deleteManifest(repository, reference string) 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) return c.C.Delete(url)
} }

View File

@ -31,7 +31,7 @@ type client struct {
func (c *client) listRepositories(project *base.Project) ([]*model.Repository, error) { func (c *client) listRepositories(project *base.Project) ([]*model.Repository, error) {
repositories := []*models.RepoRecord{} 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 { if err := c.C.GetAndIteratePagination(url, &repositories); err != nil {
return nil, err return nil, err
} }
@ -49,7 +49,7 @@ func (c *client) listArtifacts(repository string) ([]*model.Artifact, error) {
project, repository := utils.ParseRepository(repository) project, repository := utils.ParseRepository(repository)
repository = url.PathEscape(url.PathEscape(repository)) repository = url.PathEscape(url.PathEscape(repository))
url := fmt.Sprintf("%s/projects/%s/repositories/%s/artifacts?with_label=true", url := fmt.Sprintf("%s/projects/%s/repositories/%s/artifacts?with_label=true",
c.BaseURL(), project, repository) c.BasePath(), project, repository)
artifacts := []*artifact.Artifact{} artifacts := []*artifact.Artifact{}
if err := c.C.GetAndIteratePagination(url, &artifacts); err != nil { if err := c.C.GetAndIteratePagination(url, &artifacts); err != nil {
return nil, err return nil, err
@ -75,6 +75,6 @@ func (c *client) deleteTag(repository, tag string) error {
project, repository := utils.ParseRepository(repository) project, repository := utils.ParseRepository(repository)
repository = url.PathEscape(url.PathEscape(repository)) repository = url.PathEscape(url.PathEscape(repository))
url := fmt.Sprintf("%s/projects/%s/repositories/%s/artifacts/%s/tags/%s", 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) return c.C.Delete(url)
} }