Commit 51bbfafc authored by Jack Greenfield's avatar Jack Greenfield

Merge pull request #440 from jackgr/manager

Second round of refactoring for Manager
parents 91a007cf 3da6a66c
...@@ -38,7 +38,7 @@ import ( ...@@ -38,7 +38,7 @@ import (
"github.com/kubernetes/helm/cmd/manager/router" "github.com/kubernetes/helm/cmd/manager/router"
"github.com/kubernetes/helm/pkg/common" "github.com/kubernetes/helm/pkg/common"
"github.com/kubernetes/helm/pkg/httputil" "github.com/kubernetes/helm/pkg/httputil"
"github.com/kubernetes/helm/pkg/registry" "github.com/kubernetes/helm/pkg/repo"
"github.com/kubernetes/helm/pkg/util" "github.com/kubernetes/helm/pkg/util"
) )
...@@ -66,16 +66,18 @@ func registerDeploymentRoutes(c *router.Context, h *router.Handler) { ...@@ -66,16 +66,18 @@ func registerDeploymentRoutes(c *router.Context, h *router.Handler) {
h.Add("GET /deployments/*/manifests", listManifestsHandlerFunc) h.Add("GET /deployments/*/manifests", listManifestsHandlerFunc)
h.Add("GET /deployments/*/manifests/*", getManifestHandlerFunc) h.Add("GET /deployments/*/manifests/*", getManifestHandlerFunc)
h.Add("POST /expand", expandHandlerFunc) h.Add("POST /expand", expandHandlerFunc)
h.Add("GET /types", listTypesHandlerFunc) h.Add("GET /charts", listChartsHandlerFunc)
h.Add("GET /types/*/instances", listTypeInstancesHandlerFunc) h.Add("GET /charts/*/instances", listChartInstancesHandlerFunc)
h.Add("GET /types/*/registry", getRegistryForTypeHandlerFunc) h.Add("GET /charts/*/repository", getRepoForChartHandlerFunc)
h.Add("GET /types/*/metadata", getMetadataForTypeHandlerFunc) h.Add("GET /charts/*/metadata", getMetadataForChartHandlerFunc)
h.Add("GET /registries", listRegistriesHandlerFunc) h.Add("GET /charts/*", getChartHandlerFunc)
h.Add("GET /registries/*", getRegistryHandlerFunc)
h.Add("POST /registries/*", createRegistryHandlerFunc) // TODO: Refactor these commented out routes
h.Add("GET /registries/*/types", listRegistryTypesHandlerFunc) // h.Add("GET /repositories/*", getRepoHandlerFunc)
h.Add("GET /registries/*/types/*", getDownloadURLsHandlerFunc) // h.Add("POST /repositories/*", createRepoHandlerFunc)
h.Add("GET /registries/*/download", getFileHandlerFunc)
h.Add("GET /repositories/*/charts", listRepositoryChartsHandlerFunc)
h.Add("GET /repositories/*/charts/*", getRepositoryChartHandlerFunc)
h.Add("POST /credentials/*", createCredentialHandlerFunc) h.Add("POST /credentials/*", createCredentialHandlerFunc)
h.Add("GET /credentials/*", getCredentialHandlerFunc) h.Add("GET /credentials/*", getCredentialHandlerFunc)
} }
...@@ -89,20 +91,20 @@ func healthz(w http.ResponseWriter, r *http.Request, c *router.Context) error { ...@@ -89,20 +91,20 @@ func healthz(w http.ResponseWriter, r *http.Request, c *router.Context) error {
} }
func setupDependencies(c *router.Context) error { func setupDependencies(c *router.Context) error {
var credentialProvider common.CredentialProvider var credentialProvider repo.ICredentialProvider
if c.Config.CredentialFile != "" { if c.Config.CredentialFile != "" {
if c.Config.CredentialSecrets { if c.Config.CredentialSecrets {
return errors.New("Both credentialFile and credentialSecrets are set") return errors.New("Both credentialFile and credentialSecrets are set")
} }
var err error var err error
credentialProvider, err = registry.NewFilebasedCredentialProvider(c.Config.CredentialFile) credentialProvider, err = repo.NewFilebasedCredentialProvider(c.Config.CredentialFile)
if err != nil { if err != nil {
return fmt.Errorf("cannot create credential provider %s: %s", c.Config.CredentialFile, err) return fmt.Errorf("cannot create credential provider %s: %s", c.Config.CredentialFile, err)
} }
} else if *credentialSecrets { } else if *credentialSecrets {
credentialProvider = registry.NewSecretsCredentialProvider() credentialProvider = repo.NewSecretsCredentialProvider()
} else { } else {
credentialProvider = registry.NewInmemCredentialProvider() credentialProvider = repo.NewInmemCredentialProvider()
} }
c.CredentialProvider = credentialProvider c.CredentialProvider = credentialProvider
c.Manager = newManager(c) c.Manager = newManager(c)
...@@ -115,14 +117,14 @@ const deployerPort = "8080" ...@@ -115,14 +117,14 @@ const deployerPort = "8080"
func newManager(c *router.Context) manager.Manager { func newManager(c *router.Context) manager.Manager {
cfg := c.Config cfg := c.Config
service := registry.NewInmemRegistryService() service := repo.NewInmemRepoService()
registryProvider := registry.NewDefaultRegistryProvider(c.CredentialProvider, service) cp := c.CredentialProvider
resolver := manager.NewTypeResolver(registryProvider, util.DefaultHTTPClient()) repoProvider := repo.NewRepoProvider(service, repo.NewGCSRepoProvider(cp), cp)
expander := manager.NewExpander(getServiceURL(cfg.ExpanderURL, cfg.ExpanderName, expanderPort), resolver) expander := manager.NewExpander(getServiceURL(cfg.ExpanderURL, cfg.ExpanderName, expanderPort))
deployer := manager.NewDeployer(getServiceURL(cfg.DeployerURL, cfg.DeployerName, deployerPort)) deployer := manager.NewDeployer(getServiceURL(cfg.DeployerURL, cfg.DeployerName, deployerPort))
address := strings.TrimPrefix(getServiceURL(cfg.MongoAddress, cfg.MongoName, cfg.MongoPort), "http://") address := strings.TrimPrefix(getServiceURL(cfg.MongoAddress, cfg.MongoName, cfg.MongoPort), "http://")
repository := createRepository(address) repository := createRepository(address)
return manager.NewManager(expander, deployer, repository, registryProvider, service, c.CredentialProvider) return manager.NewManager(expander, deployer, repository, repoProvider, service, c.CredentialProvider)
} }
func createRepository(address string) repository.Repository { func createRepository(address string) repository.Repository {
...@@ -369,10 +371,10 @@ func expandHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context ...@@ -369,10 +371,10 @@ func expandHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context
// Putting Type handlers here for now because deployments.go // Putting Type handlers here for now because deployments.go
// currently owns its own Manager backend and doesn't like to share. // currently owns its own Manager backend and doesn't like to share.
func listTypesHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error { func listChartsHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: list types" handler := "manager: list charts"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
types, err := c.Manager.ListTypes() types, err := c.Manager.ListCharts()
if err != nil { if err != nil {
httputil.BadRequest(w, r, err) httputil.BadRequest(w, r, err)
return nil return nil
...@@ -382,15 +384,15 @@ func listTypesHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Cont ...@@ -382,15 +384,15 @@ func listTypesHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Cont
return nil return nil
} }
func listTypeInstancesHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error { func listChartInstancesHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: list instances" handler := "manager: list chart instances"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
typeName, err := pos(w, r, 2) chartName, err := pos(w, r, 2)
if err != nil { if err != nil {
return err return err
} }
instances, err := c.Manager.ListInstances(typeName) instances, err := c.Manager.ListChartInstances(chartName)
if err != nil { if err != nil {
httputil.BadRequest(w, r, err) httputil.BadRequest(w, r, err)
return nil return nil
...@@ -400,33 +402,33 @@ func listTypeInstancesHandlerFunc(w http.ResponseWriter, r *http.Request, c *rou ...@@ -400,33 +402,33 @@ func listTypeInstancesHandlerFunc(w http.ResponseWriter, r *http.Request, c *rou
return nil return nil
} }
func getRegistryForTypeHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error { func getRepoForChartHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get type registry" handler := "manager: get repository for chart"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
typeName, err := pos(w, r, 2) chartName, err := pos(w, r, 2)
if err != nil { if err != nil {
return err return err
} }
registry, err := c.Manager.GetRegistryForType(typeName) repository, err := c.Manager.GetRepoForChart(chartName)
if err != nil { if err != nil {
httputil.BadRequest(w, r, err) httputil.BadRequest(w, r, err)
return nil return nil
} }
util.LogHandlerExitWithJSON(handler, w, registry, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, repository, http.StatusOK)
return nil return nil
} }
func getMetadataForTypeHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error { func getMetadataForChartHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get type metadata" handler := "manager: get chart metadata"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
typeName, err := pos(w, r, 2) chartName, err := pos(w, r, 2)
if err != nil { if err != nil {
return err return err
} }
metadata, err := c.Manager.GetMetadataForType(typeName) metadata, err := c.Manager.GetMetadataForChart(chartName)
if err != nil { if err != nil {
httputil.BadRequest(w, r, err) httputil.BadRequest(w, r, err)
return nil return nil
...@@ -436,29 +438,37 @@ func getMetadataForTypeHandlerFunc(w http.ResponseWriter, r *http.Request, c *ro ...@@ -436,29 +438,37 @@ func getMetadataForTypeHandlerFunc(w http.ResponseWriter, r *http.Request, c *ro
return nil return nil
} }
// Putting Registry handlers here for now because deployments.go func getChartHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
// currently owns its own Manager backend and doesn't like to share. handler := "manager: get chart"
func listRegistriesHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: list registries"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
registries, err := c.Manager.ListRegistries() chartName, err := pos(w, r, 2)
if err != nil { if err != nil {
return err return err
} }
util.LogHandlerExitWithJSON(handler, w, registries, http.StatusOK) ch, err := c.Manager.GetChart(chartName)
if err != nil {
httputil.BadRequest(w, r, err)
return nil
}
util.LogHandlerExitWithJSON(handler, w, ch, http.StatusOK)
return nil return nil
} }
func getRegistryHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error { // TODO: Refactor this commented out code.
handler := "manager: get registry"
/*
func getRepoHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get repository"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
registryName, err := pos(w, r, 2) repoName, err := pos(w, r, 2)
if err != nil { if err != nil {
return err return err
} }
cr, err := c.Manager.GetRegistry(registryName) cr, err := c.Manager.GetRepo(repoName)
if err != nil { if err != nil {
httputil.BadRequest(w, r, err) httputil.BadRequest(w, r, err)
return nil return nil
...@@ -468,10 +478,10 @@ func getRegistryHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Co ...@@ -468,10 +478,10 @@ func getRegistryHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Co
return nil return nil
} }
func getRegistry(w http.ResponseWriter, r *http.Request, handler string) *common.Registry { func getRepo(w http.ResponseWriter, r *http.Request, handler string) *repo.Repo {
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
t := &common.Registry{} t := &repo.Repo{}
if err := httputil.Decode(w, r, t); err != nil { if err := httputil.Decode(w, r, t); err != nil {
httputil.BadRequest(w, r, err) httputil.BadRequest(w, r, err)
return nil return nil
...@@ -479,23 +489,23 @@ func getRegistry(w http.ResponseWriter, r *http.Request, handler string) *common ...@@ -479,23 +489,23 @@ func getRegistry(w http.ResponseWriter, r *http.Request, handler string) *common
return t return t
} }
func createRegistryHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error { func createRepoHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: create registry" handler := "manager: create repository"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
defer r.Body.Close() defer r.Body.Close()
registryName, err := pos(w, r, 2) repoName, err := pos(w, r, 2)
if err != nil { if err != nil {
return err return err
} }
reg := getRegistry(w, r, handler) reg := getRepo(w, r, handler)
if reg.Name != registryName { if reg.Name != repoName {
e := fmt.Errorf("Registry name does not match %s != %s", reg.Name, registryName) e := fmt.Errorf("Repo name does not match %s != %s", reg.Name, repoName)
httputil.BadRequest(w, r, e) httputil.BadRequest(w, r, e)
return nil return nil
} }
if reg != nil { if reg != nil {
err = c.Manager.CreateRegistry(reg) err = c.Manager.CreateRepo(reg)
if err != nil { if err != nil {
httputil.BadRequest(w, r, err) httputil.BadRequest(w, r, err)
return nil return nil
...@@ -505,11 +515,12 @@ func createRegistryHandlerFunc(w http.ResponseWriter, r *http.Request, c *router ...@@ -505,11 +515,12 @@ func createRegistryHandlerFunc(w http.ResponseWriter, r *http.Request, c *router
util.LogHandlerExitWithJSON(handler, w, reg, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, reg, http.StatusOK)
return nil return nil
} }
*/
func listRegistryTypesHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error { func listRepositoryChartsHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: list registry types" handler := "manager: list repository charts"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
registryName, err := pos(w, r, 2) repoName, err := pos(w, r, 2)
if err != nil { if err != nil {
return err return err
} }
...@@ -530,73 +541,40 @@ func listRegistryTypesHandlerFunc(w http.ResponseWriter, r *http.Request, c *rou ...@@ -530,73 +541,40 @@ func listRegistryTypesHandlerFunc(w http.ResponseWriter, r *http.Request, c *rou
} }
} }
registryTypes, err := c.Manager.ListRegistryTypes(registryName, regex) repoCharts, err := c.Manager.ListRepoCharts(repoName, regex)
if err != nil { if err != nil {
return err return err
} }
util.LogHandlerExitWithJSON(handler, w, registryTypes, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, repoCharts, http.StatusOK)
return nil return nil
} }
func getDownloadURLsHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error { func getRepositoryChartHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get download URLs" handler := "manager: get repository charts"
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
registryName, err := pos(w, r, 2) repoName, err := pos(w, r, 2)
if err != nil {
return err
}
typeName, err := pos(w, r, 4)
if err != nil { if err != nil {
return err return err
} }
tt, err := registry.ParseType(typeName) chartName, err := pos(w, r, 4)
if err != nil { if err != nil {
return err return err
} }
cr, err := c.Manager.GetDownloadURLs(registryName, tt) repoChart, err := c.Manager.GetChartForRepo(repoName, chartName)
if err != nil {
httputil.BadRequest(w, r, err)
return nil
}
urls := []string{}
for _, u := range cr {
urls = append(urls, u.String())
}
util.LogHandlerExitWithJSON(handler, w, urls, http.StatusOK)
return nil
}
func getFileHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get file"
util.LogHandlerEntry(handler, r)
registryName, err := pos(w, r, 2)
if err != nil { if err != nil {
return err return err
} }
file := r.FormValue("file") util.LogHandlerExitWithJSON(handler, w, repoChart, http.StatusOK)
if file == "" {
return err
}
b, err := c.Manager.GetFile(registryName, file)
if err != nil {
httputil.BadRequest(w, r, err)
return nil
}
util.LogHandlerExitWithJSON(handler, w, b, http.StatusOK)
return nil return nil
} }
func getCredential(w http.ResponseWriter, r *http.Request, handler string) *common.RegistryCredential { func getCredential(w http.ResponseWriter, r *http.Request, handler string) *repo.Credential {
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
t := &common.RegistryCredential{} t := &repo.Credential{}
if err := httputil.Decode(w, r, t); err != nil { if err := httputil.Decode(w, r, t); err != nil {
httputil.BadRequest(w, r, err) httputil.BadRequest(w, r, err)
return nil return nil
......
...@@ -43,8 +43,17 @@ type Expander interface { ...@@ -43,8 +43,17 @@ type Expander interface {
ExpandTemplate(t *common.Template) (*ExpandedTemplate, error) ExpandTemplate(t *common.Template) (*ExpandedTemplate, error)
} }
// TODO: Remove mockResolver when type resolver is completely excised
type mockResolver struct {
}
func (r *mockResolver) ResolveTypes(c *common.Configuration, i []*common.ImportFile) ([]*common.ImportFile, error) {
return nil, nil
}
// NewExpander returns a new initialized Expander. // NewExpander returns a new initialized Expander.
func NewExpander(url string, tr TypeResolver) Expander { func NewExpander(url string) Expander {
tr := &mockResolver{}
return &expander{url, tr} return &expander{url, tr}
} }
...@@ -53,6 +62,12 @@ type expander struct { ...@@ -53,6 +62,12 @@ type expander struct {
typeResolver TypeResolver typeResolver TypeResolver
} }
// TypeResolver finds Types in a Configuration which aren't yet reduceable to an import file
// or primitive, and attempts to replace them with a template from a URL.
type TypeResolver interface {
ResolveTypes(config *common.Configuration, imports []*common.ImportFile) ([]*common.ImportFile, error)
}
func (e *expander) getBaseURL() string { func (e *expander) getBaseURL() string {
return fmt.Sprintf("%s/expand", e.expanderURL) return fmt.Sprintf("%s/expand", e.expanderURL)
} }
......
...@@ -32,21 +32,6 @@ import ( ...@@ -32,21 +32,6 @@ import (
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
) )
type mockResolver struct {
responses [][]*common.ImportFile
t *testing.T
}
func (r *mockResolver) ResolveTypes(c *common.Configuration, i []*common.ImportFile) ([]*common.ImportFile, error) {
if len(r.responses) < 1 {
return nil, nil
}
ret := r.responses[0]
r.responses = r.responses[1:]
return ret, nil
}
var validTemplateTestCaseData = common.Template{ var validTemplateTestCaseData = common.Template{
Name: "TestTemplate", Name: "TestTemplate",
Content: string(validContentTestCaseData), Content: string(validContentTestCaseData),
...@@ -232,7 +217,6 @@ type ExpanderTestCase struct { ...@@ -232,7 +217,6 @@ type ExpanderTestCase struct {
Description string Description string
Error string Error string
Handler func(w http.ResponseWriter, r *http.Request) Handler func(w http.ResponseWriter, r *http.Request)
Resolver TypeResolver
ValidResponse *ExpandedTemplate ValidResponse *ExpandedTemplate
} }
...@@ -247,33 +231,21 @@ func TestExpandTemplate(t *testing.T) { ...@@ -247,33 +231,21 @@ func TestExpandTemplate(t *testing.T) {
"expect success for ExpandTemplate", "expect success for ExpandTemplate",
"", "",
expanderSuccessHandler, expanderSuccessHandler,
&mockResolver{},
getValidResponse(t, "expect success for ExpandTemplate"), getValidResponse(t, "expect success for ExpandTemplate"),
}, },
{ {
"expect error for ExpandTemplate", "expect error for ExpandTemplate",
"cannot expand template", "cannot expand template",
expanderErrorHandler, expanderErrorHandler,
&mockResolver{},
nil, nil,
}, },
{
"expect success for ExpandTemplate with two expansions",
"",
roundTripHandler,
&mockResolver{[][]*common.ImportFile{
{},
{&common.ImportFile{Name: "test.py"}},
}, t},
roundTripResponse,
},
} }
for _, etc := range tests { for _, etc := range tests {
ts := httptest.NewServer(http.HandlerFunc(etc.Handler)) ts := httptest.NewServer(http.HandlerFunc(etc.Handler))
defer ts.Close() defer ts.Close()
expander := NewExpander(ts.URL, etc.Resolver) expander := NewExpander(ts.URL)
actualResponse, err := expander.ExpandTemplate(&validTemplateTestCaseData) actualResponse, err := expander.ExpandTemplate(&validTemplateTestCaseData)
if err != nil { if err != nil {
message := err.Error() message := err.Error()
......
...@@ -19,15 +19,13 @@ package manager ...@@ -19,15 +19,13 @@ package manager
import ( import (
"fmt" "fmt"
"log" "log"
"net/url"
"regexp" "regexp"
"strings"
"time" "time"
"github.com/kubernetes/helm/cmd/manager/repository" "github.com/kubernetes/helm/cmd/manager/repository"
"github.com/kubernetes/helm/pkg/chart"
"github.com/kubernetes/helm/pkg/common" "github.com/kubernetes/helm/pkg/common"
"github.com/kubernetes/helm/pkg/registry" "github.com/kubernetes/helm/pkg/repo"
"github.com/kubernetes/helm/pkg/util"
) )
// Manager manages a persistent set of Deployments. // Manager manages a persistent set of Deployments.
...@@ -44,26 +42,20 @@ type Manager interface { ...@@ -44,26 +42,20 @@ type Manager interface {
GetManifest(deploymentName string, manifest string) (*common.Manifest, error) GetManifest(deploymentName string, manifest string) (*common.Manifest, error)
Expand(t *common.Template) (*common.Manifest, error) Expand(t *common.Template) (*common.Manifest, error)
// Types // Charts
ListTypes() ([]string, error) ListCharts() ([]string, error)
ListInstances(typeName string) ([]*common.TypeInstance, error) ListChartInstances(chartName string) ([]*common.ChartInstance, error)
GetRegistryForType(typeName string) (string, error) GetRepoForChart(chartName string) (string, error)
GetMetadataForType(typeName string) (string, error) GetMetadataForChart(chartName string) (*chart.Chartfile, error)
GetChart(chartName string) (*chart.Chart, error)
// Registries // Repo Charts
ListRegistries() ([]*common.Registry, error) ListRepoCharts(repoName string, regex *regexp.Regexp) ([]string, error)
CreateRegistry(pr *common.Registry) error GetChartForRepo(repoName, chartName string) (*chart.Chart, error)
GetRegistry(name string) (*common.Registry, error)
DeleteRegistry(name string) error
// Registry Types
ListRegistryTypes(registryName string, regex *regexp.Regexp) ([]registry.Type, error)
GetDownloadURLs(registryName string, t registry.Type) ([]*url.URL, error)
GetFile(registryName string, url string) (string, error)
// Credentials // Credentials
CreateCredential(name string, c *common.RegistryCredential) error CreateCredential(name string, c *repo.Credential) error
GetCredential(name string) (*common.RegistryCredential, error) GetCredential(name string) (*repo.Credential, error)
// Chart Repositories // Chart Repositories
ListChartRepos() ([]string, error) ListChartRepos() ([]string, error)
...@@ -72,24 +64,23 @@ type Manager interface { ...@@ -72,24 +64,23 @@ type Manager interface {
} }
type manager struct { type manager struct {
expander Expander expander Expander
deployer Deployer deployer Deployer
repository repository.Repository repository repository.Repository
registryProvider registry.RegistryProvider repoProvider repo.IRepoProvider
service common.RegistryService service repo.IRepoService
//TODO: add chart repo service //TODO: add chart repo service
credentialProvider common.CredentialProvider credentialProvider repo.ICredentialProvider
} }
// NewManager returns a new initialized Manager. // NewManager returns a new initialized Manager.
func NewManager(expander Expander, func NewManager(expander Expander,
deployer Deployer, deployer Deployer,
repository repository.Repository, repository repository.Repository,
registryProvider registry.RegistryProvider, repoProvider repo.IRepoProvider,
service common.RegistryService, service repo.IRepoService,
//TODO: add chart repo service credentialProvider repo.ICredentialProvider) Manager {
credentialProvider common.CredentialProvider) Manager { return &manager{expander, deployer, repository, repoProvider, service, credentialProvider}
return &manager{expander, deployer, repository, registryProvider, service, credentialProvider}
} }
// ListDeployments returns the list of deployments // ListDeployments returns the list of deployments
...@@ -190,7 +181,7 @@ func (m *manager) CreateDeployment(t *common.Template) (*common.Deployment, erro ...@@ -190,7 +181,7 @@ func (m *manager) CreateDeployment(t *common.Template) (*common.Deployment, erro
} }
// Finally update the type instances for this deployment. // Finally update the type instances for this deployment.
m.setTypeInstances(t.Name, manifest.Name, manifest.Layout) m.setChartInstances(t.Name, manifest.Name, manifest.Layout)
return m.repository.GetValidDeployment(t.Name) return m.repository.GetValidDeployment(t.Name)
} }
...@@ -210,20 +201,20 @@ func (m *manager) createManifest(t *common.Template) (*common.Manifest, error) { ...@@ -210,20 +201,20 @@ func (m *manager) createManifest(t *common.Template) (*common.Manifest, error) {
}, nil }, nil
} }
func (m *manager) setTypeInstances(deploymentName string, manifestName string, layout *common.Layout) { func (m *manager) setChartInstances(deploymentName string, manifestName string, layout *common.Layout) {
m.repository.ClearTypeInstancesForDeployment(deploymentName) m.repository.ClearChartInstancesForDeployment(deploymentName)
instances := make(map[string][]*common.TypeInstance) instances := make(map[string][]*common.ChartInstance)
for i, r := range layout.Resources { for i, r := range layout.Resources {
addTypeInstances(&instances, r, deploymentName, manifestName, fmt.Sprintf("$.resources[%d]", i)) addChartInstances(&instances, r, deploymentName, manifestName, fmt.Sprintf("$.resources[%d]", i))
} }
m.repository.AddTypeInstances(instances) m.repository.AddChartInstances(instances)
} }
func addTypeInstances(instances *map[string][]*common.TypeInstance, r *common.LayoutResource, deploymentName string, manifestName string, jsonPath string) { func addChartInstances(instances *map[string][]*common.ChartInstance, r *common.LayoutResource, deploymentName string, manifestName string, jsonPath string) {
// Add this resource. // Add this resource.
inst := &common.TypeInstance{ inst := &common.ChartInstance{
Name: r.Name, Name: r.Name,
Type: r.Type, Type: r.Type,
Deployment: deploymentName, Deployment: deploymentName,
...@@ -235,7 +226,7 @@ func addTypeInstances(instances *map[string][]*common.TypeInstance, r *common.La ...@@ -235,7 +226,7 @@ func addTypeInstances(instances *map[string][]*common.TypeInstance, r *common.La
// Add all sub resources if they exist. // Add all sub resources if they exist.
for i, sr := range r.Resources { for i, sr := range r.Resources {
addTypeInstances(instances, sr, deploymentName, manifestName, fmt.Sprintf("%s.resources[%d]", jsonPath, i)) addChartInstances(instances, sr, deploymentName, manifestName, fmt.Sprintf("%s.resources[%d]", jsonPath, i))
} }
} }
...@@ -286,7 +277,7 @@ func (m *manager) DeleteDeployment(name string, forget bool) (*common.Deployment ...@@ -286,7 +277,7 @@ func (m *manager) DeleteDeployment(name string, forget bool) (*common.Deployment
} }
// Finally remove the type instances for this deployment. // Finally remove the type instances for this deployment.
m.repository.ClearTypeInstancesForDeployment(name) m.repository.ClearChartInstancesForDeployment(name)
return d, nil return d, nil
} }
...@@ -319,7 +310,7 @@ func (m *manager) PutDeployment(name string, t *common.Template) (*common.Deploy ...@@ -319,7 +310,7 @@ func (m *manager) PutDeployment(name string, t *common.Template) (*common.Deploy
} }
// Finally update the type instances for this deployment. // Finally update the type instances for this deployment.
m.setTypeInstances(t.Name, manifest.Name, manifest.Layout) m.setChartInstances(t.Name, manifest.Name, manifest.Layout)
return m.repository.GetValidDeployment(t.Name) return m.repository.GetValidDeployment(t.Name)
} }
...@@ -336,59 +327,47 @@ func (m *manager) Expand(t *common.Template) (*common.Manifest, error) { ...@@ -336,59 +327,47 @@ func (m *manager) Expand(t *common.Template) (*common.Manifest, error) {
}, nil }, nil
} }
func (m *manager) ListTypes() ([]string, error) { func (m *manager) ListCharts() ([]string, error) {
return m.repository.ListTypes() return m.repository.ListCharts()
} }
func (m *manager) ListInstances(typeName string) ([]*common.TypeInstance, error) { func (m *manager) ListChartInstances(chartName string) ([]*common.ChartInstance, error) {
return m.repository.GetTypeInstances(typeName) return m.repository.GetChartInstances(chartName)
} }
// GetRegistryForType returns the registry where a type resides. // GetRepoForChart returns the repository where a chart resides.
func (m *manager) GetRegistryForType(typeName string) (string, error) { func (m *manager) GetRepoForChart(chartName string) (string, error) {
_, r, err := registry.GetDownloadURLs(m.registryProvider, typeName) _, r, err := m.repoProvider.GetChartByReference(chartName)
if err != nil { if err != nil {
return "", err return "", err
} }
return r.GetRegistryName(), nil return r.GetName(), nil
} }
// GetMetadataForType returns the metadata for type. // GetMetadataForChart returns the metadata for a chart.
func (m *manager) GetMetadataForType(typeName string) (string, error) { func (m *manager) GetMetadataForChart(chartName string) (*chart.Chartfile, error) {
URLs, r, err := registry.GetDownloadURLs(m.registryProvider, typeName) c, _, err := m.repoProvider.GetChartByReference(chartName)
if err != nil { if err != nil {
return "", err return nil, err
}
if len(URLs) < 1 {
return "", nil
} }
// If it's a chart, we want the provenance file return c.Chartfile(), nil
fPath := URLs[0] }
if !strings.Contains(fPath, ".prov") {
// It's not a chart, so we want the schema
fPath += ".schema"
}
metadata, err := getFileFromRegistry(fPath, r) // GetChart returns a chart.
func (m *manager) GetChart(chartName string) (*chart.Chart, error) {
c, _, err := m.repoProvider.GetChartByReference(chartName)
if err != nil { if err != nil {
return "", fmt.Errorf("cannot get metadata for type (%s): %s", typeName, err) return nil, err
} }
return metadata, nil return c, nil
}
// ListRegistries returns the list of registries
func (m *manager) ListRegistries() ([]*common.Registry, error) {
return m.service.List()
} }
// ListChartRepos returns the list of chart repositories // ListChartRepos returns the list of chart repositories
func (m *manager) ListChartRepos() ([]string, error) { func (m *manager) ListChartRepos() ([]string, error) {
//TODO: implement return m.service.List()
return nil, nil
} }
// AddChartRepo adds a chart repository to list of available chart repositories // AddChartRepo adds a chart repository to list of available chart repositories
...@@ -399,22 +378,17 @@ func (m *manager) AddChartRepo(name string) error { ...@@ -399,22 +378,17 @@ func (m *manager) AddChartRepo(name string) error {
// RemoveChartRepo removes a chart repository to list of available chart repositories // RemoveChartRepo removes a chart repository to list of available chart repositories
func (m *manager) RemoveChartRepo(name string) error { func (m *manager) RemoveChartRepo(name string) error {
//TODO: implement return m.service.Delete(name)
return nil
} }
func (m *manager) CreateRegistry(pr *common.Registry) error { func (m *manager) CreateRepo(pr repo.IRepo) error {
return m.service.Create(pr) return m.service.Create(pr)
} }
func (m *manager) GetRegistry(name string) (*common.Registry, error) { func (m *manager) GetRepo(name string) (repo.IRepo, error) {
return m.service.Get(name) return m.service.Get(name)
} }
func (m *manager) DeleteRegistry(name string) error {
return m.service.Delete(name)
}
func generateManifestName() string { func generateManifestName() string {
return fmt.Sprintf("manifest-%d", time.Now().UTC().UnixNano()) return fmt.Sprintf("manifest-%d", time.Now().UTC().UnixNano())
} }
...@@ -437,54 +411,33 @@ func getResourceErrors(c *common.Configuration) []string { ...@@ -437,54 +411,33 @@ func getResourceErrors(c *common.Configuration) []string {
return errs return errs
} }
// ListRegistryTypes lists types in a given registry whose string values // ListRepoCharts lists charts in a given repository whose names
// conform to the supplied regular expression, or all types, if the regular // conform to the supplied regular expression, or all charts, if the regular
// expression is nil. // expression is nil.
func (m *manager) ListRegistryTypes(registryName string, regex *regexp.Regexp) ([]registry.Type, error) { func (m *manager) ListRepoCharts(repoName string, regex *regexp.Regexp) ([]string, error) {
r, err := m.registryProvider.GetRegistryByName(registryName) r, err := m.repoProvider.GetRepoByName(repoName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return r.ListTypes(regex) return r.ListCharts(regex)
} }
// GetDownloadURLs returns the URLs required to download the contents // GetChartForRepo returns a chart from a given repository.
// of a given type in a given registry. func (m *manager) GetChartForRepo(repoName, chartName string) (*chart.Chart, error) {
func (m *manager) GetDownloadURLs(registryName string, t registry.Type) ([]*url.URL, error) { r, err := m.repoProvider.GetRepoByName(repoName)
r, err := m.registryProvider.GetRegistryByName(registryName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return r.GetDownloadURLs(t) return r.GetChart(chartName)
}
// GetFile returns a file from the backing registry
func (m *manager) GetFile(registryName string, url string) (string, error) {
r, err := m.registryProvider.GetRegistryByName(registryName)
if err != nil {
return "", err
}
return getFileFromRegistry(url, r)
}
func getFileFromRegistry(url string, r registry.Registry) (string, error) {
getter := util.NewHTTPClient(3, r, util.NewSleeper())
body, _, err := getter.Get(url)
if err != nil {
return "", err
}
return body, nil
} }
// CreateCredential creates a credential that can be used to authenticate to registry // CreateCredential creates a credential that can be used to authenticate to repository
func (m *manager) CreateCredential(name string, c *common.RegistryCredential) error { func (m *manager) CreateCredential(name string, c *repo.Credential) error {
return m.credentialProvider.SetCredential(name, c) return m.credentialProvider.SetCredential(name, c)
} }
func (m *manager) GetCredential(name string) (*common.RegistryCredential, error) { func (m *manager) GetCredential(name string) (*repo.Credential, error) {
return m.credentialProvider.GetCredential(name) return m.credentialProvider.GetCredential(name)
} }
...@@ -17,13 +17,13 @@ limitations under the License. ...@@ -17,13 +17,13 @@ limitations under the License.
package manager package manager
import ( import (
"github.com/kubernetes/helm/pkg/common"
"github.com/kubernetes/helm/pkg/repo"
"errors" "errors"
"reflect" "reflect"
"strings" "strings"
"testing" "testing"
"github.com/kubernetes/helm/pkg/common"
"github.com/kubernetes/helm/pkg/registry"
) )
var template = common.Template{Name: "test", Content: "test"} var template = common.Template{Name: "test", Content: "test"}
...@@ -128,17 +128,17 @@ func (deployer *deployerStub) PutConfiguration(configuration *common.Configurati ...@@ -128,17 +128,17 @@ func (deployer *deployerStub) PutConfiguration(configuration *common.Configurati
} }
type repositoryStub struct { type repositoryStub struct {
FailListDeployments bool FailListDeployments bool
Created []string Created []string
ManifestAdd map[string]*common.Manifest ManifestAdd map[string]*common.Manifest
ManifestSet map[string]*common.Manifest ManifestSet map[string]*common.Manifest
Deleted []string Deleted []string
GetValid []string GetValid []string
TypeInstances map[string][]string ChartInstances map[string][]string
TypeInstancesCleared bool ChartInstancesCleared bool
GetTypeInstancesCalled bool GetChartInstancesCalled bool
ListTypesCalled bool ListTypesCalled bool
DeploymentStates []*common.DeploymentState DeploymentStates []*common.DeploymentState
} }
func (repository *repositoryStub) reset() { func (repository *repositoryStub) reset() {
...@@ -148,9 +148,9 @@ func (repository *repositoryStub) reset() { ...@@ -148,9 +148,9 @@ func (repository *repositoryStub) reset() {
repository.ManifestSet = make(map[string]*common.Manifest) repository.ManifestSet = make(map[string]*common.Manifest)
repository.Deleted = make([]string, 0) repository.Deleted = make([]string, 0)
repository.GetValid = make([]string, 0) repository.GetValid = make([]string, 0)
repository.TypeInstances = make(map[string][]string) repository.ChartInstances = make(map[string][]string)
repository.TypeInstancesCleared = false repository.ChartInstancesCleared = false
repository.GetTypeInstancesCalled = false repository.GetChartInstancesCalled = false
repository.ListTypesCalled = false repository.ListTypesCalled = false
repository.DeploymentStates = []*common.DeploymentState{} repository.DeploymentStates = []*common.DeploymentState{}
} }
...@@ -233,26 +233,26 @@ func (repository *repositoryStub) GetLatestManifest(d string) (*common.Manifest, ...@@ -233,26 +233,26 @@ func (repository *repositoryStub) GetLatestManifest(d string) (*common.Manifest,
} }
// Types. // Types.
func (repository *repositoryStub) ListTypes() ([]string, error) { func (repository *repositoryStub) ListCharts() ([]string, error) {
repository.ListTypesCalled = true repository.ListTypesCalled = true
return []string{}, nil return []string{}, nil
} }
func (repository *repositoryStub) GetTypeInstances(t string) ([]*common.TypeInstance, error) { func (repository *repositoryStub) GetChartInstances(t string) ([]*common.ChartInstance, error) {
repository.GetTypeInstancesCalled = true repository.GetChartInstancesCalled = true
return []*common.TypeInstance{}, nil return []*common.ChartInstance{}, nil
} }
func (repository *repositoryStub) ClearTypeInstancesForDeployment(d string) error { func (repository *repositoryStub) ClearChartInstancesForDeployment(d string) error {
repository.TypeInstancesCleared = true repository.ChartInstancesCleared = true
return nil return nil
} }
func (repository *repositoryStub) AddTypeInstances(is map[string][]*common.TypeInstance) error { func (repository *repositoryStub) AddChartInstances(is map[string][]*common.ChartInstance) error {
for t, instances := range is { for t, instances := range is {
for _, instance := range instances { for _, instance := range instances {
d := instance.Deployment d := instance.Deployment
repository.TypeInstances[d] = append(repository.TypeInstances[d], t) repository.ChartInstances[d] = append(repository.ChartInstances[d], t)
} }
} }
...@@ -264,10 +264,10 @@ func (repository *repositoryStub) Close() {} ...@@ -264,10 +264,10 @@ func (repository *repositoryStub) Close() {}
var testExpander = &expanderStub{} var testExpander = &expanderStub{}
var testRepository = newRepositoryStub() var testRepository = newRepositoryStub()
var testDeployer = newDeployerStub() var testDeployer = newDeployerStub()
var testRegistryService = registry.NewInmemRegistryService() var testRepoService = repo.NewInmemRepoService()
var testCredentialProvider = registry.NewInmemCredentialProvider() var testCredentialProvider = repo.NewInmemCredentialProvider()
var testProvider = registry.NewRegistryProvider(nil, registry.NewTestGithubRegistryProvider("", nil), registry.NewTestGCSRegistryProvider("", nil), testCredentialProvider) var testProvider = repo.NewRepoProvider(nil, repo.NewGCSRepoProvider(testCredentialProvider), testCredentialProvider)
var testManager = NewManager(testExpander, testDeployer, testRepository, testProvider, testRegistryService, testCredentialProvider) var testManager = NewManager(testExpander, testDeployer, testRepository, testProvider, testRepoService, testCredentialProvider)
func TestListDeployments(t *testing.T) { func TestListDeployments(t *testing.T) {
testRepository.reset() testRepository.reset()
...@@ -363,12 +363,12 @@ func TestCreateDeployment(t *testing.T) { ...@@ -363,12 +363,12 @@ func TestCreateDeployment(t *testing.T) {
t.Fatal("CreateDeployment success did not mark deployment as deployed") t.Fatal("CreateDeployment success did not mark deployment as deployed")
} }
if !testRepository.TypeInstancesCleared { if !testRepository.ChartInstancesCleared {
t.Fatal("Repository did not clear type instances during creation") t.Fatal("Repository did not clear type instances during creation")
} }
if !reflect.DeepEqual(testRepository.TypeInstances, typeInstMap) { if !reflect.DeepEqual(testRepository.ChartInstances, typeInstMap) {
t.Fatalf("Unexpected type instances after CreateDeployment: %s", testRepository.TypeInstances) t.Fatalf("Unexpected type instances after CreateDeployment: %s", testRepository.ChartInstances)
} }
} }
...@@ -397,7 +397,7 @@ func TestCreateDeploymentCreationFailure(t *testing.T) { ...@@ -397,7 +397,7 @@ func TestCreateDeploymentCreationFailure(t *testing.T) {
"Received: %v, %s. Expected: %s, %s.", d, err, "nil", errTest) "Received: %v, %s. Expected: %s, %s.", d, err, "nil", errTest)
} }
if testRepository.TypeInstancesCleared { if testRepository.ChartInstancesCleared {
t.Fatal("Unexpected change to type instances during CreateDeployment failure.") t.Fatal("Unexpected change to type instances during CreateDeployment failure.")
} }
} }
...@@ -437,7 +437,7 @@ func TestCreateDeploymentCreationResourceFailure(t *testing.T) { ...@@ -437,7 +437,7 @@ func TestCreateDeploymentCreationResourceFailure(t *testing.T) {
"Received: %v, %v. Expected: %v, %v.", d, err, &deployment, "nil") "Received: %v, %v. Expected: %v, %v.", d, err, &deployment, "nil")
} }
if !testRepository.TypeInstancesCleared { if !testRepository.ChartInstancesCleared {
t.Fatal("Repository did not clear type instances during creation") t.Fatal("Repository did not clear type instances during creation")
} }
} }
...@@ -486,7 +486,7 @@ func TestDeleteDeploymentForget(t *testing.T) { ...@@ -486,7 +486,7 @@ func TestDeleteDeploymentForget(t *testing.T) {
} }
} }
if !testRepository.TypeInstancesCleared { if !testRepository.ChartInstancesCleared {
t.Fatal("Expected type instances to be cleared during DeleteDeployment.") t.Fatal("Expected type instances to be cleared during DeleteDeployment.")
} }
} }
...@@ -521,29 +521,29 @@ func TestExpand(t *testing.T) { ...@@ -521,29 +521,29 @@ func TestExpand(t *testing.T) {
func TestListTypes(t *testing.T) { func TestListTypes(t *testing.T) {
testRepository.reset() testRepository.reset()
testManager.ListTypes() testManager.ListCharts()
if !testRepository.ListTypesCalled { if !testRepository.ListTypesCalled {
t.Fatal("expected repository ListTypes() call.") t.Fatal("expected repository ListCharts() call.")
} }
} }
func TestListInstances(t *testing.T) { func TestListInstances(t *testing.T) {
testRepository.reset() testRepository.reset()
testManager.ListInstances("all") testManager.ListChartInstances("all")
if !testRepository.GetTypeInstancesCalled { if !testRepository.GetChartInstancesCalled {
t.Fatal("expected repository GetTypeInstances() call.") t.Fatal("expected repository GetChartInstances() call.")
} }
} }
// TODO(jackgr): Implement TestListRegistryTypes // TODO(jackgr): Implement TestListRepoCharts
func TestListRegistryTypes(t *testing.T) { func TestListRepoCharts(t *testing.T) {
/* /*
types, err := testManager.ListRegistryTypes("", nil) types, err := testManager.ListRepoCharts("", nil)
if err != nil { if err != nil {
t.Fatalf("cannot list registry types: %s", err) t.Fatalf("cannot list repository types: %s", err)
} }
*/ */
} }
...@@ -551,7 +551,7 @@ func TestListRegistryTypes(t *testing.T) { ...@@ -551,7 +551,7 @@ func TestListRegistryTypes(t *testing.T) {
// TODO(jackgr): Implement TestGetDownloadURLs // TODO(jackgr): Implement TestGetDownloadURLs
func TestGetDownloadURLs(t *testing.T) { func TestGetDownloadURLs(t *testing.T) {
/* /*
urls, err := testManager.GetDownloadURLs("", registry.Type{}) urls, err := testManager.GetDownloadURLs("", repo.Type{})
if err != nil { if err != nil {
t.Fatalf("cannot list get download urls: %s", err) t.Fatalf("cannot list get download urls: %s", err)
} }
......
/*
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 manager
import (
"fmt"
"net/http"
"github.com/kubernetes/helm/pkg/common"
"github.com/kubernetes/helm/pkg/registry"
"github.com/kubernetes/helm/pkg/util"
"github.com/ghodss/yaml"
)
const (
maxURLImports = 100
schemaSuffix = ".schema"
)
// TypeResolver finds Types in a Configuration which aren't yet reduceable to an import file
// or primitive, and attempts to replace them with a template from a URL.
type TypeResolver interface {
ResolveTypes(config *common.Configuration, imports []*common.ImportFile) ([]*common.ImportFile, error)
}
type typeResolver struct {
maxUrls int
rp registry.RegistryProvider
c util.HTTPClient
}
type fetchableURL struct {
reg registry.Registry
url string
}
type fetchUnit struct {
urls []fetchableURL
}
// NewTypeResolver returns a new initialized TypeResolver.
func NewTypeResolver(rp registry.RegistryProvider, c util.HTTPClient) TypeResolver {
return &typeResolver{maxUrls: maxURLImports, rp: rp, c: c}
}
func resolverError(c *common.Configuration, err error) error {
return fmt.Errorf("cannot resolve types in configuration %s due to: \n%s\n",
c, err)
}
func (tr *typeResolver) performHTTPGet(d util.HTTPDoer, u string, allowMissing bool) (content string, err error) {
g := tr.c
if d != nil {
g = util.NewHTTPClient(3, d, util.NewSleeper())
}
r, code, err := g.Get(u)
if err != nil {
return "", err
}
if allowMissing && code == http.StatusNotFound {
return "", nil
}
if code != http.StatusOK {
return "", fmt.Errorf(
"Received status code %d attempting to fetch Type at %s", code, u)
}
return r, nil
}
// ResolveTypes resolves the types in the supplied configuration and returns
// resolved type definitions in t.ImportFiles. Types can be either
// primitive (i.e., built in), resolved (i.e., already t.ImportFiles), or remote
// (i.e., described by a URL that must be fetched to resolve the type).
func (tr *typeResolver) ResolveTypes(config *common.Configuration, imports []*common.ImportFile) ([]*common.ImportFile, error) {
existing := map[string]bool{}
for _, v := range imports {
existing[v.Name] = true
}
fetched := map[string][]*common.ImportFile{}
// TODO(vaikas): Need to account for multiple URLs being fetched for a given type.
toFetch := make([]*fetchUnit, 0, tr.maxUrls)
for _, r := range config.Resources {
// Map the type to a fetchable URL (if applicable) or skip it if it's a non-fetchable type (primitive for example).
urls, urlRegistry, err := registry.GetDownloadURLs(tr.rp, r.Type)
if err != nil {
return nil, resolverError(config, fmt.Errorf("Failed to understand download url for %s: %v", r.Type, err))
}
if !existing[r.Type] {
f := &fetchUnit{}
for _, u := range urls {
if len(u) > 0 {
f.urls = append(f.urls, fetchableURL{urlRegistry, u})
// Add to existing map so it is not fetched multiple times.
existing[r.Type] = true
}
}
if len(f.urls) > 0 {
toFetch = append(toFetch, f)
fetched[f.urls[0].url] = append(fetched[f.urls[0].url], &common.ImportFile{Name: r.Type, Path: f.urls[0].url})
}
}
}
count := 0
for len(toFetch) > 0 {
// 1. If short github URL, resolve to a download URL
// 2. Fetch import URL. Exit if no URLs left
// 3. Check/handle HTTP status
// 4. Store results in all ImportFiles from that URL
// 5. Check for the optional schema file at import URL + .schema
// 6. Repeat 2,3 for schema file
// 7. Add each schema import to fetch if not already done
// 8. Mark URL done. Return to 1.
if count >= tr.maxUrls {
return nil, resolverError(config,
fmt.Errorf("Number of imports exceeds maximum of %d", tr.maxUrls))
}
templates := []string{}
url := toFetch[0].urls[0]
for _, u := range toFetch[0].urls {
template, err := tr.performHTTPGet(u.reg, u.url, false)
if err != nil {
return nil, resolverError(config, err)
}
templates = append(templates, template)
}
for _, i := range fetched[url.url] {
template, err := parseContent(templates)
if err != nil {
return nil, resolverError(config, err)
}
i.Content = template
}
schemaURL := url.url + schemaSuffix
sch, err := tr.performHTTPGet(url.reg, schemaURL, true)
if err != nil {
return nil, resolverError(config, err)
}
if sch != "" {
var s common.Schema
if err := yaml.Unmarshal([]byte(sch), &s); err != nil {
return nil, resolverError(config, err)
}
// Here we handle any nested imports in the schema we've just fetched.
for _, v := range s.Imports {
i := &common.ImportFile{Name: v.Name}
var existingSchema string
urls, urlRegistry, conversionErr := registry.GetDownloadURLs(tr.rp, v.Path)
if conversionErr != nil {
return nil, resolverError(config, fmt.Errorf("Failed to understand download url for %s: %v", v.Path, conversionErr))
}
if len(urls) == 0 {
// If it's not a fetchable URL, we need to use the type name as is, since it is a short name
// for a schema.
urls = []string{v.Path}
}
for _, u := range urls {
if len(fetched[u]) == 0 {
// If this import URL is new to us, add it to the URLs to fetch.
toFetch = append(toFetch, &fetchUnit{[]fetchableURL{{urlRegistry, u}}})
} else {
// If this is not a new import URL and we've already fetched its contents,
// reuse them. Also, check if we also found a schema for that import URL and
// record those contents for re-use as well.
if fetched[u][0].Content != "" {
i.Content = fetched[u][0].Content
if len(fetched[u+schemaSuffix]) > 0 {
existingSchema = fetched[u+schemaSuffix][0].Content
}
}
}
fetched[u] = append(fetched[u], i)
if existingSchema != "" {
fetched[u+schemaSuffix] = append(fetched[u+schemaSuffix],
&common.ImportFile{Name: v.Name + schemaSuffix, Content: existingSchema})
}
}
}
// Add the schema we've fetched as the schema for any templates which used this URL.
for _, i := range fetched[url.url] {
schemaImportName := i.Name + schemaSuffix
fetched[schemaURL] = append(fetched[schemaURL],
&common.ImportFile{Name: schemaImportName, Content: sch})
}
}
count = count + 1
toFetch = toFetch[1:]
}
ret := []*common.ImportFile{}
for _, v := range fetched {
ret = append(ret, v...)
}
return ret, nil
}
func parseContent(templates []string) (string, error) {
if len(templates) == 1 {
return templates[0], nil
}
// If there are multiple URLs that need to be fetched, that implies it's a package
// of raw Kubernetes objects. We need to fetch them all as a unit and create a
// template representing a package out of that below.
fakeConfig := &common.Configuration{}
for _, template := range templates {
o, err := util.ParseKubernetesObject([]byte(template))
if err != nil {
return "", fmt.Errorf("not a kubernetes object: %+v", template)
}
// Looks like a native Kubernetes object, create a configuration out of it
fakeConfig.Resources = append(fakeConfig.Resources, o)
}
marshalled, err := yaml.Marshal(fakeConfig)
if err != nil {
return "", fmt.Errorf("Failed to marshal: %+v", fakeConfig)
}
return string(marshalled), nil
}
/*
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 manager
import (
"errors"
"net/http"
"reflect"
"strings"
"testing"
"github.com/ghodss/yaml"
"github.com/kubernetes/helm/pkg/common"
"github.com/kubernetes/helm/pkg/registry"
)
type responseAndError struct {
err error
code int
resp string
}
type resolverTestCase struct {
config string
imports []*common.ImportFile
responses map[string]responseAndError
urlcount int
expectedErr error
importOut []*common.ImportFile
registryProvider registry.RegistryProvider
}
type testGetter struct {
responses map[string]responseAndError
count int
test *testing.T
}
var count = 0
func (tg testGetter) Get(url string) (body string, code int, err error) {
count = count + 1
ret := tg.responses[url]
return ret.resp, ret.code, ret.err
}
func testDriver(c resolverTestCase, t *testing.T) {
g := &testGetter{test: t, responses: c.responses}
count = 0
r := &typeResolver{
maxUrls: 5,
rp: c.registryProvider,
c: g,
}
conf := &common.Configuration{}
dataErr := yaml.Unmarshal([]byte(c.config), conf)
if dataErr != nil {
panic("bad test data")
}
result, err := r.ResolveTypes(conf, c.imports)
if count != c.urlcount {
t.Errorf("Expected %d url GETs but only %d found %#v", c.urlcount, g.count, g)
}
if (err != nil && c.expectedErr == nil) || (err == nil && c.expectedErr != nil) {
t.Errorf("Expected error %s but found %s", c.expectedErr, err)
} else if err != nil && !strings.Contains(err.Error(), c.expectedErr.Error()) {
t.Errorf("Expected error %s but found %s", c.expectedErr, err)
}
resultImport := map[common.ImportFile]bool{}
expectedImport := map[common.ImportFile]bool{}
for _, i := range result {
resultImport[*i] = true
}
for _, i := range c.importOut {
expectedImport[*i] = true
}
if !reflect.DeepEqual(resultImport, expectedImport) {
t.Errorf("Expected imports %+v but found %+v", expectedImport, resultImport)
}
}
var simpleContent = `
resources:
- name: test
type: ReplicationController
`
func TestNoImports(t *testing.T) {
test := resolverTestCase{config: simpleContent}
testDriver(test, t)
}
var includeImport = `
resources:
- name: foo
type: foo.py
`
func TestIncludedImport(t *testing.T) {
imports := []*common.ImportFile{{Name: "foo.py"}}
test := resolverTestCase{
config: includeImport,
imports: imports,
}
testDriver(test, t)
}
var templateSingleURL = `
resources:
- name: foo
type: http://my-fake-url
`
func TestSingleUrl(t *testing.T) {
finalImports := []*common.ImportFile{{Name: "http://my-fake-url", Path: "http://my-fake-url", Content: "my-content"}}
responses := map[string]responseAndError{
"http://my-fake-url": {nil, http.StatusOK, "my-content"},
"http://my-fake-url.schema": {nil, http.StatusNotFound, ""},
}
test := resolverTestCase{
config: templateSingleURL,
importOut: finalImports,
urlcount: 2,
responses: responses,
}
testDriver(test, t)
}
func TestSingleUrlWith500(t *testing.T) {
responses := map[string]responseAndError{
"http://my-fake-url": {nil, http.StatusInternalServerError, "my-content"},
}
test := resolverTestCase{
config: templateSingleURL,
urlcount: 1,
responses: responses,
expectedErr: errors.New("Received status code 500"),
}
testDriver(test, t)
}
var schema1 = `
imports:
- path: my-next-url
name: schema-import
`
func TestSingleUrlWithSchema(t *testing.T) {
finalImports := []*common.ImportFile{
{Name: "http://my-fake-url", Path: "http://my-fake-url", Content: "my-content"},
{Name: "schema-import", Content: "schema-import"},
{Name: "http://my-fake-url.schema", Content: schema1},
}
responses := map[string]responseAndError{
"http://my-fake-url": {nil, http.StatusOK, "my-content"},
"http://my-fake-url.schema": {nil, http.StatusOK, schema1},
"my-next-url": {nil, http.StatusOK, "schema-import"},
"my-next-url.schema": {nil, http.StatusNotFound, ""},
}
test := resolverTestCase{
config: templateSingleURL,
importOut: finalImports,
urlcount: 4,
responses: responses,
}
testDriver(test, t)
}
var templateExceedsMax = `
resources:
- name: foo
type: http://my-fake-url
- name: foo1
type: http://my-fake-url1
- name: foo2
type: http://my-fake-url2
- name: foo3
type: http://my-fake-url3
- name: foo4
type: http://my-fake-url4
- name: foo5
type: http://my-fake-url5
`
func TestTooManyImports(t *testing.T) {
responses := map[string]responseAndError{
"http://my-fake-url": {nil, http.StatusOK, "my-content"},
"http://my-fake-url.schema": {nil, http.StatusNotFound, ""},
"http://my-fake-url1": {nil, http.StatusOK, "my-content"},
"http://my-fake-url1.schema": {nil, http.StatusNotFound, ""},
"http://my-fake-url2": {nil, http.StatusOK, "my-content"},
"http://my-fake-url2.schema": {nil, http.StatusNotFound, ""},
"http://my-fake-url3": {nil, http.StatusOK, "my-content"},
"http://my-fake-url3.schema": {nil, http.StatusNotFound, ""},
"http://my-fake-url4": {nil, http.StatusOK, "my-content"},
"http://my-fake-url4.schema": {nil, http.StatusNotFound, ""},
"http://my-fake-url5": {nil, http.StatusOK, "my-content"},
"http://my-fake-url5.schema": {nil, http.StatusNotFound, ""},
}
test := resolverTestCase{
config: templateExceedsMax,
urlcount: 10,
responses: responses,
expectedErr: errors.New("Number of imports exceeds maximum of 5"),
}
testDriver(test, t)
}
var templateSharesImport = `
resources:
- name: foo
type: http://my-fake-url
- name: foo1
type: http://my-fake-url1
`
var schema2 = `
imports:
- path: my-next-url
name: schema-import-1
`
func TestSharedImport(t *testing.T) {
finalImports := []*common.ImportFile{
{Name: "http://my-fake-url", Path: "http://my-fake-url", Content: "my-content"},
{Name: "http://my-fake-url1", Path: "http://my-fake-url1", Content: "my-content-1"},
{Name: "schema-import", Content: "schema-import"},
{Name: "schema-import-1", Content: "schema-import"},
{Name: "http://my-fake-url.schema", Content: schema1},
{Name: "http://my-fake-url1.schema", Content: schema2},
}
responses := map[string]responseAndError{
"http://my-fake-url": {nil, http.StatusOK, "my-content"},
"http://my-fake-url.schema": {nil, http.StatusOK, schema1},
"http://my-fake-url1": {nil, http.StatusOK, "my-content-1"},
"http://my-fake-url1.schema": {nil, http.StatusOK, schema2},
"my-next-url": {nil, http.StatusOK, "schema-import"},
"my-next-url.schema": {nil, http.StatusNotFound, ""},
}
test := resolverTestCase{
config: templateSharesImport,
urlcount: 6,
responses: responses,
importOut: finalImports,
}
testDriver(test, t)
}
var templateShortGithubTemplate = `
resources:
- name: foo
type: github.com/kubernetes/application-dm-templates/common/replicatedservice:v1
- name: foo1
type: github.com/kubernetes/application-dm-templates/common/replicatedservice:v2
`
func TestShortGithubUrl(t *testing.T) {
finalImports := []*common.ImportFile{
{
Name: "github.com/kubernetes/application-dm-templates/common/replicatedservice:v1",
Path: "https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/common/replicatedservice/v1/replicatedservice.py",
Content: "my-content"},
{
Name: "github.com/kubernetes/application-dm-templates/common/replicatedservice:v2",
Path: "https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/common/replicatedservice/v2/replicatedservice.py",
Content: "my-content-2"},
}
downloadResponses := map[string]registry.DownloadResponse{
"https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/common/replicatedservice/v1/replicatedservice.py": {Err: nil, Code: http.StatusOK, Body: "my-content"},
"https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/common/replicatedservice/v1/replicatedservice.py.schema": {Err: nil, Code: http.StatusNotFound, Body: ""},
"https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/common/replicatedservice/v2/replicatedservice.py": {Err: nil, Code: http.StatusOK, Body: "my-content-2"},
"https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/common/replicatedservice/v2/replicatedservice.py.schema": {Err: nil, Code: http.StatusNotFound, Body: ""},
}
githubURLMaps := map[registry.Type]registry.TestURLAndError{
registry.NewTypeOrDie("common", "replicatedservice", "v1"): {URL: "https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/common/replicatedservice/v1/replicatedservice.py", Err: nil},
registry.NewTypeOrDie("common", "replicatedservice", "v2"): {URL: "https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/common/replicatedservice/v2/replicatedservice.py", Err: nil},
}
gcsURLMaps := map[registry.Type]registry.TestURLAndError{
registry.NewTypeOrDie("common", "replicatedservice", "v1"): {URL: "https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/common/replicatedservice/v1/replicatedservice.py", Err: nil},
registry.NewTypeOrDie("common", "replicatedservice", "v2"): {URL: "https://raw.githubusercontent.com/kubernetes/application-dm-templates/master/common/replicatedservice/v2/replicatedservice.py", Err: nil},
}
grp := registry.NewTestGithubRegistryProviderWithDownloads("github.com/kubernetes/application-dm-templates", githubURLMaps, downloadResponses)
gcsrp := registry.NewTestGCSRegistryProvider("gs://charts", gcsURLMaps)
test := resolverTestCase{
config: templateShortGithubTemplate,
importOut: finalImports,
urlcount: 0,
responses: map[string]responseAndError{},
registryProvider: registry.NewRegistryProvider(nil, grp, gcsrp, registry.NewInmemCredentialProvider()),
}
testDriver(test, t)
}
...@@ -44,7 +44,7 @@ type pManifest struct { ...@@ -44,7 +44,7 @@ type pManifest struct {
type pInstance struct { type pInstance struct {
ID string `bson:"_id"` ID string `bson:"_id"`
common.TypeInstance common.ChartInstance
} }
type pRepository struct { type pRepository struct {
...@@ -428,8 +428,8 @@ func (r *pRepository) removeManifestsForDeployment(d *common.Deployment) error { ...@@ -428,8 +428,8 @@ func (r *pRepository) removeManifestsForDeployment(d *common.Deployment) error {
return nil return nil
} }
// ListTypes returns all types known from existing instances. // ListCharts returns all types known from existing instances.
func (r *pRepository) ListTypes() ([]string, error) { func (r *pRepository) ListCharts() ([]string, error) {
var result []string var result []string
if err := r.Instances.Find(nil).Distinct("typeinstance.type", &result); err != nil { if err := r.Instances.Find(nil).Distinct("typeinstance.type", &result); err != nil {
return nil, fmt.Errorf("cannot list type instances: %s", err) return nil, fmt.Errorf("cannot list type instances: %s", err)
...@@ -438,9 +438,9 @@ func (r *pRepository) ListTypes() ([]string, error) { ...@@ -438,9 +438,9 @@ func (r *pRepository) ListTypes() ([]string, error) {
return result, nil return result, nil
} }
// GetTypeInstances returns all instances of a given type. If typeName is empty // GetChartInstances returns all instances of a given type. If typeName is empty
// or equal to "all", returns all instances of all types. // or equal to "all", returns all instances of all types.
func (r *pRepository) GetTypeInstances(typeName string) ([]*common.TypeInstance, error) { func (r *pRepository) GetChartInstances(typeName string) ([]*common.ChartInstance, error) {
query := bson.M{"typeinstance.type": typeName} query := bson.M{"typeinstance.type": typeName}
if typeName == "" || typeName == "all" { if typeName == "" || typeName == "all" {
query = nil query = nil
...@@ -451,17 +451,17 @@ func (r *pRepository) GetTypeInstances(typeName string) ([]*common.TypeInstance, ...@@ -451,17 +451,17 @@ func (r *pRepository) GetTypeInstances(typeName string) ([]*common.TypeInstance,
return nil, fmt.Errorf("cannot get instances of type %s: %s", typeName, err) return nil, fmt.Errorf("cannot get instances of type %s: %s", typeName, err)
} }
instances := []*common.TypeInstance{} instances := []*common.ChartInstance{}
for _, pi := range result { for _, pi := range result {
instances = append(instances, &pi.TypeInstance) instances = append(instances, &pi.ChartInstance)
} }
return instances, nil return instances, nil
} }
// ClearTypeInstancesForDeployment deletes all type instances associated with the given // ClearChartInstancesForDeployment deletes all type instances associated with the given
// deployment from the repository. // deployment from the repository.
func (r *pRepository) ClearTypeInstancesForDeployment(deploymentName string) error { func (r *pRepository) ClearChartInstancesForDeployment(deploymentName string) error {
if deploymentName != "" { if deploymentName != "" {
query := bson.M{"typeinstance.deployment": deploymentName} query := bson.M{"typeinstance.deployment": deploymentName}
if _, err := r.Instances.RemoveAll(query); err != nil { if _, err := r.Instances.RemoveAll(query); err != nil {
...@@ -472,12 +472,12 @@ func (r *pRepository) ClearTypeInstancesForDeployment(deploymentName string) err ...@@ -472,12 +472,12 @@ func (r *pRepository) ClearTypeInstancesForDeployment(deploymentName string) err
return nil return nil
} }
// AddTypeInstances adds the supplied type instances to the repository. // AddChartInstances adds the supplied type instances to the repository.
func (r *pRepository) AddTypeInstances(instances map[string][]*common.TypeInstance) error { func (r *pRepository) AddChartInstances(instances map[string][]*common.ChartInstance) error {
for _, is := range instances { for _, is := range instances {
for _, i := range is { for _, i := range is {
key := fmt.Sprintf("%s.%s.%s", i.Deployment, i.Type, i.Name) key := fmt.Sprintf("%s.%s.%s", i.Deployment, i.Type, i.Name)
wrapper := pInstance{ID: key, TypeInstance: *i} wrapper := pInstance{ID: key, ChartInstance: *i}
if err := r.Instances.Insert(&wrapper); err != nil { if err := r.Instances.Insert(&wrapper); err != nil {
return fmt.Errorf("cannot insert type instance %v: %s", wrapper, err) return fmt.Errorf("cannot insert type instance %v: %s", wrapper, err)
} }
......
...@@ -102,9 +102,9 @@ func TestRepositoryDeleteDeploymentWorksForget(t *testing.T) { ...@@ -102,9 +102,9 @@ func TestRepositoryDeleteDeploymentWorksForget(t *testing.T) {
} }
} }
func TestRepositoryTypeInstances(t *testing.T) { func TestRepositoryChartInstances(t *testing.T) {
if r := createRepository(); r != nil { if r := createRepository(); r != nil {
defer resetRepository(t, r) defer resetRepository(t, r)
repository.TestRepositoryTypeInstances(t, r) repository.TestRepositoryChartInstances(t, r)
} }
} }
...@@ -40,10 +40,10 @@ type Repository interface { ...@@ -40,10 +40,10 @@ type Repository interface {
GetLatestManifest(deploymentName string) (*common.Manifest, error) GetLatestManifest(deploymentName string) (*common.Manifest, error)
// Types. // Types.
ListTypes() ([]string, error) ListCharts() ([]string, error)
GetTypeInstances(typeName string) ([]*common.TypeInstance, error) GetChartInstances(chartName string) ([]*common.ChartInstance, error)
ClearTypeInstancesForDeployment(deploymentName string) error ClearChartInstancesForDeployment(deploymentName string) error
AddTypeInstances(instances map[string][]*common.TypeInstance) error AddChartInstances(instances map[string][]*common.ChartInstance) error
Close() Close()
} }
...@@ -210,9 +210,9 @@ func TestRepositoryDeleteDeploymentWorksForget(t *testing.T, r Repository) { ...@@ -210,9 +210,9 @@ func TestRepositoryDeleteDeploymentWorksForget(t *testing.T, r Repository) {
} }
} }
// TestRepositoryTypeInstances checks that type instances can be listed and retrieved successfully. // TestRepositoryChartInstances checks that type instances can be listed and retrieved successfully.
func TestRepositoryTypeInstances(t *testing.T, r Repository) { func TestRepositoryChartInstances(t *testing.T, r Repository) {
d1Map := map[string][]*common.TypeInstance{ d1Map := map[string][]*common.ChartInstance{
"t1": { "t1": {
{ {
Name: "i1", Name: "i1",
...@@ -224,7 +224,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) { ...@@ -224,7 +224,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) {
}, },
} }
d2Map := map[string][]*common.TypeInstance{ d2Map := map[string][]*common.ChartInstance{
"t2": { "t2": {
{ {
Name: "i2", Name: "i2",
...@@ -236,7 +236,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) { ...@@ -236,7 +236,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) {
}, },
} }
d3Map := map[string][]*common.TypeInstance{ d3Map := map[string][]*common.ChartInstance{
"t2": { "t2": {
{ {
Name: "i3", Name: "i3",
...@@ -248,7 +248,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) { ...@@ -248,7 +248,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) {
}, },
} }
instances, err := r.GetTypeInstances("noinstances") instances, err := r.GetChartInstances("noinstances")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -257,7 +257,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) { ...@@ -257,7 +257,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) {
t.Fatalf("expected no instances: %v", instances) t.Fatalf("expected no instances: %v", instances)
} }
types, err := r.ListTypes() types, err := r.ListCharts()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -266,11 +266,11 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) { ...@@ -266,11 +266,11 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) {
t.Fatalf("expected no types: %v", types) t.Fatalf("expected no types: %v", types)
} }
r.AddTypeInstances(d1Map) r.AddChartInstances(d1Map)
r.AddTypeInstances(d2Map) r.AddChartInstances(d2Map)
r.AddTypeInstances(d3Map) r.AddChartInstances(d3Map)
instances, err = r.GetTypeInstances("unknowntype") instances, err = r.GetChartInstances("unknowntype")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -279,7 +279,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) { ...@@ -279,7 +279,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) {
t.Fatalf("expected no instances: %v", instances) t.Fatalf("expected no instances: %v", instances)
} }
instances, err = r.GetTypeInstances("t1") instances, err = r.GetChartInstances("t1")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -288,7 +288,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) { ...@@ -288,7 +288,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) {
t.Fatalf("expected one instance: %v", instances) t.Fatalf("expected one instance: %v", instances)
} }
instances, err = r.GetTypeInstances("t2") instances, err = r.GetChartInstances("t2")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -297,7 +297,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) { ...@@ -297,7 +297,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) {
t.Fatalf("expected two instances: %v", instances) t.Fatalf("expected two instances: %v", instances)
} }
instances, err = r.GetTypeInstances("all") instances, err = r.GetChartInstances("all")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -306,7 +306,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) { ...@@ -306,7 +306,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) {
t.Fatalf("expected three total instances: %v", instances) t.Fatalf("expected three total instances: %v", instances)
} }
types, err = r.ListTypes() types, err = r.ListCharts()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -315,12 +315,12 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) { ...@@ -315,12 +315,12 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) {
t.Fatalf("expected two total types: %v", types) t.Fatalf("expected two total types: %v", types)
} }
err = r.ClearTypeInstancesForDeployment("d1") err = r.ClearChartInstancesForDeployment("d1")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
instances, err = r.GetTypeInstances("t1") instances, err = r.GetChartInstances("t1")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -329,7 +329,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) { ...@@ -329,7 +329,7 @@ func TestRepositoryTypeInstances(t *testing.T, r Repository) {
t.Fatalf("expected no instances after clear: %v", instances) t.Fatalf("expected no instances after clear: %v", instances)
} }
types, err = r.ListTypes() types, err = r.ListCharts()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
......
...@@ -27,16 +27,16 @@ import ( ...@@ -27,16 +27,16 @@ import (
"github.com/kubernetes/helm/pkg/common" "github.com/kubernetes/helm/pkg/common"
) )
// deploymentTypeInstanceMap stores type instances mapped by deployment name. // deploymentChartInstanceMap stores type instances mapped by deployment name.
// This allows for simple updating and deleting of per-deployment instances // This allows for simple updating and deleting of per-deployment instances
// when deployments are created/updated/deleted. // when deployments are created/updated/deleted.
type deploymentTypeInstanceMap map[string][]*common.TypeInstance type deploymentChartInstanceMap map[string][]*common.ChartInstance
type tRepository struct { type tRepository struct {
sync.RWMutex sync.RWMutex
deployments map[string]common.Deployment deployments map[string]common.Deployment
manifests map[string]map[string]*common.Manifest manifests map[string]map[string]*common.Manifest
instances map[string]deploymentTypeInstanceMap instances map[string]deploymentChartInstanceMap
} }
// NewRepository returns a new transient repository. Its lifetime is coupled // NewRepository returns a new transient repository. Its lifetime is coupled
...@@ -46,14 +46,14 @@ func NewRepository() repository.Repository { ...@@ -46,14 +46,14 @@ func NewRepository() repository.Repository {
return &tRepository{ return &tRepository{
deployments: make(map[string]common.Deployment, 0), deployments: make(map[string]common.Deployment, 0),
manifests: make(map[string]map[string]*common.Manifest, 0), manifests: make(map[string]map[string]*common.Manifest, 0),
instances: make(map[string]deploymentTypeInstanceMap, 0), instances: make(map[string]deploymentChartInstanceMap, 0),
} }
} }
func (r *tRepository) Close() { func (r *tRepository) Close() {
r.deployments = make(map[string]common.Deployment, 0) r.deployments = make(map[string]common.Deployment, 0)
r.manifests = make(map[string]map[string]*common.Manifest, 0) r.manifests = make(map[string]map[string]*common.Manifest, 0)
r.instances = make(map[string]deploymentTypeInstanceMap, 0) r.instances = make(map[string]deploymentChartInstanceMap, 0)
} }
// ListDeployments returns of all of the deployments in the repository. // ListDeployments returns of all of the deployments in the repository.
...@@ -258,8 +258,8 @@ func (r *tRepository) GetLatestManifest(deploymentName string) (*common.Manifest ...@@ -258,8 +258,8 @@ func (r *tRepository) GetLatestManifest(deploymentName string) (*common.Manifest
return r.getManifestForDeployment(deploymentName, d.LatestManifest) return r.getManifestForDeployment(deploymentName, d.LatestManifest)
} }
// ListTypes returns all types known from existing instances. // ListCharts returns all types known from existing instances.
func (r *tRepository) ListTypes() ([]string, error) { func (r *tRepository) ListCharts() ([]string, error) {
var keys []string var keys []string
for k := range r.instances { for k := range r.instances {
keys = append(keys, k) keys = append(keys, k)
...@@ -268,10 +268,10 @@ func (r *tRepository) ListTypes() ([]string, error) { ...@@ -268,10 +268,10 @@ func (r *tRepository) ListTypes() ([]string, error) {
return keys, nil return keys, nil
} }
// GetTypeInstances returns all instances of a given type. If type is empty, // GetChartInstances returns all instances of a given type. If type is empty,
// returns all instances for all types. // returns all instances for all types.
func (r *tRepository) GetTypeInstances(typeName string) ([]*common.TypeInstance, error) { func (r *tRepository) GetChartInstances(typeName string) ([]*common.ChartInstance, error) {
var instances []*common.TypeInstance var instances []*common.ChartInstance
for t, dInstMap := range r.instances { for t, dInstMap := range r.instances {
if t == typeName || typeName == "" || typeName == "all" { if t == typeName || typeName == "" || typeName == "all" {
for _, i := range dInstMap { for _, i := range dInstMap {
...@@ -283,9 +283,9 @@ func (r *tRepository) GetTypeInstances(typeName string) ([]*common.TypeInstance, ...@@ -283,9 +283,9 @@ func (r *tRepository) GetTypeInstances(typeName string) ([]*common.TypeInstance,
return instances, nil return instances, nil
} }
// ClearTypeInstancesForDeployment deletes all type instances associated with the given // ClearChartInstancesForDeployment deletes all type instances associated with the given
// deployment from the repository. // deployment from the repository.
func (r *tRepository) ClearTypeInstancesForDeployment(deploymentName string) error { func (r *tRepository) ClearChartInstancesForDeployment(deploymentName string) error {
r.Lock() r.Lock()
defer r.Unlock() defer r.Unlock()
...@@ -299,22 +299,22 @@ func (r *tRepository) ClearTypeInstancesForDeployment(deploymentName string) err ...@@ -299,22 +299,22 @@ func (r *tRepository) ClearTypeInstancesForDeployment(deploymentName string) err
return nil return nil
} }
// AddTypeInstances adds the supplied type instances to the repository. // AddChartInstances adds the supplied type instances to the repository.
func (r *tRepository) AddTypeInstances(instances map[string][]*common.TypeInstance) error { func (r *tRepository) AddChartInstances(instances map[string][]*common.ChartInstance) error {
r.Lock() r.Lock()
defer r.Unlock() defer r.Unlock()
// Add instances to the appropriate type and deployment maps. // Add instances to the appropriate type and deployment maps.
for t, is := range instances { for t, is := range instances {
if r.instances[t] == nil { if r.instances[t] == nil {
r.instances[t] = make(deploymentTypeInstanceMap) r.instances[t] = make(deploymentChartInstanceMap)
} }
tmap := r.instances[t] tmap := r.instances[t]
for _, instance := range is { for _, instance := range is {
deployment := instance.Deployment deployment := instance.Deployment
if tmap[deployment] == nil { if tmap[deployment] == nil {
tmap[deployment] = make([]*common.TypeInstance, 0) tmap[deployment] = make([]*common.ChartInstance, 0)
} }
tmap[deployment] = append(tmap[deployment], instance) tmap[deployment] = append(tmap[deployment], instance)
......
...@@ -50,6 +50,6 @@ func TestRepositoryDeleteDeploymentWorksForget(t *testing.T) { ...@@ -50,6 +50,6 @@ func TestRepositoryDeleteDeploymentWorksForget(t *testing.T) {
repository.TestRepositoryDeleteDeploymentWorksForget(t, NewRepository()) repository.TestRepositoryDeleteDeploymentWorksForget(t, NewRepository())
} }
func TestRepositoryTypeInstances(t *testing.T) { func TestRepositoryChartInstances(t *testing.T) {
repository.TestRepositoryTypeInstances(t, NewRepository()) repository.TestRepositoryChartInstances(t, NewRepository())
} }
...@@ -2,8 +2,8 @@ package router ...@@ -2,8 +2,8 @@ package router
import ( import (
"github.com/kubernetes/helm/cmd/manager/manager" "github.com/kubernetes/helm/cmd/manager/manager"
"github.com/kubernetes/helm/pkg/common"
helmhttp "github.com/kubernetes/helm/pkg/httputil" helmhttp "github.com/kubernetes/helm/pkg/httputil"
"github.com/kubernetes/helm/pkg/repo"
) )
// Config holds the global configuration parameters passed into the router. // Config holds the global configuration parameters passed into the router.
...@@ -47,5 +47,5 @@ type Context struct { ...@@ -47,5 +47,5 @@ type Context struct {
// Manager is a helm/manager/manager.Manager // Manager is a helm/manager/manager.Manager
Manager manager.Manager Manager manager.Manager
Encoder helmhttp.Encoder Encoder helmhttp.Encoder
CredentialProvider common.CredentialProvider CredentialProvider repo.ICredentialProvider
} }
...@@ -2,13 +2,13 @@ package main ...@@ -2,13 +2,13 @@ package main
import ( import (
"net/http/httptest" "net/http/httptest"
"net/url"
"regexp" "regexp"
"github.com/kubernetes/helm/cmd/manager/router" "github.com/kubernetes/helm/cmd/manager/router"
"github.com/kubernetes/helm/pkg/chart"
"github.com/kubernetes/helm/pkg/common" "github.com/kubernetes/helm/pkg/common"
"github.com/kubernetes/helm/pkg/httputil" "github.com/kubernetes/helm/pkg/httputil"
"github.com/kubernetes/helm/pkg/registry" "github.com/kubernetes/helm/pkg/repo"
) )
// httpHarness is a simple test server fixture. // httpHarness is a simple test server fixture.
...@@ -26,13 +26,13 @@ func httpHarness(c *router.Context, route string, fn router.HandlerFunc) *httpte ...@@ -26,13 +26,13 @@ func httpHarness(c *router.Context, route string, fn router.HandlerFunc) *httpte
// This creates a stub context with the following properties: // This creates a stub context with the following properties:
// - Config is initialized to empty values // - Config is initialized to empty values
// - Encoder is initialized to httputil.DefaultEncoder // - Encoder is initialized to httputil.DefaultEncoder
// - CredentialProvider is initialized to registry.InmemCredentialProvider // - CredentialProvider is initialized to repo.InmemCredentialProvider
// - Manager is initialized to mockManager. // - Manager is initialized to mockManager.
func stubContext() *router.Context { func stubContext() *router.Context {
return &router.Context{ return &router.Context{
Config: &router.Config{}, Config: &router.Config{},
Manager: &mockManager{}, Manager: &mockManager{},
CredentialProvider: registry.NewInmemCredentialProvider(), CredentialProvider: repo.NewInmemCredentialProvider(),
Encoder: httputil.DefaultEncoder, Encoder: httputil.DefaultEncoder,
} }
} }
...@@ -71,20 +71,24 @@ func (m *mockManager) Expand(t *common.Template) (*common.Manifest, error) { ...@@ -71,20 +71,24 @@ func (m *mockManager) Expand(t *common.Template) (*common.Manifest, error) {
return &common.Manifest{}, nil return &common.Manifest{}, nil
} }
func (m *mockManager) ListTypes() ([]string, error) { func (m *mockManager) ListCharts() ([]string, error) {
return []string{}, nil return []string{}, nil
} }
func (m *mockManager) ListInstances(typeName string) ([]*common.TypeInstance, error) { func (m *mockManager) ListChartInstances(chartName string) ([]*common.ChartInstance, error) {
return []*common.TypeInstance{}, nil return []*common.ChartInstance{}, nil
} }
func (m *mockManager) GetRegistryForType(typeName string) (string, error) { func (m *mockManager) GetRepoForChart(chartName string) (string, error) {
return "", nil return "", nil
} }
func (m *mockManager) GetMetadataForType(typeName string) (string, error) { func (m *mockManager) GetMetadataForChart(chartName string) (*chart.Chartfile, error) {
return "", nil return nil, nil
}
func (m *mockManager) GetChart(chartName string) (*chart.Chart, error) {
return nil, nil
} }
func (m *mockManager) AddChartRepo(name string) error { func (m *mockManager) AddChartRepo(name string) error {
...@@ -99,32 +103,31 @@ func (m *mockManager) RemoveChartRepo(name string) error { ...@@ -99,32 +103,31 @@ func (m *mockManager) RemoveChartRepo(name string) error {
return nil return nil
} }
func (m *mockManager) ListRegistries() ([]*common.Registry, error) { func (m *mockManager) ListRepos() ([]*repo.Repo, error) {
return []*common.Registry{}, nil return []*repo.Repo{}, nil
} }
func (m *mockManager) CreateRegistry(pr *common.Registry) error { func (m *mockManager) CreateRepo(pr *repo.Repo) error {
return nil return nil
} }
func (m *mockManager) GetRegistry(name string) (*common.Registry, error) { func (m *mockManager) GetRepo(name string) (*repo.Repo, error) {
return &common.Registry{}, nil return &repo.Repo{}, nil
} }
func (m *mockManager) DeleteRegistry(name string) error { func (m *mockManager) DeleteRepo(name string) error {
return nil return nil
} }
func (m *mockManager) ListRegistryTypes(registryName string, regex *regexp.Regexp) ([]registry.Type, error) { func (m *mockManager) ListRepoCharts(repoName string, regex *regexp.Regexp) ([]string, error) {
return []registry.Type{}, nil return []string{}, nil
}
func (m *mockManager) GetDownloadURLs(registryName string, t registry.Type) ([]*url.URL, error) {
return []*url.URL{}, nil
} }
func (m *mockManager) GetFile(registryName string, url string) (string, error) {
return "", nil func (m *mockManager) GetChartForRepo(repoName, chartName string) (*chart.Chart, error) {
return nil, nil
} }
func (m *mockManager) CreateCredential(name string, c *common.RegistryCredential) error {
func (m *mockManager) CreateCredential(name string, c *repo.Credential) error {
return nil return nil
} }
func (m *mockManager) GetCredential(name string) (*common.RegistryCredential, error) { func (m *mockManager) GetCredential(name string) (*repo.Credential, error) {
return &common.RegistryCredential{}, nil return &repo.Credential{}, nil
} }
...@@ -170,9 +170,9 @@ type Resource struct { ...@@ -170,9 +170,9 @@ type Resource struct {
State *ResourceState `json:"state,omitempty"` State *ResourceState `json:"state,omitempty"`
} }
// TypeInstance defines the metadata for an instantiation of a template type // ChartInstance defines the metadata for an instantiation of a template type
// in a deployment. // in a deployment.
type TypeInstance struct { type ChartInstance struct {
Name string `json:"name"` // instance name Name string `json:"name"` // instance name
Type string `json:"type"` // instance type Type string `json:"type"` // instance type
Deployment string `json:"deployment"` // deployment name Deployment string `json:"deployment"` // deployment name
......
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