Commit 3fe151a4 authored by Jack Greenfield's avatar Jack Greenfield

Merge pull request #446 from jackgr/manager

Third round of refactoring for Manager
parents e65b6bee f2180cea
...@@ -24,7 +24,7 @@ import ( ...@@ -24,7 +24,7 @@ import (
"log" "log"
"os/exec" "os/exec"
"github.com/kubernetes/helm/pkg/common" "github.com/kubernetes/helm/pkg/expansion"
) )
type expander struct { type expander struct {
...@@ -32,7 +32,7 @@ type expander struct { ...@@ -32,7 +32,7 @@ type expander struct {
} }
// NewExpander returns an ExpandyBird expander. // NewExpander returns an ExpandyBird expander.
func NewExpander(binary string) common.Expander { func NewExpander(binary string) expansion.Expander {
return &expander{binary} return &expander{binary}
} }
...@@ -47,7 +47,7 @@ type expandyBirdOutput struct { ...@@ -47,7 +47,7 @@ type expandyBirdOutput struct {
// ExpandChart passes the given configuration to the expander and returns the // ExpandChart passes the given configuration to the expander and returns the
// expanded configuration as a string on success. // expanded configuration as a string on success.
func (e *expander) ExpandChart(request *common.ExpansionRequest) (*common.ExpansionResponse, error) { func (e *expander) ExpandChart(request *expansion.ServiceRequest) (*expansion.ServiceResponse, error) {
if request.ChartInvocation == nil { if request.ChartInvocation == nil {
return nil, fmt.Errorf("Request does not have invocation field") return nil, fmt.Errorf("Request does not have invocation field")
} }
...@@ -155,5 +155,5 @@ func (e *expander) ExpandChart(request *common.ExpansionRequest) (*common.Expans ...@@ -155,5 +155,5 @@ func (e *expander) ExpandChart(request *common.ExpansionRequest) (*common.Expans
return nil, fmt.Errorf("cannot unmarshal expansion result (%s):\n%s", err, output) return nil, fmt.Errorf("cannot unmarshal expansion result (%s):\n%s", err, output)
} }
return &common.ExpansionResponse{Resources: output.Config.Resources}, nil return &expansion.ServiceResponse{Resources: output.Config.Resources}, nil
} }
...@@ -25,14 +25,15 @@ import ( ...@@ -25,14 +25,15 @@ import (
"github.com/kubernetes/helm/pkg/chart" "github.com/kubernetes/helm/pkg/chart"
"github.com/kubernetes/helm/pkg/common" "github.com/kubernetes/helm/pkg/common"
"github.com/kubernetes/helm/pkg/expansion"
) )
var expanderName = "../../../expansion/expansion.py" var expanderName = "../../../expansion/expansion.py"
type testCase struct { type testCase struct {
Description string Description string
Request *common.ExpansionRequest Request *expansion.ServiceRequest
ExpectedResponse *common.ExpansionResponse ExpectedResponse *expansion.ServiceResponse
ExpectedError string ExpectedError string
} }
...@@ -47,8 +48,8 @@ func funcName() string { ...@@ -47,8 +48,8 @@ func funcName() string {
return runtime.FuncForPC(pc).Name() return runtime.FuncForPC(pc).Name()
} }
func testExpansion(t *testing.T, req *common.ExpansionRequest, func testExpansion(t *testing.T, req *expansion.ServiceRequest,
expResponse *common.ExpansionResponse, expError string) { expResponse *expansion.ServiceResponse, expError string) {
backend := NewExpander(expanderName) backend := NewExpander(expanderName)
response, err := backend.ExpandChart(req) response, err := backend.ExpandChart(req)
if err != nil { if err != nil {
...@@ -81,7 +82,7 @@ var jinjaExpander = &chart.Expander{ ...@@ -81,7 +82,7 @@ var jinjaExpander = &chart.Expander{
func TestEmptyJinja(t *testing.T) { func TestEmptyJinja(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -99,7 +100,7 @@ func TestEmptyJinja(t *testing.T) { ...@@ -99,7 +100,7 @@ func TestEmptyJinja(t *testing.T) {
}, },
}, },
}, },
&common.ExpansionResponse{ &expansion.ServiceResponse{
Resources: []interface{}{}, Resources: []interface{}{},
}, },
"", // Error "", // Error
...@@ -109,7 +110,7 @@ func TestEmptyJinja(t *testing.T) { ...@@ -109,7 +110,7 @@ func TestEmptyJinja(t *testing.T) {
func TestEmptyPython(t *testing.T) { func TestEmptyPython(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -130,7 +131,7 @@ func TestEmptyPython(t *testing.T) { ...@@ -130,7 +131,7 @@ func TestEmptyPython(t *testing.T) {
}, },
}, },
}, },
&common.ExpansionResponse{ &expansion.ServiceResponse{
Resources: []interface{}{}, Resources: []interface{}{},
}, },
"", // Error "", // Error
...@@ -140,7 +141,7 @@ func TestEmptyPython(t *testing.T) { ...@@ -140,7 +141,7 @@ func TestEmptyPython(t *testing.T) {
func TestSimpleJinja(t *testing.T) { func TestSimpleJinja(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -162,7 +163,7 @@ func TestSimpleJinja(t *testing.T) { ...@@ -162,7 +163,7 @@ func TestSimpleJinja(t *testing.T) {
}, },
}, },
}, },
&common.ExpansionResponse{ &expansion.ServiceResponse{
Resources: []interface{}{ Resources: []interface{}{
map[string]interface{}{ map[string]interface{}{
"name": "foo", "name": "foo",
...@@ -177,7 +178,7 @@ func TestSimpleJinja(t *testing.T) { ...@@ -177,7 +178,7 @@ func TestSimpleJinja(t *testing.T) {
func TestSimplePython(t *testing.T) { func TestSimplePython(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -201,7 +202,7 @@ func TestSimplePython(t *testing.T) { ...@@ -201,7 +202,7 @@ func TestSimplePython(t *testing.T) {
}, },
}, },
}, },
&common.ExpansionResponse{ &expansion.ServiceResponse{
Resources: []interface{}{ Resources: []interface{}{
map[string]interface{}{ map[string]interface{}{
"name": "foo", "name": "foo",
...@@ -216,7 +217,7 @@ func TestSimplePython(t *testing.T) { ...@@ -216,7 +217,7 @@ func TestSimplePython(t *testing.T) {
func TestPropertiesJinja(t *testing.T) { func TestPropertiesJinja(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -244,7 +245,7 @@ func TestPropertiesJinja(t *testing.T) { ...@@ -244,7 +245,7 @@ func TestPropertiesJinja(t *testing.T) {
}, },
}, },
}, },
&common.ExpansionResponse{ &expansion.ServiceResponse{
Resources: []interface{}{ Resources: []interface{}{
map[string]interface{}{ map[string]interface{}{
"name": "foo", "name": "foo",
...@@ -262,7 +263,7 @@ func TestPropertiesJinja(t *testing.T) { ...@@ -262,7 +263,7 @@ func TestPropertiesJinja(t *testing.T) {
func TestPropertiesPython(t *testing.T) { func TestPropertiesPython(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -292,7 +293,7 @@ func TestPropertiesPython(t *testing.T) { ...@@ -292,7 +293,7 @@ func TestPropertiesPython(t *testing.T) {
}, },
}, },
}, },
&common.ExpansionResponse{ &expansion.ServiceResponse{
Resources: []interface{}{ Resources: []interface{}{
map[string]interface{}{ map[string]interface{}{
"name": "foo", "name": "foo",
...@@ -310,7 +311,7 @@ func TestPropertiesPython(t *testing.T) { ...@@ -310,7 +311,7 @@ func TestPropertiesPython(t *testing.T) {
func TestMultiFileJinja(t *testing.T) { func TestMultiFileJinja(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -336,7 +337,7 @@ func TestMultiFileJinja(t *testing.T) { ...@@ -336,7 +337,7 @@ func TestMultiFileJinja(t *testing.T) {
}, },
}, },
}, },
&common.ExpansionResponse{ &expansion.ServiceResponse{
Resources: []interface{}{ Resources: []interface{}{
map[string]interface{}{ map[string]interface{}{
"name": "foo", "name": "foo",
...@@ -368,7 +369,7 @@ var schemaContent = content([]string{ ...@@ -368,7 +369,7 @@ var schemaContent = content([]string{
func TestSchema(t *testing.T) { func TestSchema(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -401,7 +402,7 @@ func TestSchema(t *testing.T) { ...@@ -401,7 +402,7 @@ func TestSchema(t *testing.T) {
}, },
}, },
}, },
&common.ExpansionResponse{ &expansion.ServiceResponse{
Resources: []interface{}{ Resources: []interface{}{
map[string]interface{}{ map[string]interface{}{
"name": "foo", "name": "foo",
...@@ -419,7 +420,7 @@ func TestSchema(t *testing.T) { ...@@ -419,7 +420,7 @@ func TestSchema(t *testing.T) {
func TestSchemaFail(t *testing.T) { func TestSchemaFail(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -460,7 +461,7 @@ func TestSchemaFail(t *testing.T) { ...@@ -460,7 +461,7 @@ func TestSchemaFail(t *testing.T) {
func TestMultiFileJinjaMissing(t *testing.T) { func TestMultiFileJinjaMissing(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -486,7 +487,7 @@ func TestMultiFileJinjaMissing(t *testing.T) { ...@@ -486,7 +487,7 @@ func TestMultiFileJinjaMissing(t *testing.T) {
func TestMultiFilePython(t *testing.T) { func TestMultiFilePython(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -531,7 +532,7 @@ func TestMultiFilePython(t *testing.T) { ...@@ -531,7 +532,7 @@ func TestMultiFilePython(t *testing.T) {
}, },
}, },
}, },
&common.ExpansionResponse{ &expansion.ServiceResponse{
Resources: []interface{}{ Resources: []interface{}{
map[string]interface{}{ map[string]interface{}{
"name": "foo", "name": "foo",
...@@ -546,7 +547,7 @@ func TestMultiFilePython(t *testing.T) { ...@@ -546,7 +547,7 @@ func TestMultiFilePython(t *testing.T) {
func TestMultiFilePythonMissing(t *testing.T) { func TestMultiFilePythonMissing(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -574,7 +575,7 @@ func TestMultiFilePythonMissing(t *testing.T) { ...@@ -574,7 +575,7 @@ func TestMultiFilePythonMissing(t *testing.T) {
func TestWrongChartName(t *testing.T) { func TestWrongChartName(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -600,7 +601,7 @@ func TestWrongChartName(t *testing.T) { ...@@ -600,7 +601,7 @@ func TestWrongChartName(t *testing.T) {
func TestEntrypointNotFound(t *testing.T) { func TestEntrypointNotFound(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -621,7 +622,7 @@ func TestEntrypointNotFound(t *testing.T) { ...@@ -621,7 +622,7 @@ func TestEntrypointNotFound(t *testing.T) {
func TestMalformedResource(t *testing.T) { func TestMalformedResource(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -650,7 +651,7 @@ func TestMalformedResource(t *testing.T) { ...@@ -650,7 +651,7 @@ func TestMalformedResource(t *testing.T) {
func TestResourceNoName(t *testing.T) { func TestResourceNoName(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
...@@ -679,7 +680,7 @@ func TestResourceNoName(t *testing.T) { ...@@ -679,7 +680,7 @@ func TestResourceNoName(t *testing.T) {
func TestResourceNoType(t *testing.T) { func TestResourceNoType(t *testing.T) {
testExpansion( testExpansion(
t, t,
&common.ExpansionRequest{ &expansion.ServiceRequest{
ChartInvocation: &common.Resource{ ChartInvocation: &common.Resource{
Name: "test_invocation", Name: "test_invocation",
Type: funcName(), Type: funcName(),
......
...@@ -17,7 +17,7 @@ limitations under the License. ...@@ -17,7 +17,7 @@ limitations under the License.
package service package service
import ( import (
"github.com/kubernetes/helm/pkg/common" "github.com/kubernetes/helm/pkg/expansion"
"github.com/kubernetes/helm/pkg/util" "github.com/kubernetes/helm/pkg/util"
"errors" "errors"
...@@ -43,8 +43,8 @@ func NewService(handler restful.RouteFunction) *Service { ...@@ -43,8 +43,8 @@ func NewService(handler restful.RouteFunction) *Service {
webService.Produces(restful.MIME_JSON, restful.MIME_XML) webService.Produces(restful.MIME_JSON, restful.MIME_XML)
webService.Route(webService.POST("/expand").To(handler). webService.Route(webService.POST("/expand").To(handler).
Doc("Expand a template."). Doc("Expand a template.").
Reads(&common.ExpansionRequest{}). Reads(&expansion.ServiceRequest{}).
Writes(&common.ExpansionResponse{})) Writes(&expansion.ServiceResponse{}))
return &Service{webService} return &Service{webService}
} }
...@@ -61,10 +61,10 @@ func (s *Service) Register(container *restful.Container) { ...@@ -61,10 +61,10 @@ func (s *Service) Register(container *restful.Container) {
// NewExpansionHandler returns a route function that handles an incoming // NewExpansionHandler returns a route function that handles an incoming
// template expansion request, bound to the supplied expander. // template expansion request, bound to the supplied expander.
func NewExpansionHandler(backend common.Expander) restful.RouteFunction { func NewExpansionHandler(backend expansion.Expander) restful.RouteFunction {
return func(req *restful.Request, resp *restful.Response) { return func(req *restful.Request, resp *restful.Response) {
util.LogHandlerEntry("expandybird: expand", req.Request) util.LogHandlerEntry("expandybird: expand", req.Request)
request := &common.ExpansionRequest{} request := &expansion.ServiceRequest{}
if err := req.ReadEntity(&request); err != nil { if err := req.ReadEntity(&request); err != nil {
logAndReturnErrorFromHandler(http.StatusBadRequest, err.Error(), resp) logAndReturnErrorFromHandler(http.StatusBadRequest, err.Error(), resp)
return return
......
...@@ -2,50 +2,140 @@ package main ...@@ -2,50 +2,140 @@ package main
import ( import (
"github.com/kubernetes/helm/cmd/manager/router" "github.com/kubernetes/helm/cmd/manager/router"
"github.com/kubernetes/helm/pkg/httputil"
"github.com/kubernetes/helm/pkg/repo"
"github.com/kubernetes/helm/pkg/util" "github.com/kubernetes/helm/pkg/util"
"net/http" "net/http"
"net/url"
"regexp"
) )
func registerChartRepoRoutes(c *router.Context, h *router.Handler) { func registerChartRepoRoutes(c *router.Context, h *router.Handler) {
h.Add("GET /chart_repositories", listChartRepositoriesHandlerFunc) h.Add("GET /repositories", listChartReposHandlerFunc)
h.Add("POST /chart_repositories", addChartRepoHandlerFunc) h.Add("GET /repositories/*", getChartRepoHandlerFunc)
h.Add("DELETE /chart_repositories", removeChartRepoHandlerFunc) h.Add("GET /repositories/*/charts", listRepoChartsHandlerFunc)
h.Add("GET /repositories/*/charts/*", getRepoChartHandlerFunc)
h.Add("POST /repositories", addChartRepoHandlerFunc)
h.Add("DELETE /repositories", removeChartRepoHandlerFunc)
} }
func listChartRepositoriesHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error { func listChartReposHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: list chart repositories" handler := "manager: list chart repositories"
repos, err := c.Manager.ListChartRepos() repos, err := c.Manager.ListChartRepos()
if err != nil { if err != nil {
return err return err
} }
util.LogHandlerExitWithJSON(handler, w, repos, http.StatusOK) util.LogHandlerExitWithJSON(handler, w, repos, http.StatusOK)
return nil return nil
} }
func addChartRepoHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error { func addChartRepoHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: add chart repository" handler := "manager: add chart repository"
name, err := pos(w, r, 2) util.LogHandlerEntry(handler, r)
defer r.Body.Close()
cr := &repo.Repo{}
if err := httputil.Decode(w, r, cr); err != nil {
httputil.BadRequest(w, r, err)
return nil
}
if err := c.Manager.AddChartRepo(cr); err != nil {
httputil.BadRequest(w, r, err)
return nil
}
util.LogHandlerExitWithText(handler, w, "added", http.StatusOK)
return nil
}
func removeChartRepoHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: remove chart repository"
util.LogHandlerEntry(handler, r)
URL, err := pos(w, r, 2)
if err != nil { if err != nil {
return err return err
} }
err = c.Manager.AddChartRepo(name)
err = c.Manager.RemoveChartRepo(URL)
if err != nil { if err != nil {
return err return err
} }
util.LogHandlerExitWithJSON(handler, w, "added", http.StatusOK)
util.LogHandlerExitWithText(handler, w, "removed", http.StatusOK)
return nil return nil
} }
func removeChartRepoHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error { func getChartRepoHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: remove chart repository" handler := "manager: get repository"
name, err := pos(w, r, 2) util.LogHandlerEntry(handler, r)
repoURL, err := pos(w, r, 2)
if err != nil {
return err
}
cr, err := c.Manager.GetChartRepo(repoURL)
if err != nil {
httputil.BadRequest(w, r, err)
return nil
}
util.LogHandlerExitWithJSON(handler, w, cr, http.StatusOK)
return nil
}
func listRepoChartsHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: list repository charts"
util.LogHandlerEntry(handler, r)
repoURL, err := pos(w, r, 2)
if err != nil { if err != nil {
return err return err
} }
err = c.Manager.RemoveChartRepo(name)
values, err := url.ParseQuery(r.URL.RawQuery)
if err != nil {
httputil.BadRequest(w, r, err)
return nil
}
var regex *regexp.Regexp
regexString := values.Get("regex")
if regexString != "" {
regex, err = regexp.Compile(regexString)
if err != nil {
httputil.BadRequest(w, r, err)
return nil
}
}
repoCharts, err := c.Manager.ListRepoCharts(repoURL, regex)
if err != nil { if err != nil {
return err return err
} }
util.LogHandlerExitWithJSON(handler, w, "removed", http.StatusOK)
util.LogHandlerExitWithJSON(handler, w, repoCharts, http.StatusOK)
return nil
}
func getRepoChartHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get repository charts"
util.LogHandlerEntry(handler, r)
repoURL, err := pos(w, r, 2)
if err != nil {
return err
}
chartName, err := pos(w, r, 4)
if err != nil {
return err
}
repoChart, err := c.Manager.GetChartForRepo(repoURL, chartName)
if err != nil {
return err
}
util.LogHandlerExitWithJSON(handler, w, repoChart, http.StatusOK)
return nil return nil
} }
...@@ -7,10 +7,10 @@ import ( ...@@ -7,10 +7,10 @@ import (
func TestListChartRepositories(t *testing.T) { func TestListChartRepositories(t *testing.T) {
c := stubContext() c := stubContext()
s := httpHarness(c, "GET /chart_repositories", listChartRepositoriesHandlerFunc) s := httpHarness(c, "GET /repositories", listChartReposHandlerFunc)
defer s.Close() defer s.Close()
res, err := http.Get(s.URL + "/chart_repositories") res, err := http.Get(s.URL + "/repositories")
if err != nil { if err != nil {
t.Errorf("Failed GET: %s", err) t.Errorf("Failed GET: %s", err)
} else if res.StatusCode != http.StatusOK { } else if res.StatusCode != http.StatusOK {
......
...@@ -26,7 +26,6 @@ import ( ...@@ -26,7 +26,6 @@ import (
"net/http" "net/http"
"net/url" "net/url"
"os" "os"
"regexp"
"strings" "strings"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
...@@ -71,13 +70,6 @@ func registerDeploymentRoutes(c *router.Context, h *router.Handler) { ...@@ -71,13 +70,6 @@ func registerDeploymentRoutes(c *router.Context, h *router.Handler) {
h.Add("GET /charts/*/repository", getRepoForChartHandlerFunc) h.Add("GET /charts/*/repository", getRepoForChartHandlerFunc)
h.Add("GET /charts/*/metadata", getMetadataForChartHandlerFunc) h.Add("GET /charts/*/metadata", getMetadataForChartHandlerFunc)
h.Add("GET /charts/*", getChartHandlerFunc) h.Add("GET /charts/*", getChartHandlerFunc)
// TODO: Refactor these commented out routes
// h.Add("GET /repositories/*", getRepoHandlerFunc)
// h.Add("POST /repositories/*", createRepoHandlerFunc)
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)
} }
...@@ -456,122 +448,6 @@ func getChartHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Conte ...@@ -456,122 +448,6 @@ func getChartHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Conte
return nil return nil
} }
// TODO: Refactor this commented out code.
/*
func getRepoHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get repository"
util.LogHandlerEntry(handler, r)
repoName, err := pos(w, r, 2)
if err != nil {
return err
}
cr, err := c.Manager.GetRepo(repoName)
if err != nil {
httputil.BadRequest(w, r, err)
return nil
}
util.LogHandlerExitWithJSON(handler, w, cr, http.StatusOK)
return nil
}
func getRepo(w http.ResponseWriter, r *http.Request, handler string) *repo.Repo {
util.LogHandlerEntry(handler, r)
t := &repo.Repo{}
if err := httputil.Decode(w, r, t); err != nil {
httputil.BadRequest(w, r, err)
return nil
}
return t
}
func createRepoHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: create repository"
util.LogHandlerEntry(handler, r)
defer r.Body.Close()
repoName, err := pos(w, r, 2)
if err != nil {
return err
}
reg := getRepo(w, r, handler)
if reg.Name != repoName {
e := fmt.Errorf("Repo name does not match %s != %s", reg.Name, repoName)
httputil.BadRequest(w, r, e)
return nil
}
if reg != nil {
err = c.Manager.CreateRepo(reg)
if err != nil {
httputil.BadRequest(w, r, err)
return nil
}
}
util.LogHandlerExitWithJSON(handler, w, reg, http.StatusOK)
return nil
}
*/
func listRepositoryChartsHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: list repository charts"
util.LogHandlerEntry(handler, r)
repoName, err := pos(w, r, 2)
if err != nil {
return err
}
values, err := url.ParseQuery(r.URL.RawQuery)
if err != nil {
httputil.BadRequest(w, r, err)
return nil
}
var regex *regexp.Regexp
regexString := values.Get("regex")
if regexString != "" {
regex, err = regexp.Compile(regexString)
if err != nil {
httputil.BadRequest(w, r, err)
return nil
}
}
repoCharts, err := c.Manager.ListRepoCharts(repoName, regex)
if err != nil {
return err
}
util.LogHandlerExitWithJSON(handler, w, repoCharts, http.StatusOK)
return nil
}
func getRepositoryChartHandlerFunc(w http.ResponseWriter, r *http.Request, c *router.Context) error {
handler := "manager: get repository charts"
util.LogHandlerEntry(handler, r)
repoName, err := pos(w, r, 2)
if err != nil {
return err
}
chartName, err := pos(w, r, 4)
if err != nil {
return err
}
repoChart, err := c.Manager.GetChartForRepo(repoName, chartName)
if err != nil {
return err
}
util.LogHandlerExitWithJSON(handler, w, repoChart, http.StatusOK)
return nil
}
func getCredential(w http.ResponseWriter, r *http.Request, handler string) *repo.Credential { func getCredential(w http.ResponseWriter, r *http.Request, handler string) *repo.Credential {
util.LogHandlerEntry(handler, r) util.LogHandlerEntry(handler, r)
t := &repo.Credential{} t := &repo.Credential{}
......
...@@ -50,8 +50,8 @@ type Manager interface { ...@@ -50,8 +50,8 @@ type Manager interface {
GetChart(chartName string) (*chart.Chart, error) GetChart(chartName string) (*chart.Chart, error)
// Repo Charts // Repo Charts
ListRepoCharts(repoName string, regex *regexp.Regexp) ([]string, error) ListRepoCharts(repoURL string, regex *regexp.Regexp) ([]string, error)
GetChartForRepo(repoName, chartName string) (*chart.Chart, error) GetChartForRepo(repoURL, chartName string) (*chart.Chart, error)
// Credentials // Credentials
CreateCredential(name string, c *repo.Credential) error CreateCredential(name string, c *repo.Credential) error
...@@ -59,8 +59,9 @@ type Manager interface { ...@@ -59,8 +59,9 @@ type Manager interface {
// Chart Repositories // Chart Repositories
ListChartRepos() ([]string, error) ListChartRepos() ([]string, error)
AddChartRepo(name string) error AddChartRepo(addition repo.IRepo) error
RemoveChartRepo(name string) error RemoveChartRepo(name string) error
GetChartRepo(URL string) (repo.IRepo, error)
} }
type manager struct { type manager struct {
...@@ -335,19 +336,19 @@ func (m *manager) ListChartInstances(chartName string) ([]*common.ChartInstance, ...@@ -335,19 +336,19 @@ func (m *manager) ListChartInstances(chartName string) ([]*common.ChartInstance,
return m.repository.GetChartInstances(chartName) return m.repository.GetChartInstances(chartName)
} }
// GetRepoForChart returns the repository where a chart resides. // GetRepoForChart returns the repository where the referenced chart resides.
func (m *manager) GetRepoForChart(chartName string) (string, error) { func (m *manager) GetRepoForChart(reference string) (string, error) {
_, r, err := m.repoProvider.GetChartByReference(chartName) _, r, err := m.repoProvider.GetChartByReference(reference)
if err != nil { if err != nil {
return "", err return "", err
} }
return r.GetName(), nil return r.GetURL(), nil
} }
// GetMetadataForChart returns the metadata for a chart. // GetMetadataForChart returns the metadata for the referenced chart.
func (m *manager) GetMetadataForChart(chartName string) (*chart.Chartfile, error) { func (m *manager) GetMetadataForChart(reference string) (*chart.Chartfile, error) {
c, _, err := m.repoProvider.GetChartByReference(chartName) c, _, err := m.repoProvider.GetChartByReference(reference)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -355,9 +356,9 @@ func (m *manager) GetMetadataForChart(chartName string) (*chart.Chartfile, error ...@@ -355,9 +356,9 @@ func (m *manager) GetMetadataForChart(chartName string) (*chart.Chartfile, error
return c.Chartfile(), nil return c.Chartfile(), nil
} }
// GetChart returns a chart. // GetChart returns the referenced chart.
func (m *manager) GetChart(chartName string) (*chart.Chart, error) { func (m *manager) GetChart(reference string) (*chart.Chart, error) {
c, _, err := m.repoProvider.GetChartByReference(chartName) c, _, err := m.repoProvider.GetChartByReference(reference)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -365,28 +366,24 @@ func (m *manager) GetChart(chartName string) (*chart.Chart, error) { ...@@ -365,28 +366,24 @@ func (m *manager) GetChart(chartName string) (*chart.Chart, error) {
return c, nil return c, nil
} }
// ListChartRepos returns the list of chart repositories // ListChartRepos returns the list of available chart repository URLs
func (m *manager) ListChartRepos() ([]string, error) { func (m *manager) ListChartRepos() ([]string, error) {
return m.service.List() return m.service.ListRepos()
} }
// AddChartRepo adds a chart repository to list of available chart repositories // AddChartRepo adds a chart repository to the list
func (m *manager) AddChartRepo(name string) error { func (m *manager) AddChartRepo(addition repo.IRepo) error {
//TODO: implement return m.service.CreateRepo(addition)
return nil
} }
// RemoveChartRepo removes a chart repository to list of available chart repositories // RemoveChartRepo removes a chart repository from the list by URL
func (m *manager) RemoveChartRepo(name string) error { func (m *manager) RemoveChartRepo(URL string) error {
return m.service.Delete(name) return m.service.DeleteRepo(URL)
} }
func (m *manager) CreateRepo(pr repo.IRepo) error { // GetChartRepo returns the chart repository with the given URL
return m.service.Create(pr) func (m *manager) GetChartRepo(URL string) (repo.IRepo, error) {
} return m.service.GetRepoByURL(URL)
func (m *manager) GetRepo(name string) (repo.IRepo, error) {
return m.service.Get(name)
} }
func generateManifestName() string { func generateManifestName() string {
...@@ -411,11 +408,11 @@ func getResourceErrors(c *common.Configuration) []string { ...@@ -411,11 +408,11 @@ func getResourceErrors(c *common.Configuration) []string {
return errs return errs
} }
// ListRepoCharts lists charts in a given repository whose names // ListRepoCharts lists charts in a given repository whose URLs
// conform to the supplied regular expression, or all charts, if the regular // conform to the supplied regular expression, or all charts, if the regular
// expression is nil. // expression is nil.
func (m *manager) ListRepoCharts(repoName string, regex *regexp.Regexp) ([]string, error) { func (m *manager) ListRepoCharts(repoURL string, regex *regexp.Regexp) ([]string, error) {
r, err := m.repoProvider.GetRepoByName(repoName) r, err := m.repoProvider.GetRepoByURL(repoURL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -423,9 +420,9 @@ func (m *manager) ListRepoCharts(repoName string, regex *regexp.Regexp) ([]strin ...@@ -423,9 +420,9 @@ func (m *manager) ListRepoCharts(repoName string, regex *regexp.Regexp) ([]strin
return r.ListCharts(regex) return r.ListCharts(regex)
} }
// GetChartForRepo returns a chart from a given repository. // GetChartForRepo returns a chart by name from a given repository.
func (m *manager) GetChartForRepo(repoName, chartName string) (*chart.Chart, error) { func (m *manager) GetChartForRepo(repoURL, chartName string) (*chart.Chart, error) {
r, err := m.repoProvider.GetRepoByName(repoName) r, err := m.repoProvider.GetRepoByURL(repoURL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
......
...@@ -91,7 +91,7 @@ func (m *mockManager) GetChart(chartName string) (*chart.Chart, error) { ...@@ -91,7 +91,7 @@ func (m *mockManager) GetChart(chartName string) (*chart.Chart, error) {
return nil, nil return nil, nil
} }
func (m *mockManager) AddChartRepo(name string) error { func (m *mockManager) AddChartRepo(addition repo.IRepo) error {
return nil return nil
} }
...@@ -103,6 +103,10 @@ func (m *mockManager) RemoveChartRepo(name string) error { ...@@ -103,6 +103,10 @@ func (m *mockManager) RemoveChartRepo(name string) error {
return nil return nil
} }
func (m *mockManager) GetChartRepo(URL string) (repo.IRepo, error) {
return nil, nil
}
func (m *mockManager) ListRepos() ([]*repo.Repo, error) { func (m *mockManager) ListRepos() ([]*repo.Repo, error) {
return []*repo.Repo{}, nil return []*repo.Repo{}, nil
} }
......
...@@ -17,7 +17,6 @@ limitations under the License. ...@@ -17,7 +17,6 @@ limitations under the License.
package common package common
import ( import (
"github.com/kubernetes/helm/pkg/chart"
"time" "time"
) )
...@@ -90,35 +89,6 @@ type ChartInstance struct { ...@@ -90,35 +89,6 @@ type ChartInstance struct {
Path string `json:"path"` // JSON path within manifest Path string `json:"path"` // JSON path within manifest
} }
// TODO: Remove the following section when the refactoring of templates is complete.
// Template describes a set of resources to be deployed.
// Manager expands a Template into a Configuration, which
// describes the set in a form that can be instantiated.
type Template struct {
Name string `json:"name"`
Content string `json:"content"`
Imports []*ImportFile `json:"imports"`
}
// ImportFile describes a base64 encoded file imported by a Template.
type ImportFile struct {
Name string `json:"name,omitempty"`
Path string `json:"path,omitempty"` // Actual URL for the file
Content string `json:"content"`
}
// SchemaImport represents an import as declared in a schema file.
type SchemaImport struct {
Path string `json:"path"`
Name string `json:"name"`
}
// Schema is a partial DM schema. We only need access to the imports object at this level.
type Schema struct {
Imports []SchemaImport `json:"imports"`
}
// LayoutResource defines the structure of resources in the manifest layout. // LayoutResource defines the structure of resources in the manifest layout.
type LayoutResource struct { type LayoutResource struct {
Resource Resource
...@@ -130,22 +100,6 @@ type Layout struct { ...@@ -130,22 +100,6 @@ type Layout struct {
Resources []*LayoutResource `json:"resources,omitempty"` Resources []*LayoutResource `json:"resources,omitempty"`
} }
// ExpansionRequest defines the API to expander.
type ExpansionRequest struct {
ChartInvocation *Resource `json:"chart_invocation"`
Chart *chart.Content `json:"chart"`
}
// ExpansionResponse defines the API to expander.
type ExpansionResponse struct {
Resources []interface{} `json:"resources"`
}
// Expander abstracts interactions with the expander and deployer services.
type Expander interface {
ExpandChart(request *ExpansionRequest) (*ExpansionResponse, error)
}
// Configuration describes a set of resources in a form // Configuration describes a set of resources in a form
// that can be instantiated. // that can be instantiated.
type Configuration struct { type Configuration struct {
...@@ -180,3 +134,21 @@ type Resource struct { ...@@ -180,3 +134,21 @@ type Resource struct {
Properties map[string]interface{} `json:"properties,omitempty"` Properties map[string]interface{} `json:"properties,omitempty"`
State *ResourceState `json:"state,omitempty"` State *ResourceState `json:"state,omitempty"`
} }
// TODO: Remove the following section when the refactoring of templates is complete.
// Template describes a set of resources to be deployed.
// Manager expands a Template into a Configuration, which
// describes the set in a form that can be instantiated.
type Template struct {
Name string `json:"name"`
Content string `json:"content"`
Imports []*ImportFile `json:"imports"`
}
// ImportFile describes a base64 encoded file imported by a Template.
type ImportFile struct {
Name string `json:"name,omitempty"`
Path string `json:"path,omitempty"` // Actual URL for the file
Content string `json:"content"`
}
/*
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 expander
import (
"github.com/kubernetes/helm/pkg/chart"
)
// SchemaImport represents an import as declared in a schema file.
type SchemaImport struct {
Path string `json:"path"`
Name string `json:"name"`
}
// Schema is a partial DM schema. We only need access to the imports object at this level.
type Schema struct {
Imports []SchemaImport `json:"imports"`
}
// LayoutResource defines the structure of resources in the manifest layout.
type LayoutResource struct {
Resource
Layout
}
// Layout defines the structure of a layout as returned from expansion.
type Layout struct {
Resources []*LayoutResource `json:"resources,omitempty"`
}
// ExpansionRequest defines the API to expander.
type ExpansionRequest struct {
ChartInvocation *Resource `json:"chart_invocation"`
Chart *chart.Content `json:"chart"`
}
// ExpansionResponse defines the API to expander.
type ExpansionResponse struct {
Resources []interface{} `json:"resources"`
}
// Expander abstracts interactions with the expander and deployer services.
type Expander interface {
ExpandChart(request *ExpansionRequest) (*ExpansionResponse, error)
}
// Configuration describes a set of resources in a form
// that can be instantiated.
type Configuration struct {
Resources []*Resource `json:"resources"`
}
// ResourceStatus is an enumeration type for the status of a resource.
type ResourceStatus string
// These constants implement the resourceStatus enumeration type.
const (
Created ResourceStatus = "Created"
Failed ResourceStatus = "Failed"
Aborted ResourceStatus = "Aborted"
)
// ResourceState describes the state of a resource.
// Status is set during resource creation and is a terminal state.
type ResourceState struct {
Status ResourceStatus `json:"status,omitempty"`
SelfLink string `json:"selflink,omitempty"`
Errors []string `json:"errors,omitempty"`
}
// Resource describes a resource in a configuration. A resource has
// a name, a type and a set of properties. The name and type are used
// to identify the resource in Kubernetes. The properties are passed
// to Kubernetes as the resource configuration.
type Resource struct {
Name string `json:"name"`
Type string `json:"type"`
Properties map[string]interface{} `json:"properties,omitempty"`
State *ResourceState `json:"state,omitempty"`
}
/*
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 expansion
import (
"github.com/kubernetes/helm/pkg/chart"
"github.com/kubernetes/helm/pkg/common"
)
// ServiceRequest defines the API to expander.
type ServiceRequest struct {
ChartInvocation *common.Resource `json:"chart_invocation"`
Chart *chart.Content `json:"chart"`
}
// ServiceResponse defines the API to expander.
type ServiceResponse struct {
Resources []interface{} `json:"resources"`
}
// Expander abstracts interactions with the expander and deployer services.
type Expander interface {
ExpandChart(request *ServiceRequest) (*ServiceResponse, error)
}
...@@ -43,14 +43,11 @@ const ( ...@@ -43,14 +43,11 @@ const (
// In a GCS repository all charts appear at the top level. // In a GCS repository all charts appear at the top level.
GCSRepoFormat = FlatRepoFormat GCSRepoFormat = FlatRepoFormat
// GCSPublicRepoName is the name of the public GCS repository. // GCSPublicRepoBucket is the name of the public GCS repository bucket.
GCSPublicRepoName = "kubernetes-charts" GCSPublicRepoBucket = "kubernetes-charts"
// GCSPublicRepoURL is the URL for the public GCS repository. // GCSPublicRepoURL is the URL for the public GCS repository.
GCSPublicRepoURL = "gs://" + GCSPublicRepoName GCSPublicRepoURL = "gs://" + GCSPublicRepoBucket
// GCSPublicRepoBucket is the name of the public GCS repository bucket.
GCSPublicRepoBucket = GCSPublicRepoName
) )
// GCSRepo implements the IStorageRepo interface for Google Cloud Storage. // GCSRepo implements the IStorageRepo interface for Google Cloud Storage.
...@@ -63,12 +60,12 @@ type GCSRepo struct { ...@@ -63,12 +60,12 @@ type GCSRepo struct {
// NewPublicGCSRepo creates a new an IStorageRepo for the public GCS repository. // NewPublicGCSRepo creates a new an IStorageRepo for the public GCS repository.
func NewPublicGCSRepo(httpClient *http.Client) (IStorageRepo, error) { func NewPublicGCSRepo(httpClient *http.Client) (IStorageRepo, error) {
return NewGCSRepo(GCSPublicRepoName, GCSPublicRepoURL, "", nil) return NewGCSRepo(GCSPublicRepoURL, "", nil)
} }
// NewGCSRepo creates a new IStorageRepo for a given GCS repository. // NewGCSRepo creates a new IStorageRepo for a given GCS repository.
func NewGCSRepo(name, URL, credentialName string, httpClient *http.Client) (IStorageRepo, error) { func NewGCSRepo(URL, credentialName string, httpClient *http.Client) (IStorageRepo, error) {
r, err := newRepo(name, URL, credentialName, GCSRepoFormat, GCSRepoType) r, err := newRepo(URL, credentialName, GCSRepoFormat, GCSRepoType)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -120,7 +117,7 @@ func validateRepoType(repoType ERepoType) error { ...@@ -120,7 +117,7 @@ func validateRepoType(repoType ERepoType) error {
func (g *GCSRepo) ListCharts(regex *regexp.Regexp) ([]string, error) { func (g *GCSRepo) ListCharts(regex *regexp.Regexp) ([]string, error) {
charts := []string{} charts := []string{}
// List all objects in a bucket using pagination // ListRepos all objects in a bucket using pagination
pageToken := "" pageToken := ""
for { for {
call := g.service.Objects.List(g.bucket) call := g.service.Objects.List(g.bucket)
...@@ -135,7 +132,7 @@ func (g *GCSRepo) ListCharts(regex *regexp.Regexp) ([]string, error) { ...@@ -135,7 +132,7 @@ func (g *GCSRepo) ListCharts(regex *regexp.Regexp) ([]string, error) {
} }
for _, object := range res.Items { for _, object := range res.Items {
// Charts should be named bucket/chart-X.Y.Z.tgz, so tease apart the name // Charts should be named chart-X.Y.Z.tgz, so tease apart the name
m := ChartNameMatcher.FindStringSubmatch(object.Name) m := ChartNameMatcher.FindStringSubmatch(object.Name)
if len(m) != 3 { if len(m) != 3 {
continue continue
...@@ -156,7 +153,7 @@ func (g *GCSRepo) ListCharts(regex *regexp.Regexp) ([]string, error) { ...@@ -156,7 +153,7 @@ func (g *GCSRepo) ListCharts(regex *regexp.Regexp) ([]string, error) {
// GetChart retrieves, unpacks and returns a chart by name. // GetChart retrieves, unpacks and returns a chart by name.
func (g *GCSRepo) GetChart(name string) (*chart.Chart, error) { func (g *GCSRepo) GetChart(name string) (*chart.Chart, error) {
// Charts should be named bucket/chart-X.Y.Z.tgz, so check that the name matches // Charts should be named chart-X.Y.Z.tgz, so check that the name matches
if !ChartNameMatcher.MatchString(name) { if !ChartNameMatcher.MatchString(name) {
return nil, fmt.Errorf("name must be of the form <name>-<version>.tgz, was %s", name) return nil, fmt.Errorf("name must be of the form <name>-<version>.tgz, was %s", name)
} }
......
...@@ -37,7 +37,7 @@ var ( ...@@ -37,7 +37,7 @@ var (
func TestValidGSURL(t *testing.T) { func TestValidGSURL(t *testing.T) {
tr := getTestRepo(t) tr := getTestRepo(t)
err := validateRepo(tr, TestRepoName, TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType) err := validateRepo(tr, TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -51,7 +51,7 @@ func TestValidGSURL(t *testing.T) { ...@@ -51,7 +51,7 @@ func TestValidGSURL(t *testing.T) {
func TestInvalidGSURL(t *testing.T) { func TestInvalidGSURL(t *testing.T) {
var invalidGSURL = "https://valid.url/wrong/scheme" var invalidGSURL = "https://valid.url/wrong/scheme"
_, err := NewGCSRepo(TestRepoName, invalidGSURL, TestRepoCredentialName, nil) _, err := NewGCSRepo(invalidGSURL, TestRepoCredentialName, nil)
if err == nil { if err == nil {
t.Fatalf("expected error did not occur for invalid GS URL") t.Fatalf("expected error did not occur for invalid GS URL")
} }
...@@ -126,7 +126,7 @@ func TestGetChartWithInvalidName(t *testing.T) { ...@@ -126,7 +126,7 @@ func TestGetChartWithInvalidName(t *testing.T) {
} }
func getTestRepo(t *testing.T) IStorageRepo { func getTestRepo(t *testing.T) IStorageRepo {
tr, err := NewGCSRepo(TestRepoName, TestRepoURL, TestRepoCredentialName, nil) tr, err := NewGCSRepo(TestRepoURL, TestRepoCredentialName, nil)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
......
...@@ -35,55 +35,55 @@ func NewInmemRepoService() IRepoService { ...@@ -35,55 +35,55 @@ func NewInmemRepoService() IRepoService {
r, err := NewPublicGCSRepo(nil) r, err := NewPublicGCSRepo(nil)
if err == nil { if err == nil {
rs.Create(r) rs.CreateRepo(r)
} }
return rs return rs
} }
// List returns the list of all known chart repositories // ListRepos returns the list of all known chart repositories
func (rs *inmemRepoService) List() ([]string, error) { func (rs *inmemRepoService) ListRepos() ([]string, error) {
rs.RLock() rs.RLock()
defer rs.RUnlock() defer rs.RUnlock()
ret := []string{} ret := []string{}
for _, r := range rs.repositories { for _, r := range rs.repositories {
ret = append(ret, r.GetName()) ret = append(ret, r.GetURL())
} }
return ret, nil return ret, nil
} }
// Create adds a known repository to the list // CreateRepo adds a known repository to the list
func (rs *inmemRepoService) Create(repository IRepo) error { func (rs *inmemRepoService) CreateRepo(repository IRepo) error {
rs.Lock() rs.Lock()
defer rs.Unlock() defer rs.Unlock()
name := repository.GetName() URL := repository.GetURL()
_, ok := rs.repositories[name] _, ok := rs.repositories[URL]
if ok { if ok {
return fmt.Errorf("Repository named %s already exists", name) return fmt.Errorf("Repository with URL %s already exists", URL)
} }
rs.repositories[name] = repository rs.repositories[URL] = repository
return nil return nil
} }
// Get returns the repository with the given name // GetRepoByURL returns the repository with the given URL
func (rs *inmemRepoService) Get(name string) (IRepo, error) { func (rs *inmemRepoService) GetRepoByURL(URL string) (IRepo, error) {
rs.RLock() rs.RLock()
defer rs.RUnlock() defer rs.RUnlock()
r, ok := rs.repositories[name] r, ok := rs.repositories[URL]
if !ok { if !ok {
return nil, fmt.Errorf("Failed to find repository named %s", name) return nil, fmt.Errorf("No repository with URL %s", URL)
} }
return r, nil return r, nil
} }
// GetByURL returns the repository that backs the given URL // GetRepoByChartURL returns the repository that backs the given chart URL
func (rs *inmemRepoService) GetByURL(URL string) (IRepo, error) { func (rs *inmemRepoService) GetRepoByChartURL(URL string) (IRepo, error) {
rs.RLock() rs.RLock()
defer rs.RUnlock() defer rs.RUnlock()
...@@ -98,22 +98,22 @@ func (rs *inmemRepoService) GetByURL(URL string) (IRepo, error) { ...@@ -98,22 +98,22 @@ func (rs *inmemRepoService) GetByURL(URL string) (IRepo, error) {
} }
if found == nil { if found == nil {
return nil, fmt.Errorf("Failed to find repository for url: %s", URL) return nil, fmt.Errorf("No repository for url %s", URL)
} }
return found, nil return found, nil
} }
// Delete removes a known repository from the list // DeleteRepo removes a known repository from the list
func (rs *inmemRepoService) Delete(name string) error { func (rs *inmemRepoService) DeleteRepo(URL string) error {
rs.Lock() rs.Lock()
defer rs.Unlock() defer rs.Unlock()
_, ok := rs.repositories[name] _, ok := rs.repositories[URL]
if !ok { if !ok {
return fmt.Errorf("Failed to find repository named %s", name) return fmt.Errorf("No repository with URL %s", URL)
} }
delete(rs.repositories, name) delete(rs.repositories, URL)
return nil return nil
} }
...@@ -23,7 +23,7 @@ import ( ...@@ -23,7 +23,7 @@ import (
func TestService(t *testing.T) { func TestService(t *testing.T) {
rs := NewInmemRepoService() rs := NewInmemRepoService()
repos, err := rs.List() repos, err := rs.ListRepos()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -32,16 +32,16 @@ func TestService(t *testing.T) { ...@@ -32,16 +32,16 @@ func TestService(t *testing.T) {
t.Fatalf("unexpected repo count; want: %d, have %d.", 1, len(repos)) t.Fatalf("unexpected repo count; want: %d, have %d.", 1, len(repos))
} }
tr, err := rs.Get(repos[0]) tr, err := rs.GetRepoByURL(repos[0])
if err != nil { if err != nil {
t.Fatalf("cannot get repo named %s: %s", repos[0], err) t.Fatal(err)
} }
if err := validateRepo(tr, GCSPublicRepoName, GCSPublicRepoURL, "", GCSRepoFormat, GCSRepoType); err != nil { if err := validateRepo(tr, GCSPublicRepoURL, "", GCSRepoFormat, GCSRepoType); err != nil {
t.Fatal(err) t.Fatal(err)
} }
r1, err := rs.Get(GCSPublicRepoName) r1, err := rs.GetRepoByURL(GCSPublicRepoURL)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -50,7 +50,8 @@ func TestService(t *testing.T) { ...@@ -50,7 +50,8 @@ func TestService(t *testing.T) {
t.Fatalf("invalid repo returned; want: %#v, have %#v.", tr, r1) t.Fatalf("invalid repo returned; want: %#v, have %#v.", tr, r1)
} }
r2, err := rs.GetByURL(GCSPublicRepoURL) URL := GCSPublicRepoURL + TestArchiveName
r2, err := rs.GetRepoByChartURL(URL)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -59,50 +60,50 @@ func TestService(t *testing.T) { ...@@ -59,50 +60,50 @@ func TestService(t *testing.T) {
t.Fatalf("invalid repo returned; want: %#v, have %#v.", tr, r2) t.Fatalf("invalid repo returned; want: %#v, have %#v.", tr, r2)
} }
if err := rs.Delete(GCSPublicRepoName); err != nil { if err := rs.DeleteRepo(GCSPublicRepoURL); err != nil {
t.Fatal(err) t.Fatal(err)
} }
if _, err := rs.Get(GCSPublicRepoName); err == nil { if _, err := rs.GetRepoByURL(GCSPublicRepoURL); err == nil {
t.Fatalf("deleted repo named %s returned", GCSPublicRepoName) t.Fatalf("deleted repo with URL %s returned", GCSPublicRepoURL)
} }
} }
func TestCreateRepoWithDuplicateName(t *testing.T) { func TestCreateRepoWithDuplicateURL(t *testing.T) {
rs := NewInmemRepoService() rs := NewInmemRepoService()
r, err := newRepo(GCSPublicRepoName, GCSPublicRepoURL, "", GCSRepoFormat, GCSRepoType) r, err := newRepo(GCSPublicRepoURL, "", GCSRepoFormat, GCSRepoType)
if err != nil { if err != nil {
t.Fatalf("cannot create test repo: %s", err) t.Fatalf("cannot create test repo: %s", err)
} }
if err := rs.Create(r); err == nil { if err := rs.CreateRepo(r); err == nil {
t.Fatalf("created repo with duplicate name: %s", GCSPublicRepoName) t.Fatalf("created repo with duplicate URL: %s", GCSPublicRepoURL)
} }
} }
func TestGetRepoWithInvalidName(t *testing.T) { func TestGetRepoWithInvalidURL(t *testing.T) {
invalidName := "InvalidRepoName" invalidURL := "https://not.a.valid/url"
rs := NewInmemRepoService() rs := NewInmemRepoService()
_, err := rs.Get(invalidName) _, err := rs.GetRepoByURL(invalidURL)
if err == nil { if err == nil {
t.Fatalf("found repo with invalid name: %s", invalidName) t.Fatalf("found repo with invalid URL: %s", invalidURL)
} }
} }
func TestGetRepoWithInvalidURL(t *testing.T) { func TestGetRepoWithInvalidChartURL(t *testing.T) {
invalidURL := "https://not.a.valid/url" invalidURL := "https://not.a.valid/url"
rs := NewInmemRepoService() rs := NewInmemRepoService()
_, err := rs.GetByURL(invalidURL) _, err := rs.GetRepoByChartURL(invalidURL)
if err == nil { if err == nil {
t.Fatalf("found repo with invalid URL: %s", invalidURL) t.Fatalf("found repo with invalid chart URL: %s", invalidURL)
} }
} }
func TestDeleteRepoWithInvalidName(t *testing.T) { func TestDeleteRepoWithInvalidURL(t *testing.T) {
invalidName := "InvalidRepoName" invalidURL := "https://not.a.valid/url"
rs := NewInmemRepoService() rs := NewInmemRepoService()
err := rs.Delete(invalidName) err := rs.DeleteRepo(invalidURL)
if err == nil { if err == nil {
t.Fatalf("deleted repo with invalid name: %s", invalidName) t.Fatalf("deleted repo with invalid name: %s", invalidURL)
} }
} }
...@@ -22,15 +22,11 @@ import ( ...@@ -22,15 +22,11 @@ import (
) )
// NewRepo takes params and returns a IRepo // NewRepo takes params and returns a IRepo
func NewRepo(name, URL, credentialName, repoFormat, repoType string) (IRepo, error) { func NewRepo(URL, credentialName, repoFormat, repoType string) (IRepo, error) {
return newRepo(name, URL, credentialName, ERepoFormat(repoFormat), ERepoType(repoType)) return newRepo(URL, credentialName, ERepoFormat(repoFormat), ERepoType(repoType))
} }
func newRepo(name, URL, credentialName string, repoFormat ERepoFormat, repoType ERepoType) (*Repo, error) { func newRepo(URL, credentialName string, repoFormat ERepoFormat, repoType ERepoType) (*Repo, error) {
if name == "" {
return nil, fmt.Errorf("name must not be empty")
}
_, err := url.Parse(URL) _, err := url.Parse(URL)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid URL (%s): %s", URL, err) return nil, fmt.Errorf("invalid URL (%s): %s", URL, err)
...@@ -45,11 +41,10 @@ func newRepo(name, URL, credentialName string, repoFormat ERepoFormat, repoType ...@@ -45,11 +41,10 @@ func newRepo(name, URL, credentialName string, repoFormat ERepoFormat, repoType
} }
r := &Repo{ r := &Repo{
Name: name,
Type: repoType,
URL: URL, URL: URL,
Format: repoFormat,
CredentialName: credentialName, CredentialName: credentialName,
Type: repoType,
Format: repoFormat,
} }
return r, nil return r, nil
...@@ -65,11 +60,6 @@ func validateRepoFormat(repoFormat ERepoFormat) error { ...@@ -65,11 +60,6 @@ func validateRepoFormat(repoFormat ERepoFormat) error {
return fmt.Errorf("unknown repository format: %s", repoFormat) return fmt.Errorf("unknown repository format: %s", repoFormat)
} }
// GetName returns the friendly name of this repository.
func (r *Repo) GetName() string {
return r.Name
}
// GetType returns the technology implementing this repository. // GetType returns the technology implementing this repository.
func (r *Repo) GetType() ERepoType { func (r *Repo) GetType() ERepoType {
return r.Type return r.Type
...@@ -90,12 +80,7 @@ func (r *Repo) GetCredentialName() string { ...@@ -90,12 +80,7 @@ func (r *Repo) GetCredentialName() string {
return r.CredentialName return r.CredentialName
} }
func validateRepo(tr IRepo, wantName, wantURL, wantCredentialName string, wantFormat ERepoFormat, wantType ERepoType) error { func validateRepo(tr IRepo, wantURL, wantCredentialName string, wantFormat ERepoFormat, wantType ERepoType) error {
haveName := tr.GetName()
if haveName != wantName {
return fmt.Errorf("unexpected repository name; want: %s, have %s", wantName, haveName)
}
haveURL := tr.GetURL() haveURL := tr.GetURL()
if haveURL != wantURL { if haveURL != wantURL {
return fmt.Errorf("unexpected repository url; want: %s, have %s", wantURL, haveURL) return fmt.Errorf("unexpected repository url; want: %s, have %s", wantURL, haveURL)
......
...@@ -21,8 +21,7 @@ import ( ...@@ -21,8 +21,7 @@ import (
) )
var ( var (
TestRepoName = "kubernetes-charts-testing" TestRepoBucket = "kubernetes-charts-testing"
TestRepoBucket = TestRepoName
TestRepoURL = "gs://" + TestRepoBucket TestRepoURL = "gs://" + TestRepoBucket
TestRepoType = GCSRepoType TestRepoType = GCSRepoType
TestRepoFormat = GCSRepoFormat TestRepoFormat = GCSRepoFormat
...@@ -30,32 +29,25 @@ var ( ...@@ -30,32 +29,25 @@ var (
) )
func TestValidRepoURL(t *testing.T) { func TestValidRepoURL(t *testing.T) {
tr, err := NewRepo(TestRepoName, TestRepoURL, TestRepoCredentialName, string(TestRepoFormat), string(TestRepoType)) tr, err := NewRepo(TestRepoURL, TestRepoCredentialName, string(TestRepoFormat), string(TestRepoType))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := validateRepo(tr, TestRepoName, TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType); err != nil { if err := validateRepo(tr, TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType); err != nil {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestInvalidRepoName(t *testing.T) {
_, err := newRepo("", TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType)
if err == nil {
t.Fatalf("expected error did not occur for invalid name")
}
}
func TestInvalidRepoURL(t *testing.T) { func TestInvalidRepoURL(t *testing.T) {
_, err := newRepo(TestRepoName, "%:invalid&url:%", TestRepoCredentialName, TestRepoFormat, TestRepoType) _, err := newRepo("%:invalid&url:%", TestRepoCredentialName, TestRepoFormat, TestRepoType)
if err == nil { if err == nil {
t.Fatalf("expected error did not occur for invalid URL") t.Fatalf("expected error did not occur for invalid URL")
} }
} }
func TestDefaultCredentialName(t *testing.T) { func TestDefaultCredentialName(t *testing.T) {
tr, err := newRepo(TestRepoName, TestRepoURL, "", TestRepoFormat, TestRepoType) tr, err := newRepo(TestRepoURL, "", TestRepoFormat, TestRepoType)
if err != nil { if err != nil {
t.Fatalf("cannot create repo using default credential name") t.Fatalf("cannot create repo using default credential name")
} }
...@@ -68,7 +60,7 @@ func TestDefaultCredentialName(t *testing.T) { ...@@ -68,7 +60,7 @@ func TestDefaultCredentialName(t *testing.T) {
} }
func TestInvalidRepoFormat(t *testing.T) { func TestInvalidRepoFormat(t *testing.T) {
_, err := newRepo(TestRepoName, TestRepoURL, TestRepoCredentialName, "", TestRepoType) _, err := newRepo(TestRepoURL, TestRepoCredentialName, "", TestRepoType)
if err == nil { if err == nil {
t.Fatalf("expected error did not occur for invalid format") t.Fatalf("expected error did not occur for invalid format")
} }
......
...@@ -29,28 +29,21 @@ import ( ...@@ -29,28 +29,21 @@ import (
"sync" "sync"
) )
// IRepoProvider is a factory for IChartRepo instances.
type IRepoProvider interface {
GetRepoByURL(URL string) (IChartRepo, error)
GetRepoByName(repoName string) (IChartRepo, error)
GetChartByReference(reference string) (*chart.Chart, IChartRepo, error)
}
type repoProvider struct { type repoProvider struct {
sync.RWMutex sync.RWMutex
rs IRepoService rs IRepoService
cp ICredentialProvider cp ICredentialProvider
gcsrp GCSRepoProvider gcsrp IGCSRepoProvider
repos map[string]IChartRepo repos map[string]IChartRepo
} }
// NewRepoProvider creates a new repository provider. // NewRepoProvider creates a new repository provider.
func NewRepoProvider(rs IRepoService, gcsrp GCSRepoProvider, cp ICredentialProvider) IRepoProvider { func NewRepoProvider(rs IRepoService, gcsrp IGCSRepoProvider, cp ICredentialProvider) IRepoProvider {
return newRepoProvider(rs, gcsrp, cp) return newRepoProvider(rs, gcsrp, cp)
} }
// newRepoProvider creates a new repository provider. // newRepoProvider creates a new repository provider.
func newRepoProvider(rs IRepoService, gcsrp GCSRepoProvider, cp ICredentialProvider) *repoProvider { func newRepoProvider(rs IRepoService, gcsrp IGCSRepoProvider, cp ICredentialProvider) *repoProvider {
if rs == nil { if rs == nil {
rs = NewInmemRepoService() rs = NewInmemRepoService()
} }
...@@ -79,20 +72,20 @@ func (rp *repoProvider) GetCredentialProvider() ICredentialProvider { ...@@ -79,20 +72,20 @@ func (rp *repoProvider) GetCredentialProvider() ICredentialProvider {
} }
// GetGCSRepoProvider returns the GCS repository provider used by this repository provider. // GetGCSRepoProvider returns the GCS repository provider used by this repository provider.
func (rp *repoProvider) GetGCSRepoProvider() GCSRepoProvider { func (rp *repoProvider) GetGCSRepoProvider() IGCSRepoProvider {
return rp.gcsrp return rp.gcsrp
} }
// GetRepoByName returns the repository with the given name. // GetRepoByURL returns the repository with the given name.
func (rp *repoProvider) GetRepoByName(repoName string) (IChartRepo, error) { func (rp *repoProvider) GetRepoByURL(URL string) (IChartRepo, error) {
rp.Lock() rp.Lock()
defer rp.Unlock() defer rp.Unlock()
if r, ok := rp.repos[repoName]; ok { if r, ok := rp.repos[URL]; ok {
return r, nil return r, nil
} }
cr, err := rp.rs.Get(repoName) cr, err := rp.rs.GetRepoByURL(URL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -115,25 +108,25 @@ func (rp *repoProvider) createRepoByType(r IRepo) (IChartRepo, error) { ...@@ -115,25 +108,25 @@ func (rp *repoProvider) createRepoByType(r IRepo) (IChartRepo, error) {
} }
func (rp *repoProvider) createRepo(cr IChartRepo) (IChartRepo, error) { func (rp *repoProvider) createRepo(cr IChartRepo) (IChartRepo, error) {
name := cr.GetName() URL := cr.GetURL()
if _, ok := rp.repos[name]; ok { if _, ok := rp.repos[URL]; ok {
return nil, fmt.Errorf("respository named %s already exists", name) return nil, fmt.Errorf("respository with URL %s already exists", URL)
} }
rp.repos[name] = cr rp.repos[URL] = cr
return cr, nil return cr, nil
} }
// GetRepoByURL returns the repository whose URL is a prefix of the given URL. // GetRepoByChartURL returns the repository whose URL is a prefix of the given URL.
func (rp *repoProvider) GetRepoByURL(URL string) (IChartRepo, error) { func (rp *repoProvider) GetRepoByChartURL(URL string) (IChartRepo, error) {
rp.Lock() rp.Lock()
defer rp.Unlock() defer rp.Unlock()
if r := rp.findRepoByURL(URL); r != nil { if r := rp.findRepoByChartURL(URL); r != nil {
return r, nil return r, nil
} }
cr, err := rp.rs.GetByURL(URL) cr, err := rp.rs.GetRepoByChartURL(URL)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -141,7 +134,7 @@ func (rp *repoProvider) GetRepoByURL(URL string) (IChartRepo, error) { ...@@ -141,7 +134,7 @@ func (rp *repoProvider) GetRepoByURL(URL string) (IChartRepo, error) {
return rp.createRepoByType(cr) return rp.createRepoByType(cr)
} }
func (rp *repoProvider) findRepoByURL(URL string) IChartRepo { func (rp *repoProvider) findRepoByChartURL(URL string) IChartRepo {
var found IChartRepo var found IChartRepo
for _, r := range rp.repos { for _, r := range rp.repos {
rURL := r.GetURL() rURL := r.GetURL()
...@@ -157,19 +150,14 @@ func (rp *repoProvider) findRepoByURL(URL string) IChartRepo { ...@@ -157,19 +150,14 @@ func (rp *repoProvider) findRepoByURL(URL string) IChartRepo {
// GetChartByReference maps the supplied chart reference into a fully qualified // GetChartByReference maps the supplied chart reference into a fully qualified
// URL, uses the URL to find the repository it references, queries the repository // URL, uses the URL to find the repository it references, queries the repository
// for the chart by URL, and returns the chart and the repository that backs it. // for the chart, and then returns the chart and the repository that backs it.
func (rp *repoProvider) GetChartByReference(reference string) (*chart.Chart, IChartRepo, error) { func (rp *repoProvider) GetChartByReference(reference string) (*chart.Chart, IChartRepo, error) {
l, err := ParseGCSChartReference(reference) l, URL, err := parseChartReference(reference)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
URL, err := l.Long(true) r, err := rp.GetRepoByChartURL(URL)
if err != nil {
return nil, nil, fmt.Errorf("invalid reference %s: %s", reference, err)
}
r, err := rp.GetRepoByURL(URL)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
...@@ -183,17 +171,45 @@ func (rp *repoProvider) GetChartByReference(reference string) (*chart.Chart, ICh ...@@ -183,17 +171,45 @@ func (rp *repoProvider) GetChartByReference(reference string) (*chart.Chart, ICh
return c, r, nil return c, r, nil
} }
// GCSRepoProvider is a factory for GCS IRepo instances. // IsChartReference returns true if the supplied string is a reference to a chart in a repository
type GCSRepoProvider interface { func IsChartReference(reference string) bool {
GetGCSRepo(r IRepo) (IStorageRepo, error) if _, err := ParseChartReference(reference); err != nil {
return false
}
return true
}
// ParseChartReference parses a reference to a chart in a repository and returns the URL for the chart
func ParseChartReference(reference string) (*chart.Locator, error) {
l, _, err := parseChartReference(reference)
if err != nil {
return nil, err
}
return l, nil
}
func parseChartReference(reference string) (*chart.Locator, string, error) {
l, err := chart.Parse(reference)
if err != nil {
return nil, "", fmt.Errorf("cannot parse chart reference %s: %s", reference, err)
}
URL, err := l.Long(true)
if err != nil {
return nil, "", fmt.Errorf("chart reference %s does not resolve to a URL: %s", reference, err)
}
return l, URL, nil
} }
type gcsRepoProvider struct { type gcsRepoProvider struct {
cp ICredentialProvider cp ICredentialProvider
} }
// NewGCSRepoProvider creates a GCSRepoProvider. // NewGCSRepoProvider creates a IGCSRepoProvider.
func NewGCSRepoProvider(cp ICredentialProvider) GCSRepoProvider { func NewGCSRepoProvider(cp ICredentialProvider) IGCSRepoProvider {
if cp == nil { if cp == nil {
cp = NewInmemCredentialProvider() cp = NewInmemCredentialProvider()
} }
...@@ -209,7 +225,7 @@ func (gcsrp gcsRepoProvider) GetGCSRepo(r IRepo) (IStorageRepo, error) { ...@@ -209,7 +225,7 @@ func (gcsrp gcsRepoProvider) GetGCSRepo(r IRepo) (IStorageRepo, error) {
return nil, err return nil, err
} }
return NewGCSRepo(r.GetName(), r.GetURL(), r.GetCredentialName(), client) return NewGCSRepo(r.GetURL(), r.GetCredentialName(), client)
} }
func (gcsrp gcsRepoProvider) createGCSClient(credentialName string) (*http.Client, error) { func (gcsrp gcsRepoProvider) createGCSClient(credentialName string) (*http.Client, error) {
...@@ -233,8 +249,8 @@ func (gcsrp gcsRepoProvider) createGCSClient(credentialName string) (*http.Clien ...@@ -233,8 +249,8 @@ func (gcsrp gcsRepoProvider) createGCSClient(credentialName string) (*http.Clien
} }
// IsGCSChartReference returns true if the supplied string is a reference to a chart in a GCS repository // IsGCSChartReference returns true if the supplied string is a reference to a chart in a GCS repository
func IsGCSChartReference(r string) bool { func IsGCSChartReference(reference string) bool {
if _, err := ParseGCSChartReference(r); err != nil { if _, err := ParseGCSChartReference(reference); err != nil {
return false return false
} }
...@@ -242,20 +258,15 @@ func IsGCSChartReference(r string) bool { ...@@ -242,20 +258,15 @@ func IsGCSChartReference(r string) bool {
} }
// ParseGCSChartReference parses a reference to a chart in a GCS repository and returns the URL for the chart // ParseGCSChartReference parses a reference to a chart in a GCS repository and returns the URL for the chart
func ParseGCSChartReference(r string) (*chart.Locator, error) { func ParseGCSChartReference(reference string) (*chart.Locator, error) {
l, err := chart.Parse(r) l, URL, err := parseChartReference(reference)
if err != nil {
return nil, fmt.Errorf("cannot parse chart reference %s: %s", r, err)
}
URL, err := l.Long(true)
if err != nil { if err != nil {
return nil, fmt.Errorf("chart reference %s does not resolve to a URL: %s", r, err) return nil, err
} }
m := GCSChartURLMatcher.FindStringSubmatch(URL) m := GCSChartURLMatcher.FindStringSubmatch(URL)
if len(m) != 4 { if len(m) != 4 {
return nil, fmt.Errorf("chart reference %s resolve to invalid URL: %s", r, URL) return nil, fmt.Errorf("chart reference %s resolve to invalid URL: %s", reference, URL)
} }
return l, nil return l, nil
......
...@@ -41,12 +41,12 @@ var InvalidChartReferences = []string{ ...@@ -41,12 +41,12 @@ var InvalidChartReferences = []string{
func TestRepoProvider(t *testing.T) { func TestRepoProvider(t *testing.T) {
rp := NewRepoProvider(nil, nil, nil) rp := NewRepoProvider(nil, nil, nil)
haveRepo, err := rp.GetRepoByName(GCSPublicRepoName) haveRepo, err := rp.GetRepoByURL(GCSPublicRepoURL)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if err := validateRepo(haveRepo, GCSPublicRepoName, GCSPublicRepoURL, "", GCSRepoFormat, GCSRepoType); err != nil { if err := validateRepo(haveRepo, GCSPublicRepoURL, "", GCSRepoFormat, GCSRepoType); err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -62,7 +62,8 @@ func TestRepoProvider(t *testing.T) { ...@@ -62,7 +62,8 @@ func TestRepoProvider(t *testing.T) {
} }
wantRepo := haveRepo wantRepo := haveRepo
haveRepo, err = rp.GetRepoByURL(GCSPublicRepoURL) URL := GCSPublicRepoURL + TestArchiveName
haveRepo, err = rp.GetRepoByChartURL(URL)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -72,21 +73,21 @@ func TestRepoProvider(t *testing.T) { ...@@ -72,21 +73,21 @@ func TestRepoProvider(t *testing.T) {
} }
} }
func TestGetRepoByNameWithInvalidName(t *testing.T) { func TestGetRepoByURLWithInvalidURL(t *testing.T) {
var invalidName = "InvalidRepoName" var invalidURL = "https://valid.url/wrong/scheme"
rp := NewRepoProvider(nil, nil, nil) rp := NewRepoProvider(nil, nil, nil)
_, err := rp.GetRepoByName(invalidName) _, err := rp.GetRepoByURL(invalidURL)
if err == nil { if err == nil {
t.Fatalf("found repo using invalid name: %s", invalidName) t.Fatalf("found repo using invalid URL: %s", invalidURL)
} }
} }
func TestGetRepoByURLWithInvalidURL(t *testing.T) { func TestGetRepoByChartURLWithInvalidChartURL(t *testing.T) {
var invalidURL = "https://valid.url/wrong/scheme" var invalidURL = "https://valid.url/wrong/scheme"
rp := NewRepoProvider(nil, nil, nil) rp := NewRepoProvider(nil, nil, nil)
_, err := rp.GetRepoByURL(invalidURL) _, err := rp.GetRepoByChartURL(invalidURL)
if err == nil { if err == nil {
t.Fatalf("found repo using invalid URL: %s", invalidURL) t.Fatalf("found repo using invalid chart URL: %s", invalidURL)
} }
} }
...@@ -115,12 +116,12 @@ func TestGetChartByReferenceWithValidReferences(t *testing.T) { ...@@ -115,12 +116,12 @@ func TestGetChartByReferenceWithValidReferences(t *testing.T) {
func getTestRepoProvider(t *testing.T) IRepoProvider { func getTestRepoProvider(t *testing.T) IRepoProvider {
rp := newRepoProvider(nil, nil, nil) rp := newRepoProvider(nil, nil, nil)
rs := rp.GetRepoService() rs := rp.GetRepoService()
tr, err := newRepo(TestRepoName, TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType) tr, err := newRepo(TestRepoURL, TestRepoCredentialName, TestRepoFormat, TestRepoType)
if err != nil { if err != nil {
t.Fatalf("cannot create test repository: %s", err) t.Fatalf("cannot create test repository: %s", err)
} }
if err := rs.Create(tr); err != nil { if err := rs.CreateRepo(tr); err != nil {
t.Fatalf("cannot initialize repository service: %s", err) t.Fatalf("cannot initialize repository service: %s", err)
} }
......
...@@ -70,17 +70,14 @@ const ( ...@@ -70,17 +70,14 @@ const (
// Repo describes a repository // Repo describes a repository
type Repo struct { type Repo struct {
Name string `json:"name"` // Friendly name for this repository
URL string `json:"url"` // URL to the root of this repository URL string `json:"url"` // URL to the root of this repository
CredentialName string `json:"credentialname"` // Credential name used to access this repository CredentialName string `json:"credentialname,omitempty"` // Credential name used to access this repository
Format ERepoFormat `json:"format"` // Format of this repository Format ERepoFormat `json:"format,omitempty"` // Format of this repository
Type ERepoType `json:"type"` // Technology implementing this repository Type ERepoType `json:"type,omitempty"` // Technology implementing this repository
} }
// IRepo abstracts a repository. // IRepo abstracts a repository.
type IRepo interface { type IRepo interface {
// GetName returns the friendly name of this repository.
GetName() string
// GetURL returns the URL to the root of this repository. // GetURL returns the URL to the root of this repository.
GetURL() string GetURL() string
// GetCredentialName returns the credential name used to access this repository. // GetCredentialName returns the credential name used to access this repository.
...@@ -96,7 +93,7 @@ type IChartRepo interface { ...@@ -96,7 +93,7 @@ type IChartRepo interface {
// A IChartRepo is a IRepo // A IChartRepo is a IRepo
IRepo IRepo
// ListCharts lists charts in this repository whose string values // ListCharts lists the URLs for charts in this repository that
// conform to the supplied regular expression, or all charts if regex is nil // conform to the supplied regular expression, or all charts if regex is nil
ListCharts(regex *regexp.Regexp) ([]string, error) ListCharts(regex *regexp.Regexp) ([]string, error)
...@@ -117,14 +114,26 @@ type IStorageRepo interface { ...@@ -117,14 +114,26 @@ type IStorageRepo interface {
// IRepoService maintains a list of chart repositories that defines the scope of all // IRepoService maintains a list of chart repositories that defines the scope of all
// repository based operations, such as search and chart reference resolution. // repository based operations, such as search and chart reference resolution.
type IRepoService interface { type IRepoService interface {
// List returns the list of all known chart repositories // ListRepos returns the list of all known chart repositories
List() ([]string, error) ListRepos() ([]string, error)
// Create adds a known repository to the list // CreateRepo adds a known repository to the list
Create(repository IRepo) error CreateRepo(repository IRepo) error
// Get returns the repository with the given name // GetRepoByURL returns the repository with the given name
Get(name string) (IRepo, error) GetRepoByURL(name string) (IRepo, error)
// GetByURL returns the repository that backs the given URL // GetRepoByChartURL returns the repository that backs the given URL
GetByURL(URL string) (IRepo, error) GetRepoByChartURL(URL string) (IRepo, error)
// Delete removes a known repository from the list // DeleteRepo removes a known repository from the list
Delete(name string) error DeleteRepo(name string) error
}
// IRepoProvider is a factory for IChartRepo instances.
type IRepoProvider interface {
GetChartByReference(reference string) (*chart.Chart, IChartRepo, error)
GetRepoByChartURL(URL string) (IChartRepo, error)
GetRepoByURL(URL string) (IChartRepo, error)
}
// IGCSRepoProvider is a factory for GCS IRepo instances.
type IGCSRepoProvider interface {
GetGCSRepo(r IRepo) (IStorageRepo, error)
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment