From 17f22d777fbe4e4cc1931c7b2cfd3c9b6ff4277f Mon Sep 17 00:00:00 2001 From: jackgr Date: Thu, 7 Jan 2016 18:37:47 -0800 Subject: [PATCH] Merge changes from #172. --- common/types.go | 2 +- dm/dm.go | 2 +- manager/deployments.go | 68 ++++++++++- manager/manager/manager.go | 58 +++++++-- manager/manager/manager_test.go | 98 ++++++++++++++- manager/manager/typeresolver.go | 4 +- manager/manager/typeresolver_test.go | 32 +++++ registry/github_package_registry.go | 37 +++++- registry/github_registry.go | 54 +++++++++ ...y_service.go => inmem_registry_service.go} | 30 ++--- registry/registry.go | 48 +++++--- registry/registry_provider.go | 114 ++++++++++++++++++ registry/registryprovider.go | 55 --------- registry/semver.go | 80 ++++++++++++ 14 files changed, 575 insertions(+), 107 deletions(-) rename registry/{inmem_repository_service.go => inmem_registry_service.go} (64%) create mode 100644 registry/registry_provider.go delete mode 100644 registry/registryprovider.go create mode 100644 registry/semver.go diff --git a/common/types.go b/common/types.go index 72681820d..0bdda9e7a 100644 --- a/common/types.go +++ b/common/types.go @@ -190,7 +190,7 @@ type Registry struct { type RegistryType string const ( - Github RegistryType = "github" + GithubRegistryType RegistryType = "github" ) // RegistryFormat defines the format of the registry diff --git a/dm/dm.go b/dm/dm.go index 2c7e56151..95f48ffd0 100644 --- a/dm/dm.go +++ b/dm/dm.go @@ -82,7 +82,7 @@ var usage = func() { } func getGitRegistry() (registry.Registry, error) { - return registry.NewDefaultRegistryProvider().GetRegistry(*template_registry) + return registry.NewDefaultRegistryProvider().GetRegistryByURL(*template_registry) } func main() { diff --git a/manager/deployments.go b/manager/deployments.go index 02c21f8b3..1d728c829 100644 --- a/manager/deployments.go +++ b/manager/deployments.go @@ -50,6 +50,9 @@ var deployments = []Route{ {"ListTypes", "/types", "GET", listTypesHandlerFunc, ""}, {"ListTypeInstances", "/types/{type}/instances", "GET", listTypeInstancesHandlerFunc, ""}, {"ListRegistries", "/registries", "GET", listRegistriesHandlerFunc, ""}, + {"GetRegistry", "/registries/{registry}", "GET", getRegistryHandlerFunc, ""}, + {"ListCharts", "/registries/{registry}/charts", "GET", listChartsHandlerFunc, ""}, + {"GetChart", "/registries/{registry}/charts/{chart}", "GET", getChartHandlerFunc, ""}, } var ( @@ -72,11 +75,13 @@ func init() { } func newManager() manager.Manager { - expander := manager.NewExpander(getServiceURL(*expanderURL, *expanderName), manager.NewTypeResolver(registry.NewDefaultRegistryProvider())) + provider := registry.NewDefaultRegistryProvider() + resolver := manager.NewTypeResolver(provider) + expander := manager.NewExpander(getServiceURL(*expanderURL, *expanderName), resolver) deployer := manager.NewDeployer(getServiceURL(*deployerURL, *deployerName)) r := repository.NewMapBasedRepository() - registryService := registry.NewInmemRepositoryService() - return manager.NewManager(expander, deployer, r, registryService) + service := registry.NewInmemRegistryService() + return manager.NewManager(expander, deployer, r, provider, service) } func getServiceURL(serviceURL, serviceName string) string { @@ -342,5 +347,62 @@ func listRegistriesHandlerFunc(w http.ResponseWriter, r *http.Request) { if err != nil { return } + util.LogHandlerExitWithJSON(handler, w, registries, http.StatusOK) } + +func getRegistryHandlerFunc(w http.ResponseWriter, r *http.Request) { + handler := "manager: get registry" + util.LogHandlerEntry(handler, r) + registryName, err := getPathVariable(w, r, "registry", handler) + if err != nil { + return + } + + cr, err := backend.GetRegistry(registryName) + if err != nil { + util.LogAndReturnError(handler, http.StatusBadRequest, err, w) + return + } + + util.LogHandlerExitWithJSON(handler, w, cr, http.StatusOK) +} + +func listChartsHandlerFunc(w http.ResponseWriter, r *http.Request) { + handler := "manager: list charts" + util.LogHandlerEntry(handler, r) + registryName, err := getPathVariable(w, r, "registry", handler) + if err != nil { + return + } + + chartNames, err := backend.ListCharts(registryName) + if err != nil { + util.LogAndReturnError(handler, http.StatusInternalServerError, err, w) + return + } + + util.LogHandlerExitWithJSON(handler, w, chartNames, http.StatusOK) +} + +func getChartHandlerFunc(w http.ResponseWriter, r *http.Request) { + handler := "manager: get chart" + util.LogHandlerEntry(handler, r) + registryName, err := getPathVariable(w, r, "registry", handler) + if err != nil { + return + } + + chartName, err := getPathVariable(w, r, "chart", handler) + if err != nil { + return + } + + c, err := backend.GetChart(registryName, chartName) + if err != nil { + util.LogAndReturnError(handler, http.StatusBadRequest, err, w) + return + } + + util.LogHandlerExitWithJSON(handler, w, c, http.StatusOK) +} diff --git a/manager/manager/manager.go b/manager/manager/manager.go index 1953198ba..a8ecee6c3 100644 --- a/manager/manager/manager.go +++ b/manager/manager/manager.go @@ -28,33 +28,48 @@ import ( // Manager manages a persistent set of Deployments. type Manager interface { + // Deployments ListDeployments() ([]common.Deployment, error) GetDeployment(name string) (*common.Deployment, error) CreateDeployment(t *common.Template) (*common.Deployment, error) DeleteDeployment(name string, forget bool) (*common.Deployment, error) PutDeployment(name string, t *common.Template) (*common.Deployment, error) + + // Manifests ListManifests(deploymentName string) (map[string]*common.Manifest, error) GetManifest(deploymentName string, manifest string) (*common.Manifest, error) Expand(t *common.Template) (*common.Manifest, error) + + // Types ListTypes() []string ListInstances(typeName string) []*common.TypeInstance - // Registry related functions + + // Registries ListRegistries() ([]*common.Registry, error) CreateRegistry(pr *common.Registry) error GetRegistry(name string) (*common.Registry, error) DeleteRegistry(name string) error + + // Charts + ListCharts(registryName string) ([]string, error) + GetChart(registryName, chartName string) (*registry.Chart, error) } type manager struct { - expander Expander - deployer Deployer - repository repository.Repository - registryService registry.RegistryService + expander Expander + deployer Deployer + repository repository.Repository + provider registry.RegistryProvider + service registry.RegistryService } // NewManager returns a new initialized Manager. -func NewManager(expander Expander, deployer Deployer, repository repository.Repository, registryService registry.RegistryService) Manager { - return &manager{expander, deployer, repository, registryService} +func NewManager(expander Expander, + deployer Deployer, + repository repository.Repository, + provider registry.RegistryProvider, + service registry.RegistryService) Manager { + return &manager{expander, deployer, repository, provider, service} } // ListDeployments returns the list of deployments @@ -309,20 +324,21 @@ func (m *manager) ListInstances(typeName string) []*common.TypeInstance { return m.repository.GetTypeInstances(typeName) } +// ListRegistries returns the list of registries func (m *manager) ListRegistries() ([]*common.Registry, error) { - return m.registryService.List() + return m.service.List() } func (m *manager) CreateRegistry(pr *common.Registry) error { - return m.registryService.Create(pr) + return m.service.Create(pr) } func (m *manager) GetRegistry(name string) (*common.Registry, error) { - return m.registryService.Get(name) + return m.service.Get(name) } func (m *manager) DeleteRegistry(name string) error { - return m.registryService.Delete(name) + return m.service.Delete(name) } func generateManifestName() string { @@ -346,3 +362,23 @@ func getResourceErrors(c *common.Configuration) []string { return errs } + +// ListCharts retrieves the names of the charts in a given registry. +func (m *manager) ListCharts(registryName string) ([]string, error) { + r, err := m.provider.GetRegistryByName(registryName) + if err != nil { + return nil, err + } + + return r.ListCharts() +} + +// GetChart retrieves a given chart in a given registry. +func (m *manager) GetChart(registryName, chartName string) (*registry.Chart, error) { + r, err := m.provider.GetRegistryByName(registryName) + if err != nil { + return nil, err + } + + return r.GetChart(chartName) +} diff --git a/manager/manager/manager_test.go b/manager/manager/manager_test.go index d0e59efda..3cfb68891 100644 --- a/manager/manager/manager_test.go +++ b/manager/manager/manager_test.go @@ -66,7 +66,7 @@ var deploymentList = []common.Deployment{deployment, {Name: "test2"}} var typeInstMap = map[string][]string{"test": []string{"test"}} -var errTest = errors.New("test") +var errTest = errors.New("test error") type expanderStub struct{} @@ -164,6 +164,7 @@ func (repository *repositoryStub) ListDeployments() ([]common.Deployment, error) if repository.FailListDeployments { return deploymentList, errTest } + return deploymentList, nil } @@ -249,11 +250,102 @@ func (r *repositoryStub) SetTypeInstances(d string, is map[string][]*common.Type } } +type registryStub struct { + FailListCharts bool + FailGetChart bool + ListChartsCalled bool + GetChartCalled bool +} + +func newRegistryStub() *registryStub { + ret := ®istryStub{} + return ret +} + +func (r *registryStub) reset() { + r.FailListCharts = false + r.FailGetChart = false + r.ListChartsCalled = false + r.GetChartCalled = false +} + +var testRegistryName = "TestRegistry" +var testRegistryURL = "https://github.com/helm/charts" +var testChartName = "TestChart" + +var testChart = registry.Chart{ + Name: testChartName, +} + +var testChartList = []string{testChartName, "TestChart2"} + +func (r *registryStub) GetRegistryName() string { + return testRegistryName +} + +func (r *registryStub) GetRegistryType() common.RegistryType { + return common.GithubRegistryType +} + +func (r *registryStub) GetRegistryURL() string { + return testRegistryURL +} + +func (r *registryStub) ListCharts() ([]string, error) { + if r.FailListCharts { + return nil, errTest + } + + return testChartList, nil +} + +func (r *registryStub) GetChart(chartName string) (*registry.Chart, error) { + if !r.FailGetChart { + if chartName == testChartName { + return &testChart, nil + } + } + + return nil, errTest +} + +// Deprecated: Use ListCharts, instead. +func (r *registryStub) List() ([]registry.Type, error) { + return []registry.Type{}, nil +} + +// Deprecated: Use GetChart, instead. +func (r *registryStub) GetURLs(t registry.Type) ([]string, error) { + return []string{}, nil +} + +type registryProviderStub struct { + FailGetGithubRegistry bool + FailGetGithubPackageRegistry bool +} + +var testRegistryOwner = "TestOwner" +var testRegistryRepository = "TestRepository" + +func newRegistryProviderStub() *registryProviderStub { + ret := ®istryProviderStub{} + return ret +} + +func (rp *registryProviderStub) GetRegistryByURL(URL string) (registry.Registry, error) { + return newRegistryStub(), nil +} + +func (rp *registryProviderStub) GetRegistryByName(registryName string) (registry.Registry, error) { + return newRegistryStub(), nil +} + var testExpander = &expanderStub{} var testRepository = newRepositoryStub() var testDeployer = newDeployerStub() -var testRegistryService = registry.NewInmemRepositoryService() -var testManager = NewManager(testExpander, testDeployer, testRepository, testRegistryService) +var testRegistryService = registry.NewInmemRegistryService() +var testProvider = newRegistryProviderStub() +var testManager = NewManager(testExpander, testDeployer, testRepository, testProvider, testRegistryService) func TestListDeployments(t *testing.T) { testRepository.reset() diff --git a/manager/manager/typeresolver.go b/manager/manager/typeresolver.go index 3da460c23..99b4b86fa 100644 --- a/manager/manager/typeresolver.go +++ b/manager/manager/typeresolver.go @@ -244,7 +244,7 @@ func (tr *typeResolver) ShortTypeToDownloadURLs(template string) ([]string, erro if len(m) != 6 { return []string{}, fmt.Errorf("Failed to parse short github url: %s", template) } - r, err := tr.rp.GetRegistry(template) + r, err := tr.rp.GetRegistryByURL(template) if err != nil { return []string{}, err } @@ -262,7 +262,7 @@ func (tr *typeResolver) ShortTypeToPackageDownloadURLs(template string) ([]strin if len(m) != 4 { return []string{}, fmt.Errorf("Failed to parse short github url: %s", template) } - r, err := tr.rp.GetRegistry(template) + r, err := tr.rp.GetRegistryByURL(template) if err != nil { return []string{}, err } diff --git a/manager/manager/typeresolver_test.go b/manager/manager/typeresolver_test.go index 96010f4f8..a2e1d4f85 100644 --- a/manager/manager/typeresolver_test.go +++ b/manager/manager/typeresolver_test.go @@ -74,26 +74,58 @@ func newTestRegistryProvider(URLPrefix string, tests map[registry.Type]urlAndErr return &testRegistryProvider{URLPrefix, r} } +// Deprecated: Use GetRegistryByURL, instead. func (trp *testRegistryProvider) GetRegistry(URL string) (registry.Registry, error) { + return trp.GetRegistryByURL(URL) +} + +func (trp *testRegistryProvider) GetRegistryByURL(URL string) (registry.Registry, error) { for key, r := range trp.r { if strings.HasPrefix(URL, key) { return r, nil } } + return nil, fmt.Errorf("No registry found for %s", URL) } +func (trp *testRegistryProvider) GetRegistryByName(registryName string) (registry.Registry, error) { + return newRegistryStub(), nil +} + type testGithubRegistry struct { responses map[registry.Type]urlAndError count int } +func (r *testGithubRegistry) GetRegistryName() string { + return "" +} + +func (r *testGithubRegistry) GetRegistryType() common.RegistryType { + return common.GithubRegistryType +} + +func (r *testGithubRegistry) GetRegistryURL() string { + return "" +} + +func (r *testGithubRegistry) ListCharts() ([]string, error) { + return []string{}, fmt.Errorf("ListCharts should not be called in the test") +} + +func (r *testGithubRegistry) GetChart(chartName string) (*registry.Chart, error) { + return nil, fmt.Errorf("GetChart should not be called in the test") +} + +// Deprecated: Use GetChart, instead. func (tgr *testGithubRegistry) GetURLs(t registry.Type) ([]string, error) { tgr.count = tgr.count + 1 ret := tgr.responses[t] return []string{ret.u}, ret.e } +// Deprecated: Use ListCharts, instead. func (tgr *testGithubRegistry) List() ([]registry.Type, error) { return []registry.Type{}, fmt.Errorf("List should not be called in the test") } diff --git a/registry/github_package_registry.go b/registry/github_package_registry.go index ba8c903a2..30fbdee04 100644 --- a/registry/github_package_registry.go +++ b/registry/github_package_registry.go @@ -17,10 +17,11 @@ limitations under the License. package registry import ( + "github.com/google/go-github/github" + "github.com/kubernetes/deployment-manager/common" + "log" "strings" - - "github.com/google/go-github/github" ) // GithubPackageRegistry implements the Registry interface that talks to github and @@ -47,6 +48,37 @@ func NewGithubPackageRegistry(owner, repository string, client *github.Client) * } } +// GetRegistryName returns the name of this registry +func (g *GithubPackageRegistry) GetRegistryName() string { + // TODO(jackgr): implement this method + return "" +} + +// GetRegistryType returns the type of this registry. +func (g *GithubPackageRegistry) GetRegistryType() common.RegistryType { + // TODO(jackgr): implement this method + return common.GithubRegistryType +} + +// GetRegistryURL returns the URL for this registry. +func (g *GithubPackageRegistry) GetRegistryURL() string { + // TODO(jackgr): implement this method + return "" +} + +// ListCharts lists the versioned chart names in this registry. +func (g *GithubPackageRegistry) ListCharts() ([]string, error) { + // TODO(jackgr): implement this method + return []string{}, nil +} + +// GetChart fetches the contents of a given chart. +func (g *GithubPackageRegistry) GetChart(chartName string) (*Chart, error) { + // TODO(jackgr): implement this method + return nil, nil +} + +// Deprecated: Use ListCharts, instead. // List the types from the Registry. func (g *GithubPackageRegistry) List() ([]Type, error) { // Just list all the types at the top level. @@ -74,6 +106,7 @@ func (g *GithubPackageRegistry) List() ([]Type, error) { return retTypes, nil } +// Deprecated: Use GetChart, instead. // GetURLs fetches the download URLs for a given Type. func (g *GithubPackageRegistry) GetURLs(t Type) ([]string, error) { path, err := g.MakeRepositoryPath(t) diff --git a/registry/github_registry.go b/registry/github_registry.go index c3cf70f01..970340faa 100644 --- a/registry/github_registry.go +++ b/registry/github_registry.go @@ -18,6 +18,7 @@ package registry import ( "github.com/google/go-github/github" + "github.com/kubernetes/deployment-manager/common" "fmt" "log" @@ -64,6 +65,58 @@ func NewGithubRegistry(owner, repository, path string, client *github.Client) *G } } +// GetRegistryName returns the name of this registry +func (g *GithubRegistry) GetRegistryName() string { + // TODO(jackgr): implement this method + return "" +} + +// GetRegistryType returns the type of this registry. +func (g *GithubRegistry) GetRegistryType() common.RegistryType { + // TODO(jackgr): implement this method + return common.GithubRegistryType +} + +// GetRegistryURL returns the URL for this registry. +func (g *GithubRegistry) GetRegistryURL() string { + // TODO(jackgr): implement this method + return "" +} + +// ListCharts lists the versioned chart names in this registry. +func (g *GithubRegistry) ListCharts() ([]string, error) { + var result []string + names, err := g.getDirs("") + if err != nil { + log.Printf("Failed to fetch chart names from registry: %s/%s/%s", g.owner, g.repository, g.path) + return nil, err + } + + // Fetch the chart names + for _, name := range names { + // Then fetch the versions for each chart name + versions, err := g.getDirs("/" + name) + if err != nil { + log.Printf("Failed to fetch versions for chart name: %s/%s/%s/%s", + g.owner, g.repository, g.path, name) + return nil, err + } + + for _, version := range versions { + result = append(result, fmt.Sprintf("%s#%s", name, version)) + } + } + + return result, nil +} + +// GetChart fetches the contents of a given chart. +func (g *GithubRegistry) GetChart(chartName string) (*Chart, error) { + // TODO(jackgr): implement this method + return nil, nil +} + +// Deprecated: Use ListCharts, instead. // List the types from the Registry. func (g *GithubRegistry) List() ([]Type, error) { // First list all the collections at the top level. @@ -98,6 +151,7 @@ func (g *GithubRegistry) List() ([]Type, error) { return retTypes, nil } +// Deprecated: Use GetChart, instead. // GetURL fetches the download URL for a given Type and checks for existence of a schema file. func (g *GithubRegistry) GetURLs(t Type) ([]string, error) { path, err := g.MakeRepositoryPath(t) diff --git a/registry/inmem_repository_service.go b/registry/inmem_registry_service.go similarity index 64% rename from registry/inmem_repository_service.go rename to registry/inmem_registry_service.go index 47845ac26..71de20818 100644 --- a/registry/inmem_repository_service.go +++ b/registry/inmem_registry_service.go @@ -23,53 +23,53 @@ import ( "github.com/kubernetes/deployment-manager/common" ) -type inmemRepositoryService struct { - repositories map[string]*common.Registry +type inmemRegistryService struct { + registries map[string]*common.Registry } -func NewInmemRepositoryService() RegistryService { - rs := &inmemRepositoryService{ - repositories: make(map[string]*common.Registry), +func NewInmemRegistryService() RegistryService { + rs := &inmemRegistryService{ + registries: make(map[string]*common.Registry), } rs.Create(&common.Registry{ Name: "charts", - Type: common.Github, + Type: common.GithubRegistryType, URL: "github.com/helm/charts", Format: common.UnversionedRegistry, }) rs.Create(&common.Registry{ Name: "application-dm-templates", - Type: common.Github, + Type: common.GithubRegistryType, URL: "github.com/kubernetes/application-dm-templates", Format: common.VersionedRegistry, }) return rs } -func (rs *inmemRepositoryService) List() ([]*common.Registry, error) { +func (rs *inmemRegistryService) List() ([]*common.Registry, error) { ret := []*common.Registry{} - for _, r := range rs.repositories { + for _, r := range rs.registries { ret = append(ret, r) } return ret, nil } -func (rs *inmemRepositoryService) Create(repository *common.Registry) error { - rs.repositories[repository.URL] = repository +func (rs *inmemRegistryService) Create(registry *common.Registry) error { + rs.registries[registry.URL] = registry return nil } -func (rs *inmemRepositoryService) Get(name string) (*common.Registry, error) { +func (rs *inmemRegistryService) Get(name string) (*common.Registry, error) { return &common.Registry{}, nil } -func (rs *inmemRepositoryService) Delete(name string) error { +func (rs *inmemRegistryService) Delete(name string) error { return nil } // GetByURL returns a registry that handles the types for a given URL. -func (rs *inmemRepositoryService) GetByURL(URL string) (*common.Registry, error) { - for _, r := range rs.repositories { +func (rs *inmemRegistryService) GetByURL(URL string) (*common.Registry, error) { + for _, r := range rs.registries { if strings.HasPrefix(URL, r.URL) { return r, nil } diff --git a/registry/registry.go b/registry/registry.go index 9e8269bb4..44c037d4d 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -20,13 +20,37 @@ import ( "strings" "github.com/kubernetes/deployment-manager/common" + + "net/url" ) +// Registry abstracts a registry that holds charts, which can be +// used in a Deployment Manager configuration. There can be multiple +// registry implementations. +type Registry interface { + // GetRegistryName returns the name of this registry + GetRegistryName() string + // GetRegistryType returns the type of this registry. + GetRegistryType() common.RegistryType + // GetRegistryURL returns the URL for this registry. + GetRegistryURL() string + + // ListCharts lists the versioned chart names in this registry. + ListCharts() ([]string, error) + // GetChart fetches the contents of a given chart. + GetChart(chartName string) (*Chart, error) + + // Deprecated: Use ListCharts, instead. + List() ([]Type, error) + // Deprecated: Use GetChart, instead. + GetURLs(t Type) ([]string, error) +} + type RegistryService interface { // List all the registries List() ([]*common.Registry, error) // Create a new registry - Create(repository *common.Registry) error + Create(registry *common.Registry) error // Get a registry Get(name string) (*common.Registry, error) // Delete a registry @@ -35,13 +59,7 @@ type RegistryService interface { GetByURL(URL string) (*common.Registry, error) } -// Registry abstracts a registry that holds templates, which can be -// used in a Deployment Manager configurations. There can be multiple -// implementations of a registry. Currently we support Deployment Manager -// github.com/kubernetes/application-dm-templates -// and helm packages -// github.com/helm/charts -// +// Deprecated: Use Chart, instead type Type struct { Collection string Name string @@ -68,10 +86,12 @@ func ParseType(name string) *Type { return tt } -// Registry abstracts type interactions. -type Registry interface { - // List all the templates at the given path - List() ([]Type, error) - // Get the download URL(s) for a given type - GetURLs(t Type) ([]string, error) +type Chart struct { + Name string + Version SemVer + RegistryURL string + DownloadURLs []url.URL + + // TODO(jackgr): Should the metadata be strongly typed? + Metadata map[string]interface{} } diff --git a/registry/registry_provider.go b/registry/registry_provider.go new file mode 100644 index 000000000..9e97d62bc --- /dev/null +++ b/registry/registry_provider.go @@ -0,0 +1,114 @@ +/* +Copyright 2015 The Kubernetes Authors 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 ( + "fmt" + "strings" + "sync" + + "github.com/google/go-github/github" + "github.com/kubernetes/deployment-manager/common" +) + +// RegistryProvider returns factories for creating registry clients. +type RegistryProvider interface { + GetRegistryByURL(URL string) (Registry, error) + GetRegistryByName(registryName string) (Registry, error) +} + +func NewDefaultRegistryProvider() RegistryProvider { + registries := make(map[string]Registry) + rs := NewInmemRegistryService() + return &DefaultRegistryProvider{registries: registries, rs: rs} +} + +type DefaultRegistryProvider struct { + sync.RWMutex + registries map[string]Registry + rs RegistryService +} + +func (drp *DefaultRegistryProvider) GetRegistryByURL(URL string) (Registry, error) { + drp.RLock() + defer drp.RUnlock() + + ghr := drp.findRegistryByURL(URL) + if ghr == nil { + cr, err := drp.rs.GetByURL(URL) + if err != nil { + return nil, err + } + + ghr, err := drp.getGithubRegistry(cr) + if err != nil { + return nil, err + } + + drp.registries[ghr.GetRegistryName()] = ghr + } + + return ghr, nil +} + +func (drp *DefaultRegistryProvider) findRegistryByURL(URL string) Registry { + for _, ghr := range drp.registries { + if strings.HasPrefix(URL, ghr.GetRegistryURL()) { + return ghr + } + } + + return nil +} + +func (drp *DefaultRegistryProvider) GetRegistryByName(registryName string) (Registry, error) { + drp.RLock() + defer drp.RUnlock() + + ghr, ok := drp.registries[registryName] + if !ok { + cr, err := drp.rs.Get(registryName) + if err != nil { + return nil, err + } + + ghr, err := drp.getGithubRegistry(cr) + if err != nil { + return nil, err + } + + drp.registries[ghr.GetRegistryName()] = ghr + } + + return ghr, nil +} + +func (drp *DefaultRegistryProvider) getGithubRegistry(cr *common.Registry) (Registry, error) { + // TODO(jackgr): Take owner and repository from cr instead of hard wiring + if cr.Type == common.GithubRegistryType { + switch cr.Format { + case common.UnversionedRegistry: + return NewGithubPackageRegistry("helm", "charts", github.NewClient(nil)), nil + case common.VersionedRegistry: + return NewGithubRegistry("kubernetes", "application-dm-templates", "", github.NewClient(nil)), nil + default: + return nil, fmt.Errorf("unknown registry format: %s", cr.Format) + } + } + + return nil, fmt.Errorf("unknown registry type: %s", cr.Type) +} diff --git a/registry/registryprovider.go b/registry/registryprovider.go deleted file mode 100644 index f767e896d..000000000 --- a/registry/registryprovider.go +++ /dev/null @@ -1,55 +0,0 @@ -/* -Copyright 2015 The Kubernetes Authors 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 ( - "fmt" - - "github.com/google/go-github/github" - "github.com/kubernetes/deployment-manager/common" -) - -// RegistryProvider returns factories for creating registries for a given RegistryType. -type RegistryProvider interface { - GetRegistry(prefix string) (Registry, error) -} - -func NewDefaultRegistryProvider() RegistryProvider { - rs := NewInmemRepositoryService() - return &DefaultRegistryProvider{rs: rs} - -} - -type DefaultRegistryProvider struct { - rs RegistryService -} - -func (drp *DefaultRegistryProvider) GetRegistry(URL string) (Registry, error) { - r, err := drp.rs.GetByURL(URL) - if err != nil { - return nil, err - } - if r.Type == common.Github { - if r.Format == common.UnversionedRegistry { - return NewGithubPackageRegistry("helm", "charts", github.NewClient(nil)), nil - } - if r.Format == common.VersionedRegistry { - return NewGithubRegistry("kubernetes", "application-dm-templates", "", github.NewClient(nil)), nil - } - } - return nil, fmt.Errorf("cannot find registry backing url %s", URL) -} diff --git a/registry/semver.go b/registry/semver.go new file mode 100644 index 000000000..f5c1ff596 --- /dev/null +++ b/registry/semver.go @@ -0,0 +1,80 @@ +/* +Copyright 2015 The Kubernetes Authors 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 ( + "fmt" + "strconv" + "strings" +) + +type SemVer struct { + Major uint + Minor uint + Patch uint +} + +func NewSemVer(version string) (*SemVer, error) { + result := &SemVer{} + parts := strings.SplitN(version, ".", 3) + if len(parts) > 3 { + return nil, fmt.Errorf("invalid semantic version: %s", version) + } + + major, err := strconv.ParseUint(parts[0], 10, 0) + if err != nil { + return nil, fmt.Errorf("invalid semantic version: %s", version) + } + + result.Major = uint(major) + if len(parts) < 3 { + if len(parts) < 2 { + if len(parts) < 1 { + return nil, fmt.Errorf("invalid semantic version: %s", version) + } + } else { + minor, err := strconv.ParseUint(parts[1], 10, 0) + if err != nil { + return nil, fmt.Errorf("invalid semantic version: %s", version) + } + + result.Minor = uint(minor) + } + } else { + patch, err := strconv.ParseUint(parts[2], 10, 0) + if err != nil { + return nil, fmt.Errorf("invalid semantic version: %s", version) + } + + result.Patch = uint(patch) + } + + return result, nil +} + +func (s *SemVer) String() string { + result := strconv.Itoa(int(s.Major)) + if s.Minor != 0 || s.Patch != 0 { + result = result + "." + strconv.Itoa(int(s.Minor)) + } + + if s.Patch != 0 { + result = result + "." + strconv.Itoa(int(s.Patch)) + } + + return result +}