Commit e065ebcc authored by jackgr's avatar jackgr

Remove repo name

parent c14b92bd
...@@ -43,14 +43,11 @@ const ( ...@@ -43,14 +43,11 @@ const (
// In a GCS repository all charts appear at the top level. // In a GCS repository all charts appear at the top level.
GCSRepoFormat = FlatRepoFormat GCSRepoFormat = FlatRepoFormat
// GCSPublicRepoName is the name of the public GCS repository. // GCSPublicRepoBucket is the name of the public GCS repository bucket.
GCSPublicRepoName = "kubernetes-charts" GCSPublicRepoBucket = "kubernetes-charts"
// GCSPublicRepoURL is the URL for the public GCS repository. // GCSPublicRepoURL is the URL for the public GCS repository.
GCSPublicRepoURL = "gs://" + GCSPublicRepoName GCSPublicRepoURL = "gs://" + GCSPublicRepoBucket
// GCSPublicRepoBucket is the name of the public GCS repository bucket.
GCSPublicRepoBucket = GCSPublicRepoName
) )
// GCSRepo implements the IStorageRepo interface for Google Cloud Storage. // GCSRepo implements the IStorageRepo interface for Google Cloud Storage.
...@@ -63,12 +60,12 @@ type GCSRepo struct { ...@@ -63,12 +60,12 @@ type GCSRepo struct {
// NewPublicGCSRepo creates a new an IStorageRepo for the public GCS repository. // NewPublicGCSRepo creates a new an IStorageRepo for the public GCS repository.
func NewPublicGCSRepo(httpClient *http.Client) (IStorageRepo, error) { func NewPublicGCSRepo(httpClient *http.Client) (IStorageRepo, error) {
return NewGCSRepo(GCSPublicRepoName, GCSPublicRepoURL, "", nil) return NewGCSRepo(GCSPublicRepoURL, "", nil)
} }
// NewGCSRepo creates a new IStorageRepo for a given GCS repository. // NewGCSRepo creates a new IStorageRepo for a given GCS repository.
func NewGCSRepo(name, URL, credentialName string, httpClient *http.Client) (IStorageRepo, error) { func NewGCSRepo(URL, credentialName string, httpClient *http.Client) (IStorageRepo, error) {
r, err := newRepo(name, URL, credentialName, GCSRepoFormat, GCSRepoType) r, err := newRepo(URL, credentialName, GCSRepoFormat, GCSRepoType)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -120,7 +117,7 @@ func validateRepoType(repoType ERepoType) error { ...@@ -120,7 +117,7 @@ func validateRepoType(repoType ERepoType) error {
func (g *GCSRepo) ListCharts(regex *regexp.Regexp) ([]string, error) { func (g *GCSRepo) ListCharts(regex *regexp.Regexp) ([]string, error) {
charts := []string{} charts := []string{}
// List all objects in a bucket using pagination // ListRepos all objects in a bucket using pagination
pageToken := "" pageToken := ""
for { for {
call := g.service.Objects.List(g.bucket) call := g.service.Objects.List(g.bucket)
...@@ -135,7 +132,7 @@ func (g *GCSRepo) ListCharts(regex *regexp.Regexp) ([]string, error) { ...@@ -135,7 +132,7 @@ func (g *GCSRepo) ListCharts(regex *regexp.Regexp) ([]string, error) {
} }
for _, object := range res.Items { for _, object := range res.Items {
// Charts should be named bucket/chart-X.Y.Z.tgz, so tease apart the name // Charts should be named chart-X.Y.Z.tgz, so tease apart the name
m := ChartNameMatcher.FindStringSubmatch(object.Name) m := ChartNameMatcher.FindStringSubmatch(object.Name)
if len(m) != 3 { if len(m) != 3 {
continue continue
...@@ -156,7 +153,7 @@ func (g *GCSRepo) ListCharts(regex *regexp.Regexp) ([]string, error) { ...@@ -156,7 +153,7 @@ func (g *GCSRepo) ListCharts(regex *regexp.Regexp) ([]string, error) {
// GetChart retrieves, unpacks and returns a chart by name. // GetChart retrieves, unpacks and returns a chart by name.
func (g *GCSRepo) GetChart(name string) (*chart.Chart, error) { func (g *GCSRepo) GetChart(name string) (*chart.Chart, error) {
// Charts should be named bucket/chart-X.Y.Z.tgz, so check that the name matches // Charts should be named chart-X.Y.Z.tgz, so check that the name matches
if !ChartNameMatcher.MatchString(name) { if !ChartNameMatcher.MatchString(name) {
return nil, fmt.Errorf("name must be of the form <name>-<version>.tgz, was %s", name) return nil, fmt.Errorf("name must be of the form <name>-<version>.tgz, was %s", name)
} }
......
...@@ -37,7 +37,7 @@ var ( ...@@ -37,7 +37,7 @@ var (
func TestValidGSURL(t *testing.T) { func TestValidGSURL(t *testing.T) {
tr := getTestRepo(t) tr := getTestRepo(t)
err := validateRepo(tr, TestRepoName, TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType) err := validateRepo(tr, TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -51,7 +51,7 @@ func TestValidGSURL(t *testing.T) { ...@@ -51,7 +51,7 @@ func TestValidGSURL(t *testing.T) {
func TestInvalidGSURL(t *testing.T) { func TestInvalidGSURL(t *testing.T) {
var invalidGSURL = "https://valid.url/wrong/scheme" var invalidGSURL = "https://valid.url/wrong/scheme"
_, err := NewGCSRepo(TestRepoName, invalidGSURL, TestRepoCredentialName, nil) _, err := NewGCSRepo(invalidGSURL, TestRepoCredentialName, nil)
if err == nil { if err == nil {
t.Fatalf("expected error did not occur for invalid GS URL") t.Fatalf("expected error did not occur for invalid GS URL")
} }
...@@ -126,7 +126,7 @@ func TestGetChartWithInvalidName(t *testing.T) { ...@@ -126,7 +126,7 @@ func TestGetChartWithInvalidName(t *testing.T) {
} }
func getTestRepo(t *testing.T) IStorageRepo { func getTestRepo(t *testing.T) IStorageRepo {
tr, err := NewGCSRepo(TestRepoName, TestRepoURL, TestRepoCredentialName, nil) tr, err := NewGCSRepo(TestRepoURL, TestRepoCredentialName, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
......
...@@ -35,55 +35,55 @@ func NewInmemRepoService() IRepoService { ...@@ -35,55 +35,55 @@ func NewInmemRepoService() IRepoService {
r, err := NewPublicGCSRepo(nil) r, err := NewPublicGCSRepo(nil)
if err == nil { if err == nil {
rs.Create(r) rs.CreateRepo(r)
} }
return rs return rs
} }
// List returns the list of all known chart repositories // ListRepos returns the list of all known chart repositories
func (rs *inmemRepoService) List() ([]string, error) { func (rs *inmemRepoService) ListRepos() ([]string, error) {
rs.RLock() rs.RLock()
defer rs.RUnlock() defer rs.RUnlock()
ret := []string{} ret := []string{}
for _, r := range rs.repositories { for _, r := range rs.repositories {
ret = append(ret, r.GetName()) ret = append(ret, r.GetURL())
} }
return ret, nil return ret, nil
} }
// Create adds a known repository to the list // CreateRepo adds a known repository to the list
func (rs *inmemRepoService) Create(repository IRepo) error { func (rs *inmemRepoService) CreateRepo(repository IRepo) error {
rs.Lock() rs.Lock()
defer rs.Unlock() defer rs.Unlock()
name := repository.GetName() URL := repository.GetURL()
_, ok := rs.repositories[name] _, ok := rs.repositories[URL]
if ok { if ok {
return fmt.Errorf("Repository named %s already exists", name) return fmt.Errorf("Repository with URL %s already exists", URL)
} }
rs.repositories[name] = repository rs.repositories[URL] = repository
return nil return nil
} }
// Get returns the repository with the given name // GetRepoByURL returns the repository with the given URL
func (rs *inmemRepoService) Get(name string) (IRepo, error) { func (rs *inmemRepoService) GetRepoByURL(URL string) (IRepo, error) {
rs.RLock() rs.RLock()
defer rs.RUnlock() defer rs.RUnlock()
r, ok := rs.repositories[name] r, ok := rs.repositories[URL]
if !ok { if !ok {
return nil, fmt.Errorf("Failed to find repository named %s", name) return nil, fmt.Errorf("No repository with URL %s", URL)
} }
return r, nil return r, nil
} }
// GetByURL returns the repository that backs the given URL // GetRepoByChartURL returns the repository that backs the given chart URL
func (rs *inmemRepoService) GetByURL(URL string) (IRepo, error) { func (rs *inmemRepoService) GetRepoByChartURL(URL string) (IRepo, error) {
rs.RLock() rs.RLock()
defer rs.RUnlock() defer rs.RUnlock()
...@@ -98,22 +98,22 @@ func (rs *inmemRepoService) GetByURL(URL string) (IRepo, error) { ...@@ -98,22 +98,22 @@ func (rs *inmemRepoService) GetByURL(URL string) (IRepo, error) {
} }
if found == nil { if found == nil {
return nil, fmt.Errorf("Failed to find repository for url: %s", URL) return nil, fmt.Errorf("No repository for url %s", URL)
} }
return found, nil return found, nil
} }
// Delete removes a known repository from the list // DeleteRepo removes a known repository from the list
func (rs *inmemRepoService) Delete(name string) error { func (rs *inmemRepoService) DeleteRepo(URL string) error {
rs.Lock() rs.Lock()
defer rs.Unlock() defer rs.Unlock()
_, ok := rs.repositories[name] _, ok := rs.repositories[URL]
if !ok { if !ok {
return fmt.Errorf("Failed to find repository named %s", name) return fmt.Errorf("No repository with URL %s", URL)
} }
delete(rs.repositories, name) delete(rs.repositories, URL)
return nil return nil
} }
...@@ -23,7 +23,7 @@ import ( ...@@ -23,7 +23,7 @@ import (
func TestService(t *testing.T) { func TestService(t *testing.T) {
rs := NewInmemRepoService() rs := NewInmemRepoService()
repos, err := rs.List() repos, err := rs.ListRepos()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -32,16 +32,16 @@ func TestService(t *testing.T) { ...@@ -32,16 +32,16 @@ func TestService(t *testing.T) {
t.Fatalf("unexpected repo count; want: %d, have %d.", 1, len(repos)) t.Fatalf("unexpected repo count; want: %d, have %d.", 1, len(repos))
} }
tr, err := rs.Get(repos[0]) tr, err := rs.GetRepoByURL(repos[0])
if err != nil { if err != nil {
t.Fatalf("cannot get repo named %s: %s", repos[0], err) t.Fatal(err)
} }
if err := validateRepo(tr, GCSPublicRepoName, GCSPublicRepoURL, "", GCSRepoFormat, GCSRepoType); err != nil { if err := validateRepo(tr, GCSPublicRepoURL, "", GCSRepoFormat, GCSRepoType); err != nil {
t.Fatal(err) t.Fatal(err)
} }
r1, err := rs.Get(GCSPublicRepoName) r1, err := rs.GetRepoByURL(GCSPublicRepoURL)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -50,7 +50,8 @@ func TestService(t *testing.T) { ...@@ -50,7 +50,8 @@ func TestService(t *testing.T) {
t.Fatalf("invalid repo returned; want: %#v, have %#v.", tr, r1) t.Fatalf("invalid repo returned; want: %#v, have %#v.", tr, r1)
} }
r2, err := rs.GetByURL(GCSPublicRepoURL) URL := GCSPublicRepoURL + TestArchiveName
r2, err := rs.GetRepoByChartURL(URL)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -59,50 +60,50 @@ func TestService(t *testing.T) { ...@@ -59,50 +60,50 @@ func TestService(t *testing.T) {
t.Fatalf("invalid repo returned; want: %#v, have %#v.", tr, r2) t.Fatalf("invalid repo returned; want: %#v, have %#v.", tr, r2)
} }
if err := rs.Delete(GCSPublicRepoName); err != nil { if err := rs.DeleteRepo(GCSPublicRepoURL); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if _, err := rs.Get(GCSPublicRepoName); err == nil { if _, err := rs.GetRepoByURL(GCSPublicRepoURL); err == nil {
t.Fatalf("deleted repo named %s returned", GCSPublicRepoName) t.Fatalf("deleted repo with URL %s returned", GCSPublicRepoURL)
} }
} }
func TestCreateRepoWithDuplicateName(t *testing.T) { func TestCreateRepoWithDuplicateURL(t *testing.T) {
rs := NewInmemRepoService() rs := NewInmemRepoService()
r, err := newRepo(GCSPublicRepoName, GCSPublicRepoURL, "", GCSRepoFormat, GCSRepoType) r, err := newRepo(GCSPublicRepoURL, "", GCSRepoFormat, GCSRepoType)
if err != nil { if err != nil {
t.Fatalf("cannot create test repo: %s", err) t.Fatalf("cannot create test repo: %s", err)
} }
if err := rs.Create(r); err == nil { if err := rs.CreateRepo(r); err == nil {
t.Fatalf("created repo with duplicate name: %s", GCSPublicRepoName) t.Fatalf("created repo with duplicate URL: %s", GCSPublicRepoURL)
} }
} }
func TestGetRepoWithInvalidName(t *testing.T) { func TestGetRepoWithInvalidURL(t *testing.T) {
invalidName := "InvalidRepoName" invalidURL := "https://not.a.valid/url"
rs := NewInmemRepoService() rs := NewInmemRepoService()
_, err := rs.Get(invalidName) _, err := rs.GetRepoByURL(invalidURL)
if err == nil { if err == nil {
t.Fatalf("found repo with invalid name: %s", invalidName) t.Fatalf("found repo with invalid URL: %s", invalidURL)
} }
} }
func TestGetRepoWithInvalidURL(t *testing.T) { func TestGetRepoWithInvalidChartURL(t *testing.T) {
invalidURL := "https://not.a.valid/url" invalidURL := "https://not.a.valid/url"
rs := NewInmemRepoService() rs := NewInmemRepoService()
_, err := rs.GetByURL(invalidURL) _, err := rs.GetRepoByChartURL(invalidURL)
if err == nil { if err == nil {
t.Fatalf("found repo with invalid URL: %s", invalidURL) t.Fatalf("found repo with invalid chart URL: %s", invalidURL)
} }
} }
func TestDeleteRepoWithInvalidName(t *testing.T) { func TestDeleteRepoWithInvalidURL(t *testing.T) {
invalidName := "InvalidRepoName" invalidURL := "https://not.a.valid/url"
rs := NewInmemRepoService() rs := NewInmemRepoService()
err := rs.Delete(invalidName) err := rs.DeleteRepo(invalidURL)
if err == nil { if err == nil {
t.Fatalf("deleted repo with invalid name: %s", invalidName) t.Fatalf("deleted repo with invalid name: %s", invalidURL)
} }
} }
...@@ -22,15 +22,11 @@ import ( ...@@ -22,15 +22,11 @@ import (
) )
// NewRepo takes params and returns a IRepo // NewRepo takes params and returns a IRepo
func NewRepo(name, URL, credentialName, repoFormat, repoType string) (IRepo, error) { func NewRepo(URL, credentialName, repoFormat, repoType string) (IRepo, error) {
return newRepo(name, URL, credentialName, ERepoFormat(repoFormat), ERepoType(repoType)) return newRepo(URL, credentialName, ERepoFormat(repoFormat), ERepoType(repoType))
} }
func newRepo(name, URL, credentialName string, repoFormat ERepoFormat, repoType ERepoType) (*Repo, error) { func newRepo(URL, credentialName string, repoFormat ERepoFormat, repoType ERepoType) (*Repo, error) {
if name == "" {
return nil, fmt.Errorf("name must not be empty")
}
_, err := url.Parse(URL) _, err := url.Parse(URL)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid URL (%s): %s", URL, err) return nil, fmt.Errorf("invalid URL (%s): %s", URL, err)
...@@ -45,11 +41,10 @@ func newRepo(name, URL, credentialName string, repoFormat ERepoFormat, repoType ...@@ -45,11 +41,10 @@ func newRepo(name, URL, credentialName string, repoFormat ERepoFormat, repoType
} }
r := &Repo{ r := &Repo{
Name: name,
Type: repoType,
URL: URL, URL: URL,
Format: repoFormat,
CredentialName: credentialName, CredentialName: credentialName,
Type: repoType,
Format: repoFormat,
} }
return r, nil return r, nil
...@@ -65,11 +60,6 @@ func validateRepoFormat(repoFormat ERepoFormat) error { ...@@ -65,11 +60,6 @@ func validateRepoFormat(repoFormat ERepoFormat) error {
return fmt.Errorf("unknown repository format: %s", repoFormat) return fmt.Errorf("unknown repository format: %s", repoFormat)
} }
// GetName returns the friendly name of this repository.
func (r *Repo) GetName() string {
return r.Name
}
// GetType returns the technology implementing this repository. // GetType returns the technology implementing this repository.
func (r *Repo) GetType() ERepoType { func (r *Repo) GetType() ERepoType {
return r.Type return r.Type
...@@ -90,12 +80,7 @@ func (r *Repo) GetCredentialName() string { ...@@ -90,12 +80,7 @@ func (r *Repo) GetCredentialName() string {
return r.CredentialName return r.CredentialName
} }
func validateRepo(tr IRepo, wantName, wantURL, wantCredentialName string, wantFormat ERepoFormat, wantType ERepoType) error { func validateRepo(tr IRepo, wantURL, wantCredentialName string, wantFormat ERepoFormat, wantType ERepoType) error {
haveName := tr.GetName()
if haveName != wantName {
return fmt.Errorf("unexpected repository name; want: %s, have %s", wantName, haveName)
}
haveURL := tr.GetURL() haveURL := tr.GetURL()
if haveURL != wantURL { if haveURL != wantURL {
return fmt.Errorf("unexpected repository url; want: %s, have %s", wantURL, haveURL) return fmt.Errorf("unexpected repository url; want: %s, have %s", wantURL, haveURL)
......
...@@ -21,8 +21,7 @@ import ( ...@@ -21,8 +21,7 @@ import (
) )
var ( var (
TestRepoName = "kubernetes-charts-testing" TestRepoBucket = "kubernetes-charts-testing"
TestRepoBucket = TestRepoName
TestRepoURL = "gs://" + TestRepoBucket TestRepoURL = "gs://" + TestRepoBucket
TestRepoType = GCSRepoType TestRepoType = GCSRepoType
TestRepoFormat = GCSRepoFormat TestRepoFormat = GCSRepoFormat
...@@ -30,32 +29,25 @@ var ( ...@@ -30,32 +29,25 @@ var (
) )
func TestValidRepoURL(t *testing.T) { func TestValidRepoURL(t *testing.T) {
tr, err := NewRepo(TestRepoName, TestRepoURL, TestRepoCredentialName, string(TestRepoFormat), string(TestRepoType)) tr, err := NewRepo(TestRepoURL, TestRepoCredentialName, string(TestRepoFormat), string(TestRepoType))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := validateRepo(tr, TestRepoName, TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType); err != nil { if err := validateRepo(tr, TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestInvalidRepoName(t *testing.T) {
_, err := newRepo("", TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType)
if err == nil {
t.Fatalf("expected error did not occur for invalid name")
}
}
func TestInvalidRepoURL(t *testing.T) { func TestInvalidRepoURL(t *testing.T) {
_, err := newRepo(TestRepoName, "%:invalid&url:%", TestRepoCredentialName, TestRepoFormat, TestRepoType) _, err := newRepo("%:invalid&url:%", TestRepoCredentialName, TestRepoFormat, TestRepoType)
if err == nil { if err == nil {
t.Fatalf("expected error did not occur for invalid URL") t.Fatalf("expected error did not occur for invalid URL")
} }
} }
func TestDefaultCredentialName(t *testing.T) { func TestDefaultCredentialName(t *testing.T) {
tr, err := newRepo(TestRepoName, TestRepoURL, "", TestRepoFormat, TestRepoType) tr, err := newRepo(TestRepoURL, "", TestRepoFormat, TestRepoType)
if err != nil { if err != nil {
t.Fatalf("cannot create repo using default credential name") t.Fatalf("cannot create repo using default credential name")
} }
...@@ -68,7 +60,7 @@ func TestDefaultCredentialName(t *testing.T) { ...@@ -68,7 +60,7 @@ func TestDefaultCredentialName(t *testing.T) {
} }
func TestInvalidRepoFormat(t *testing.T) { func TestInvalidRepoFormat(t *testing.T) {
_, err := newRepo(TestRepoName, TestRepoURL, TestRepoCredentialName, "", TestRepoType) _, err := newRepo(TestRepoURL, TestRepoCredentialName, "", TestRepoType)
if err == nil { if err == nil {
t.Fatalf("expected error did not occur for invalid format") t.Fatalf("expected error did not occur for invalid format")
} }
......
...@@ -29,28 +29,21 @@ import ( ...@@ -29,28 +29,21 @@ import (
"sync" "sync"
) )
// IRepoProvider is a factory for IChartRepo instances.
type IRepoProvider interface {
GetRepoByURL(URL string) (IChartRepo, error)
GetRepoByName(repoName string) (IChartRepo, error)
GetChartByReference(reference string) (*chart.Chart, IChartRepo, error)
}
type repoProvider struct { type repoProvider struct {
sync.RWMutex sync.RWMutex
rs IRepoService rs IRepoService
cp ICredentialProvider cp ICredentialProvider
gcsrp GCSRepoProvider gcsrp IGCSRepoProvider
repos map[string]IChartRepo repos map[string]IChartRepo
} }
// NewRepoProvider creates a new repository provider. // NewRepoProvider creates a new repository provider.
func NewRepoProvider(rs IRepoService, gcsrp GCSRepoProvider, cp ICredentialProvider) IRepoProvider { func NewRepoProvider(rs IRepoService, gcsrp IGCSRepoProvider, cp ICredentialProvider) IRepoProvider {
return newRepoProvider(rs, gcsrp, cp) return newRepoProvider(rs, gcsrp, cp)
} }
// newRepoProvider creates a new repository provider. // newRepoProvider creates a new repository provider.
func newRepoProvider(rs IRepoService, gcsrp GCSRepoProvider, cp ICredentialProvider) *repoProvider { func newRepoProvider(rs IRepoService, gcsrp IGCSRepoProvider, cp ICredentialProvider) *repoProvider {
if rs == nil { if rs == nil {
rs = NewInmemRepoService() rs = NewInmemRepoService()
} }
...@@ -79,20 +72,20 @@ func (rp *repoProvider) GetCredentialProvider() ICredentialProvider { ...@@ -79,20 +72,20 @@ func (rp *repoProvider) GetCredentialProvider() ICredentialProvider {
} }
// GetGCSRepoProvider returns the GCS repository provider used by this repository provider. // GetGCSRepoProvider returns the GCS repository provider used by this repository provider.
func (rp *repoProvider) GetGCSRepoProvider() GCSRepoProvider { func (rp *repoProvider) GetGCSRepoProvider() IGCSRepoProvider {
return rp.gcsrp return rp.gcsrp
} }
// GetRepoByName returns the repository with the given name. // GetRepoByURL returns the repository with the given name.
func (rp *repoProvider) GetRepoByName(repoName string) (IChartRepo, error) { func (rp *repoProvider) GetRepoByURL(URL string) (IChartRepo, error) {
rp.Lock() rp.Lock()
defer rp.Unlock() defer rp.Unlock()
if r, ok := rp.repos[repoName]; ok { if r, ok := rp.repos[URL]; ok {
return r, nil return r, nil
} }
cr, err := rp.rs.Get(repoName) cr, err := rp.rs.GetRepoByURL(URL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -115,25 +108,25 @@ func (rp *repoProvider) createRepoByType(r IRepo) (IChartRepo, error) { ...@@ -115,25 +108,25 @@ func (rp *repoProvider) createRepoByType(r IRepo) (IChartRepo, error) {
} }
func (rp *repoProvider) createRepo(cr IChartRepo) (IChartRepo, error) { func (rp *repoProvider) createRepo(cr IChartRepo) (IChartRepo, error) {
name := cr.GetName() URL := cr.GetURL()
if _, ok := rp.repos[name]; ok { if _, ok := rp.repos[URL]; ok {
return nil, fmt.Errorf("respository named %s already exists", name) return nil, fmt.Errorf("respository with URL %s already exists", URL)
} }
rp.repos[name] = cr rp.repos[URL] = cr
return cr, nil return cr, nil
} }
// GetRepoByURL returns the repository whose URL is a prefix of the given URL. // GetRepoByChartURL returns the repository whose URL is a prefix of the given URL.
func (rp *repoProvider) GetRepoByURL(URL string) (IChartRepo, error) { func (rp *repoProvider) GetRepoByChartURL(URL string) (IChartRepo, error) {
rp.Lock() rp.Lock()
defer rp.Unlock() defer rp.Unlock()
if r := rp.findRepoByURL(URL); r != nil { if r := rp.findRepoByChartURL(URL); r != nil {
return r, nil return r, nil
} }
cr, err := rp.rs.GetByURL(URL) cr, err := rp.rs.GetRepoByChartURL(URL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -141,7 +134,7 @@ func (rp *repoProvider) GetRepoByURL(URL string) (IChartRepo, error) { ...@@ -141,7 +134,7 @@ func (rp *repoProvider) GetRepoByURL(URL string) (IChartRepo, error) {
return rp.createRepoByType(cr) return rp.createRepoByType(cr)
} }
func (rp *repoProvider) findRepoByURL(URL string) IChartRepo { func (rp *repoProvider) findRepoByChartURL(URL string) IChartRepo {
var found IChartRepo var found IChartRepo
for _, r := range rp.repos { for _, r := range rp.repos {
rURL := r.GetURL() rURL := r.GetURL()
...@@ -157,19 +150,14 @@ func (rp *repoProvider) findRepoByURL(URL string) IChartRepo { ...@@ -157,19 +150,14 @@ func (rp *repoProvider) findRepoByURL(URL string) IChartRepo {
// GetChartByReference maps the supplied chart reference into a fully qualified // GetChartByReference maps the supplied chart reference into a fully qualified
// URL, uses the URL to find the repository it references, queries the repository // URL, uses the URL to find the repository it references, queries the repository
// for the chart by URL, and returns the chart and the repository that backs it. // for the chart, and then returns the chart and the repository that backs it.
func (rp *repoProvider) GetChartByReference(reference string) (*chart.Chart, IChartRepo, error) { func (rp *repoProvider) GetChartByReference(reference string) (*chart.Chart, IChartRepo, error) {
l, err := ParseGCSChartReference(reference) l, URL, err := parseChartReference(reference)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
URL, err := l.Long(true) r, err := rp.GetRepoByChartURL(URL)
if err != nil {
return nil, nil, fmt.Errorf("invalid reference %s: %s", reference, err)
}
r, err := rp.GetRepoByURL(URL)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
...@@ -183,17 +171,45 @@ func (rp *repoProvider) GetChartByReference(reference string) (*chart.Chart, ICh ...@@ -183,17 +171,45 @@ func (rp *repoProvider) GetChartByReference(reference string) (*chart.Chart, ICh
return c, r, nil return c, r, nil
} }
// GCSRepoProvider is a factory for GCS IRepo instances. // IsChartReference returns true if the supplied string is a reference to a chart in a repository
type GCSRepoProvider interface { func IsChartReference(reference string) bool {
GetGCSRepo(r IRepo) (IStorageRepo, error) if _, err := ParseChartReference(reference); err != nil {
return false
}
return true
}
// ParseChartReference parses a reference to a chart in a repository and returns the URL for the chart
func ParseChartReference(reference string) (*chart.Locator, error) {
l, _, err := parseChartReference(reference)
if err != nil {
return nil, err
}
return l, nil
}
func parseChartReference(reference string) (*chart.Locator, string, error) {
l, err := chart.Parse(reference)
if err != nil {
return nil, "", fmt.Errorf("cannot parse chart reference %s: %s", reference, err)
}
URL, err := l.Long(true)
if err != nil {
return nil, "", fmt.Errorf("chart reference %s does not resolve to a URL: %s", reference, err)
}
return l, URL, nil
} }
type gcsRepoProvider struct { type gcsRepoProvider struct {
cp ICredentialProvider cp ICredentialProvider
} }
// NewGCSRepoProvider creates a GCSRepoProvider. // NewGCSRepoProvider creates a IGCSRepoProvider.
func NewGCSRepoProvider(cp ICredentialProvider) GCSRepoProvider { func NewGCSRepoProvider(cp ICredentialProvider) IGCSRepoProvider {
if cp == nil { if cp == nil {
cp = NewInmemCredentialProvider() cp = NewInmemCredentialProvider()
} }
...@@ -209,7 +225,7 @@ func (gcsrp gcsRepoProvider) GetGCSRepo(r IRepo) (IStorageRepo, error) { ...@@ -209,7 +225,7 @@ func (gcsrp gcsRepoProvider) GetGCSRepo(r IRepo) (IStorageRepo, error) {
return nil, err return nil, err
} }
return NewGCSRepo(r.GetName(), r.GetURL(), r.GetCredentialName(), client) return NewGCSRepo(r.GetURL(), r.GetCredentialName(), client)
} }
func (gcsrp gcsRepoProvider) createGCSClient(credentialName string) (*http.Client, error) { func (gcsrp gcsRepoProvider) createGCSClient(credentialName string) (*http.Client, error) {
...@@ -233,8 +249,8 @@ func (gcsrp gcsRepoProvider) createGCSClient(credentialName string) (*http.Clien ...@@ -233,8 +249,8 @@ func (gcsrp gcsRepoProvider) createGCSClient(credentialName string) (*http.Clien
} }
// IsGCSChartReference returns true if the supplied string is a reference to a chart in a GCS repository // IsGCSChartReference returns true if the supplied string is a reference to a chart in a GCS repository
func IsGCSChartReference(r string) bool { func IsGCSChartReference(reference string) bool {
if _, err := ParseGCSChartReference(r); err != nil { if _, err := ParseGCSChartReference(reference); err != nil {
return false return false
} }
...@@ -242,20 +258,15 @@ func IsGCSChartReference(r string) bool { ...@@ -242,20 +258,15 @@ func IsGCSChartReference(r string) bool {
} }
// ParseGCSChartReference parses a reference to a chart in a GCS repository and returns the URL for the chart // ParseGCSChartReference parses a reference to a chart in a GCS repository and returns the URL for the chart
func ParseGCSChartReference(r string) (*chart.Locator, error) { func ParseGCSChartReference(reference string) (*chart.Locator, error) {
l, err := chart.Parse(r) l, URL, err := parseChartReference(reference)
if err != nil {
return nil, fmt.Errorf("cannot parse chart reference %s: %s", r, err)
}
URL, err := l.Long(true)
if err != nil { if err != nil {
return nil, fmt.Errorf("chart reference %s does not resolve to a URL: %s", r, err) return nil, err
} }
m := GCSChartURLMatcher.FindStringSubmatch(URL) m := GCSChartURLMatcher.FindStringSubmatch(URL)
if len(m) != 4 { if len(m) != 4 {
return nil, fmt.Errorf("chart reference %s resolve to invalid URL: %s", r, URL) return nil, fmt.Errorf("chart reference %s resolve to invalid URL: %s", reference, URL)
} }
return l, nil return l, nil
......
...@@ -41,12 +41,12 @@ var InvalidChartReferences = []string{ ...@@ -41,12 +41,12 @@ var InvalidChartReferences = []string{
func TestRepoProvider(t *testing.T) { func TestRepoProvider(t *testing.T) {
rp := NewRepoProvider(nil, nil, nil) rp := NewRepoProvider(nil, nil, nil)
haveRepo, err := rp.GetRepoByName(GCSPublicRepoName) haveRepo, err := rp.GetRepoByURL(GCSPublicRepoURL)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := validateRepo(haveRepo, GCSPublicRepoName, GCSPublicRepoURL, "", GCSRepoFormat, GCSRepoType); err != nil { if err := validateRepo(haveRepo, GCSPublicRepoURL, "", GCSRepoFormat, GCSRepoType); err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -62,7 +62,8 @@ func TestRepoProvider(t *testing.T) { ...@@ -62,7 +62,8 @@ func TestRepoProvider(t *testing.T) {
} }
wantRepo := haveRepo wantRepo := haveRepo
haveRepo, err = rp.GetRepoByURL(GCSPublicRepoURL) URL := GCSPublicRepoURL + TestArchiveName
haveRepo, err = rp.GetRepoByChartURL(URL)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -72,21 +73,21 @@ func TestRepoProvider(t *testing.T) { ...@@ -72,21 +73,21 @@ func TestRepoProvider(t *testing.T) {
} }
} }
func TestGetRepoByNameWithInvalidName(t *testing.T) { func TestGetRepoByURLWithInvalidURL(t *testing.T) {
var invalidName = "InvalidRepoName" var invalidURL = "https://valid.url/wrong/scheme"
rp := NewRepoProvider(nil, nil, nil) rp := NewRepoProvider(nil, nil, nil)
_, err := rp.GetRepoByName(invalidName) _, err := rp.GetRepoByURL(invalidURL)
if err == nil { if err == nil {
t.Fatalf("found repo using invalid name: %s", invalidName) t.Fatalf("found repo using invalid URL: %s", invalidURL)
} }
} }
func TestGetRepoByURLWithInvalidURL(t *testing.T) { func TestGetRepoByChartURLWithInvalidChartURL(t *testing.T) {
var invalidURL = "https://valid.url/wrong/scheme" var invalidURL = "https://valid.url/wrong/scheme"
rp := NewRepoProvider(nil, nil, nil) rp := NewRepoProvider(nil, nil, nil)
_, err := rp.GetRepoByURL(invalidURL) _, err := rp.GetRepoByChartURL(invalidURL)
if err == nil { if err == nil {
t.Fatalf("found repo using invalid URL: %s", invalidURL) t.Fatalf("found repo using invalid chart URL: %s", invalidURL)
} }
} }
...@@ -115,12 +116,12 @@ func TestGetChartByReferenceWithValidReferences(t *testing.T) { ...@@ -115,12 +116,12 @@ func TestGetChartByReferenceWithValidReferences(t *testing.T) {
func getTestRepoProvider(t *testing.T) IRepoProvider { func getTestRepoProvider(t *testing.T) IRepoProvider {
rp := newRepoProvider(nil, nil, nil) rp := newRepoProvider(nil, nil, nil)
rs := rp.GetRepoService() rs := rp.GetRepoService()
tr, err := newRepo(TestRepoName, TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType) tr, err := newRepo(TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType)
if err != nil { if err != nil {
t.Fatalf("cannot create test repository: %s", err) t.Fatalf("cannot create test repository: %s", err)
} }
if err := rs.Create(tr); err != nil { if err := rs.CreateRepo(tr); err != nil {
t.Fatalf("cannot initialize repository service: %s", err) t.Fatalf("cannot initialize repository service: %s", err)
} }
......
...@@ -70,17 +70,14 @@ const ( ...@@ -70,17 +70,14 @@ const (
// Repo describes a repository // Repo describes a repository
type Repo struct { type Repo struct {
Name string `json:"name"` // Friendly name for this repository
URL string `json:"url"` // URL to the root of this repository URL string `json:"url"` // URL to the root of this repository
CredentialName string `json:"credentialname"` // Credential name used to access this repository CredentialName string `json:"credentialname,omitempty"` // Credential name used to access this repository
Format ERepoFormat `json:"format"` // Format of this repository Format ERepoFormat `json:"format,omitempty"` // Format of this repository
Type ERepoType `json:"type"` // Technology implementing this repository Type ERepoType `json:"type,omitempty"` // Technology implementing this repository
} }
// IRepo abstracts a repository. // IRepo abstracts a repository.
type IRepo interface { type IRepo interface {
// GetName returns the friendly name of this repository.
GetName() string
// GetURL returns the URL to the root of this repository. // GetURL returns the URL to the root of this repository.
GetURL() string GetURL() string
// GetCredentialName returns the credential name used to access this repository. // GetCredentialName returns the credential name used to access this repository.
...@@ -96,7 +93,7 @@ type IChartRepo interface { ...@@ -96,7 +93,7 @@ type IChartRepo interface {
// A IChartRepo is a IRepo // A IChartRepo is a IRepo
IRepo IRepo
// ListCharts lists charts in this repository whose string values // ListCharts lists the URLs for charts in this repository that
// conform to the supplied regular expression, or all charts if regex is nil // conform to the supplied regular expression, or all charts if regex is nil
ListCharts(regex *regexp.Regexp) ([]string, error) ListCharts(regex *regexp.Regexp) ([]string, error)
...@@ -117,14 +114,26 @@ type IStorageRepo interface { ...@@ -117,14 +114,26 @@ type IStorageRepo interface {
// IRepoService maintains a list of chart repositories that defines the scope of all // IRepoService maintains a list of chart repositories that defines the scope of all
// repository based operations, such as search and chart reference resolution. // repository based operations, such as search and chart reference resolution.
type IRepoService interface { type IRepoService interface {
// List returns the list of all known chart repositories // ListRepos returns the list of all known chart repositories
List() ([]string, error) ListRepos() ([]string, error)
// Create adds a known repository to the list // CreateRepo adds a known repository to the list
Create(repository IRepo) error CreateRepo(repository IRepo) error
// Get returns the repository with the given name // GetRepoByURL returns the repository with the given name
Get(name string) (IRepo, error) GetRepoByURL(name string) (IRepo, error)
// GetByURL returns the repository that backs the given URL // GetRepoByChartURL returns the repository that backs the given URL
GetByURL(URL string) (IRepo, error) GetRepoByChartURL(URL string) (IRepo, error)
// Delete removes a known repository from the list // DeleteRepo removes a known repository from the list
Delete(name string) error DeleteRepo(name string) error
}
// IRepoProvider is a factory for IChartRepo instances.
type IRepoProvider interface {
GetChartByReference(reference string) (*chart.Chart, IChartRepo, error)
GetRepoByChartURL(URL string) (IChartRepo, error)
GetRepoByURL(URL string) (IChartRepo, error)
}
// IGCSRepoProvider is a factory for GCS IRepo instances.
type IGCSRepoProvider interface {
GetGCSRepo(r IRepo) (IStorageRepo, error)
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment