2016-04-13 08:43:17 +02:00
|
|
|
/*
|
|
|
|
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package registry
|
|
|
|
|
|
|
|
import (
|
2016-06-21 10:39:03 +02:00
|
|
|
"crypto/tls"
|
2016-04-15 07:17:32 +02:00
|
|
|
"encoding/json"
|
2016-04-13 08:43:17 +02:00
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
2016-04-27 11:59:43 +02:00
|
|
|
"strings"
|
2016-09-29 10:17:18 +02:00
|
|
|
"time"
|
2016-04-13 08:43:17 +02:00
|
|
|
|
2016-06-27 08:37:26 +02:00
|
|
|
"github.com/vmware/harbor/utils"
|
2016-05-24 08:59:36 +02:00
|
|
|
registry_error "github.com/vmware/harbor/utils/registry/error"
|
2016-05-20 07:16:58 +02:00
|
|
|
)
|
|
|
|
|
2016-04-20 07:06:19 +02:00
|
|
|
// Registry holds information of a registry entity
|
2016-04-13 08:43:17 +02:00
|
|
|
type Registry struct {
|
|
|
|
Endpoint *url.URL
|
|
|
|
client *http.Client
|
|
|
|
}
|
|
|
|
|
2016-09-29 10:17:18 +02:00
|
|
|
var secureHTTPTransport, insecureHTTPTransport *http.Transport
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
secureHTTPTransport = &http.Transport{
|
|
|
|
TLSClientConfig: &tls.Config{
|
|
|
|
InsecureSkipVerify: false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
insecureHTTPTransport = &http.Transport{
|
|
|
|
TLSClientConfig: &tls.Config{
|
|
|
|
InsecureSkipVerify: true,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetHTTPTransport returns HttpTransport based on insecure configuration
|
|
|
|
func GetHTTPTransport(insecure bool) *http.Transport {
|
|
|
|
if insecure {
|
|
|
|
return insecureHTTPTransport
|
|
|
|
}
|
|
|
|
return secureHTTPTransport
|
|
|
|
}
|
|
|
|
|
2016-04-27 11:59:43 +02:00
|
|
|
// NewRegistry returns an instance of registry
|
|
|
|
func NewRegistry(endpoint string, client *http.Client) (*Registry, error) {
|
2016-06-21 10:39:03 +02:00
|
|
|
u, err := utils.ParseEndpoint(endpoint)
|
2016-04-13 08:43:17 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-04-27 11:59:43 +02:00
|
|
|
registry := &Registry{
|
2016-04-13 08:43:17 +02:00
|
|
|
Endpoint: u,
|
|
|
|
client: client,
|
2016-04-17 16:39:10 +02:00
|
|
|
}
|
|
|
|
|
2016-04-27 11:59:43 +02:00
|
|
|
return registry, nil
|
2016-04-15 07:17:32 +02:00
|
|
|
}
|
|
|
|
|
2016-06-21 10:39:03 +02:00
|
|
|
// NewRegistryWithModifiers returns an instance of Registry according to the modifiers
|
|
|
|
func NewRegistryWithModifiers(endpoint string, insecure bool, modifiers ...Modifier) (*Registry, error) {
|
2016-05-23 10:48:55 +02:00
|
|
|
|
2016-09-29 10:17:18 +02:00
|
|
|
transport := NewTransport(GetHTTPTransport(insecure), modifiers...)
|
2016-06-21 10:39:03 +02:00
|
|
|
|
2016-08-16 07:45:59 +02:00
|
|
|
return NewRegistry(endpoint, &http.Client{
|
|
|
|
Transport: transport,
|
2016-09-29 10:17:18 +02:00
|
|
|
Timeout: 30 * time.Second,
|
2016-08-16 07:45:59 +02:00
|
|
|
})
|
2016-05-23 10:48:55 +02:00
|
|
|
}
|
|
|
|
|
2016-04-27 11:59:43 +02:00
|
|
|
// Catalog ...
|
|
|
|
func (r *Registry) Catalog() ([]string, error) {
|
|
|
|
repos := []string{}
|
2016-06-23 19:37:37 +02:00
|
|
|
suffix := "/v2/_catalog?n=1000"
|
2016-06-23 18:21:14 +02:00
|
|
|
var url string
|
2016-04-21 08:55:15 +02:00
|
|
|
|
2016-06-23 18:21:14 +02:00
|
|
|
for len(suffix) > 0 {
|
|
|
|
url = r.Endpoint.String() + suffix
|
2016-04-21 08:55:15 +02:00
|
|
|
|
2016-06-23 18:21:14 +02:00
|
|
|
req, err := http.NewRequest("GET", url, nil)
|
|
|
|
if err != nil {
|
2016-04-27 11:59:43 +02:00
|
|
|
return repos, err
|
2016-04-21 08:55:15 +02:00
|
|
|
}
|
2016-06-23 18:21:14 +02:00
|
|
|
resp, err := r.client.Do(req)
|
|
|
|
if err != nil {
|
2016-06-24 08:59:20 +02:00
|
|
|
return nil, parseError(err)
|
2016-04-21 08:55:15 +02:00
|
|
|
}
|
2016-04-13 08:43:17 +02:00
|
|
|
|
2016-06-23 18:21:14 +02:00
|
|
|
defer resp.Body.Close()
|
|
|
|
b, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return repos, err
|
|
|
|
}
|
2016-04-13 08:43:17 +02:00
|
|
|
|
2016-06-23 18:21:14 +02:00
|
|
|
if resp.StatusCode == http.StatusOK {
|
|
|
|
catalogResp := struct {
|
|
|
|
Repositories []string `json:"repositories"`
|
|
|
|
}{}
|
|
|
|
|
|
|
|
if err := json.Unmarshal(b, &catalogResp); err != nil {
|
|
|
|
return repos, err
|
|
|
|
}
|
|
|
|
|
|
|
|
repos = append(repos, catalogResp.Repositories...)
|
|
|
|
//Link: </v2/_catalog?last=library%2Fhello-world-25&n=100>; rel="next"
|
|
|
|
link := resp.Header.Get("Link")
|
|
|
|
if strings.HasSuffix(link, `rel="next"`) && strings.Index(link, "<") >= 0 && strings.Index(link, ">") >= 0 {
|
|
|
|
suffix = link[strings.Index(link, "<")+1 : strings.Index(link, ">")]
|
|
|
|
} else {
|
|
|
|
suffix = ""
|
|
|
|
}
|
|
|
|
} else {
|
2016-06-24 08:59:20 +02:00
|
|
|
return repos, ®istry_error.Error{
|
2016-06-23 18:21:14 +02:00
|
|
|
StatusCode: resp.StatusCode,
|
2016-06-24 08:59:20 +02:00
|
|
|
Detail: string(b),
|
2016-06-23 18:21:14 +02:00
|
|
|
}
|
|
|
|
}
|
2016-04-15 07:17:32 +02:00
|
|
|
}
|
2016-06-23 18:21:14 +02:00
|
|
|
return repos, nil
|
2016-04-15 07:17:32 +02:00
|
|
|
}
|
|
|
|
|
2016-05-23 10:48:55 +02:00
|
|
|
// Ping ...
|
|
|
|
func (r *Registry) Ping() error {
|
|
|
|
req, err := http.NewRequest("GET", buildPingURL(r.Endpoint.String()), nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := r.client.Do(req)
|
|
|
|
if err != nil {
|
2016-06-01 09:09:10 +02:00
|
|
|
return parseError(err)
|
2016-05-23 10:48:55 +02:00
|
|
|
}
|
2016-07-14 11:50:25 +02:00
|
|
|
defer resp.Body.Close()
|
2016-05-23 10:48:55 +02:00
|
|
|
|
|
|
|
if resp.StatusCode == http.StatusOK {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2016-05-24 08:59:36 +02:00
|
|
|
return ®istry_error.Error{
|
2016-05-23 10:48:55 +02:00
|
|
|
StatusCode: resp.StatusCode,
|
2016-05-24 08:59:36 +02:00
|
|
|
Detail: string(b),
|
2016-05-23 10:48:55 +02:00
|
|
|
}
|
|
|
|
}
|