diff --git a/pkg/apiserver/registries/registries.go b/pkg/apiserver/registries/registries.go index ef785013a..4a8ec0138 100644 --- a/pkg/apiserver/registries/registries.go +++ b/pkg/apiserver/registries/registries.go @@ -21,6 +21,7 @@ package registries import ( "github.com/emicklei/go-restful" "net/http" + "strings" "kubesphere.io/kubesphere/pkg/models/registries" "kubesphere.io/kubesphere/pkg/server/errors" @@ -68,6 +69,25 @@ func RegistryImageBlob(request *restful.Request, response *restful.Response) { return } + // default use ssl + checkSSl := func(serverAddress string) bool { + if strings.HasPrefix(serverAddress, "http://") { + return false + } else { + return true + } + } + + if strings.HasPrefix(imageName, "http") { + dockerurl, err := registries.ParseDockerURL(imageName) + if err != nil { + log.Errorf("%+v", err) + errors.ParseSvcErr(restful.NewError(http.StatusBadRequest, err.Error()), response) + return + } + imageName = dockerurl.StringWithoutScheme() + } + // parse image image, err := registries.ParseImage(imageName) if err != nil { @@ -76,8 +96,10 @@ func RegistryImageBlob(request *restful.Request, response *restful.Response) { return } + useSSL := checkSSl(entry.ServerAddress) + // Create the registry client. - r, err := registries.CreateRegistryClient(entry.Username, entry.Password, image.Domain) + r, err := registries.CreateRegistryClient(entry.Username, entry.Password, image.Domain, useSSL) if err != nil { log.Errorf("%+v", err) response.WriteAsJson(®istries.ImageDetails{Status: registries.StatusFailed, Message: err.Error()}) diff --git a/pkg/models/registries/image.go b/pkg/models/registries/image.go index 1d5f725be..fd32f35fe 100644 --- a/pkg/models/registries/image.go +++ b/pkg/models/registries/image.go @@ -2,9 +2,11 @@ package registries import ( "fmt" - "github.com/docker/distribution/reference" - digest "github.com/opencontainers/go-digest" + "github.com/opencontainers/go-digest" + log "k8s.io/klog" + "net/url" + "strings" ) // Image holds information about an image. @@ -30,9 +32,28 @@ func (i *Image) Reference() string { return i.Tag } +type DockerURL struct { + *url.URL +} + +func (u *DockerURL) StringWithoutScheme() string { + u.Scheme = "" + s := u.String() + return strings.Trim(s, "//") +} + +func ParseDockerURL(rawurl string) (*DockerURL, error) { + url, err := url.Parse(rawurl) + if err != nil { + log.Errorf("%+v", err) + return nil, err + } + return &DockerURL{URL: url}, nil +} + // ParseImage returns an Image struct with all the values filled in for a given image. // example : localhost:5000/nginx:latest, nginx:perl etc. -func ParseImage(image string) (Image, error) { +func ParseImage(image string) (i Image, err error) { // Parse the image name and tag. named, err := reference.ParseNormalizedNamed(image) if err != nil { @@ -41,7 +62,7 @@ func ParseImage(image string) (Image, error) { // Add the latest lag if they did not provide one. named = reference.TagNameOnly(named) - i := Image{ + i = Image{ named: named, Domain: reference.Domain(named), Path: reference.Path(named), diff --git a/pkg/models/registries/image_test.go b/pkg/models/registries/image_test.go new file mode 100644 index 000000000..f86b4f4d5 --- /dev/null +++ b/pkg/models/registries/image_test.go @@ -0,0 +1,84 @@ +package registries + +import ( + "testing" +) + +func TestParseImage(t *testing.T) { + type image struct { + ImageName string + ExDomain string + ExTag string + ExPath string + } + + testImages := []image{ + {ImageName: "dockerhub.qingcloud.com/kubesphere/test:v1", ExDomain: "dockerhub.qingcloud.com", ExTag: "v1", ExPath: "kubesphere/test"}, + {ImageName: "harbor.devops.kubesphere.local:30280/library/tomcat:latest", ExDomain: "harbor.devops.kubesphere.local:30280", ExTag: "latest", ExPath: "library/tomcat"}, + {ImageName: "zhuxiaoyang/nginx:v1", ExDomain: "docker.io", ExTag: "v1", ExPath: "zhuxiaoyang/nginx"}, + {ImageName: "nginx", ExDomain: "docker.io", ExTag: "latest", ExPath: "library/nginx"}, + {ImageName: "nginx:latest", ExDomain: "docker.io", ExTag: "latest", ExPath: "library/nginx"}, + {ImageName: "kubesphere/ks-account:v2.1.0", ExDomain: "docker.io", ExTag: "v2.1.0", ExPath: "kubesphere/ks-account"}, + } + + for _, image := range testImages { + res, err := ParseImage(image.ImageName) + if err != nil { + t.Fatalf("Get err %s", err) + } + + if res.Domain != image.ExDomain { + t.Fatalf("Doamin got %v, expected %v", res.Domain, image.ExDomain) + } + + if res.Tag != image.ExTag { + t.Fatalf("Tag got %v, expected %v", res.Tag, image.ExTag) + } + + if res.Path != image.ExPath { + t.Fatalf("Path got %v, expected %v", res.Path, image.ExPath) + } + } + + invalidImage := []image{ + {ImageName: "http://docker.io/nginx:latest"}, + {ImageName: "https://harbor.devops.kubesphere.local:30280/library/tomcat:latest"}, + {ImageName: "docker.io/nginx:latest:latest"}, + {ImageName: "nginx:8000:latest"}, + } + + for _, image := range invalidImage { + _, err := ParseImage(image.ImageName) + if err == nil { + t.Fatalf("Parse invalid image but without get any error") + } + } + +} + +func TestStringWithoutScheme(t *testing.T) { + type testRawurl struct { + Rawurl string + ExUrl string + } + testRawurls := []testRawurl{ + {"http://dockerhub.qingcloud.com/kubesphere/nginx:v1", "dockerhub.qingcloud.com/kubesphere/nginx:v1"}, + {"https://dockerhub.qingcloud.com/kubesphere/nginx:v1", "dockerhub.qingcloud.com/kubesphere/nginx:v1"}, + {"dockerhub.qingcloud.com/kubesphere/nginx:v1", "dockerhub.qingcloud.com/kubesphere/nginx:v1"}, + {"http://harbor.devops.kubesphere.local:30280/library/tomcat:latest", "harbor.devops.kubesphere.local:30280/library/tomcat:latest"}, + {"https://harbor.devops.kubesphere.local:30280/library/tomcat:latest", "harbor.devops.kubesphere.local:30280/library/tomcat:latest"}, + } + + for _, rawurl := range testRawurls { + dockerurl, err := ParseDockerURL(rawurl.Rawurl) + if err != nil { + t.Fatalf("Get err %s", err) + } + + imageName := dockerurl.StringWithoutScheme() + + if imageName != rawurl.ExUrl { + t.Fatalf("imagename got %v, expected %v", imageName, rawurl.ExUrl) + } + } +} diff --git a/pkg/models/registries/manifest_test.go b/pkg/models/registries/manifest_test.go index 7afad1cce..2b52939cf 100644 --- a/pkg/models/registries/manifest_test.go +++ b/pkg/models/registries/manifest_test.go @@ -7,7 +7,7 @@ import ( func TestDigestFromDockerHub(t *testing.T) { testImage := Image{Domain: "docker.io", Path: "library/alpine", Tag: "latest"} - r, err := CreateRegistryClient("", "", "docker.io") + r, err := CreateRegistryClient("", "", "docker.io", true) if err != nil { t.Fatalf("Could not get client: %s", err) } diff --git a/pkg/models/registries/registry_client.go b/pkg/models/registries/registry_client.go index 5db8fde65..6b6464ce9 100644 --- a/pkg/models/registries/registry_client.go +++ b/pkg/models/registries/registry_client.go @@ -64,7 +64,7 @@ type authService struct { Scope []string } -func CreateRegistryClient(username, password, domain string) (*Registry, error) { +func CreateRegistryClient(username, password, domain string, useSSL bool) (*Registry, error) { authDomain := domain auth, err := GetAuthConfig(username, password, authDomain) if err != nil { @@ -75,6 +75,7 @@ func CreateRegistryClient(username, password, domain string) (*Registry, error) // Create the registry client. return New(auth, RegistryOpt{ Domain: domain, + UseSSL: useSSL, }) } diff --git a/pkg/models/registries/registry_client_test.go b/pkg/models/registries/registry_client_test.go index ad7da03fa..d48647dec 100644 --- a/pkg/models/registries/registry_client_test.go +++ b/pkg/models/registries/registry_client_test.go @@ -4,6 +4,8 @@ import ( "testing" ) +const DockerHub = "docker.io" + func TestCreateRegistryClient(t *testing.T) { type imageInfo struct { Username string @@ -11,17 +13,19 @@ func TestCreateRegistryClient(t *testing.T) { Domain string ExDomain string ExUrl string + UseSSL bool } testImages := []imageInfo{ - {Domain: "kubesphere.io", ExDomain: "kubesphere.io", ExUrl: "http://kubesphere.io"}, - {Domain: "127.0.0.1:5000", ExDomain: "127.0.0.1:5000", ExUrl: "http://127.0.0.1:5000"}, - {Username: "Username", Password: "Password", Domain: "docker.io", ExDomain: "registry-1.docker.io", ExUrl: "https://registry-1.docker.io"}, - {Domain: "harbor.devops.kubesphere.local:30280", ExDomain: "harbor.devops.kubesphere.local:30280", ExUrl: "http://harbor.devops.kubesphere.local:30280"}, + {Domain: "kubesphere.io", ExDomain: "kubesphere.io", ExUrl: "https://kubesphere.io", UseSSL: true}, + {Domain: "127.0.0.1:5000", ExDomain: "127.0.0.1:5000", ExUrl: "http://127.0.0.1:5000", UseSSL: false}, + {Username: "Username", Password: "Password", Domain: DockerHub, ExDomain: "registry-1.docker.io", ExUrl: "https://registry-1.docker.io", UseSSL: true}, + {Domain: "harbor.devops.kubesphere.local:30280", ExDomain: "harbor.devops.kubesphere.local:30280", ExUrl: "http://harbor.devops.kubesphere.local:30280", UseSSL: false}, + {Domain: "dockerhub.qingcloud.com/zxytest/s2i-jj:jj", ExDomain: "dockerhub.qingcloud.com", ExUrl: "https://dockerhub.qingcloud.com/zxytest/s2i-jj:jj", UseSSL: true}, } for _, testImage := range testImages { - reg, err := CreateRegistryClient(testImage.Username, testImage.Password, testImage.Domain) + reg, err := CreateRegistryClient(testImage.Username, testImage.Password, testImage.Domain, testImage.UseSSL) if err != nil { t.Fatalf("Get err %s", err) } @@ -36,8 +40,8 @@ func TestCreateRegistryClient(t *testing.T) { } - testImage := Image{Domain: "docker.io", Path: "library/alpine", Tag: "latest"} - r, err := CreateRegistryClient("", "", "docker.io") + testImage := Image{Domain: DockerHub, Path: "library/alpine", Tag: "latest"} + r, err := CreateRegistryClient("", "", DockerHub, true) if err != nil { t.Fatalf("Could not get client: %s", err) } diff --git a/pkg/models/registries/token_test.go b/pkg/models/registries/token_test.go index ea231472e..68ea0cd34 100644 --- a/pkg/models/registries/token_test.go +++ b/pkg/models/registries/token_test.go @@ -32,7 +32,7 @@ func (asm authServiceMock) equalTo(v *authService) bool { func TestToken(t *testing.T) { testImage := Image{Domain: "docker.io", Path: "library/alpine", Tag: "latest"} - r, err := CreateRegistryClient("", "", "docker.io") + r, err := CreateRegistryClient("", "", "docker.io", true) if err != nil { t.Fatalf("Could not get registry client: %s", err) }