Skip to content

Commit

Permalink
Add --disable-api and --chart-url flags to CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
jdolitsky committed Oct 8, 2017
1 parent 996aa26 commit 06ff31b
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 48 deletions.
12 changes: 12 additions & 0 deletions cmd/chartmuseum/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ func cliHandler(c *cli.Context) {
options := chartmuseum.ServerOptions{
Debug: c.Bool("debug"),
LogJSON: c.Bool("log-json"),
EnableAPI: !c.Bool("disable-api"),
ChartURL: c.String("chart-url"),
StorageBackend: backend,
}

Expand Down Expand Up @@ -117,12 +119,22 @@ var cliFlags = []cli.Flag{
Usage: "output structured logs as json",
EnvVar: "LOG_JSON",
},
cli.BoolFlag{
Name: "disable-api",
Usage: "disable all routes prefixed with /api",
EnvVar: "DISABLE_API",
},
cli.IntFlag{
Name: "port",
Value: 8080,
Usage: "port to listen on",
EnvVar: "PORT",
},
cli.StringFlag{
Name: "chart-url",
Usage: "absolute url for .tgzs in index.yaml",
EnvVar: "CHART_URL",
},
cli.StringFlag{
Name: "storage",
Usage: "storage backend, can be one of: local, amazon, google",
Expand Down
16 changes: 9 additions & 7 deletions pkg/chartmuseum/routes.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package chartmuseum

func (server *Server) setRoutes() {
func (server *Server) setRoutes(enableAPI bool) {
// Helm Chart Repository
server.Router.GET("/index.yaml", server.getIndexFileRequestHandler)
server.Router.GET("/charts/:filename", server.getStorageObjectRequestHandler)

// Chart Manipulation
server.Router.GET("/api/charts", server.getAllChartsRequestHandler)
server.Router.POST("/api/charts", server.postPackageRequestHandler)
server.Router.POST("/api/prov", server.postProvenanceFileRequestHandler)
server.Router.GET("/api/charts/:name", server.getChartRequestHandler)
server.Router.GET("/api/charts/:name/:version", server.getChartVersionRequestHandler)
server.Router.DELETE("/api/charts/:name/:version", server.deleteChartVersionRequestHandler)
if enableAPI {
server.Router.GET("/api/charts", server.getAllChartsRequestHandler)
server.Router.POST("/api/charts", server.postPackageRequestHandler)
server.Router.POST("/api/prov", server.postProvenanceFileRequestHandler)
server.Router.GET("/api/charts/:name", server.getChartRequestHandler)
server.Router.GET("/api/charts/:name/:version", server.getChartVersionRequestHandler)
server.Router.DELETE("/api/charts/:name/:version", server.deleteChartVersionRequestHandler)
}
}
12 changes: 9 additions & 3 deletions pkg/chartmuseum/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ type (
StorageBackend storage.Backend
LogJSON bool
Debug bool
EnableAPI bool
ChartURL string
}
)

Expand Down Expand Up @@ -84,13 +86,13 @@ func NewServer(options ServerOptions) (*Server, error) {
server := &Server{
Logger: logger,
Router: router,
RepositoryIndex: repo.NewIndex(),
RepositoryIndex: repo.NewIndex(options.ChartURL),
StorageBackend: options.StorageBackend,
StorageCache: []storage.Object{},
StorageCacheLock: &sync.Mutex{},
}

server.setRoutes()
server.setRoutes(options.EnableAPI)

err = server.regenerateRepositoryIndex()
return server, err
Expand Down Expand Up @@ -176,7 +178,11 @@ func (server *Server) regenerateRepositoryIndex() error {
return err
}

index := &repo.Index{IndexFile: server.RepositoryIndex.IndexFile, Raw: server.RepositoryIndex.Raw}
index := &repo.Index{
IndexFile: server.RepositoryIndex.IndexFile,
Raw: server.RepositoryIndex.Raw,
ChartURL: server.RepositoryIndex.ChartURL,
}

for _, object := range diff.Removed {
err := server.removeIndexObject(index, object)
Expand Down
96 changes: 63 additions & 33 deletions pkg/chartmuseum/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,22 @@ var testProvfilePath = "../../testdata/charts/mychart/mychart-0.1.0.tgz.prov"
type ServerTestSuite struct {
suite.Suite
Server *Server
DisabledAPIServer *Server
BrokenServer *Server
TempDirectory string
BrokenTempDirectory string
TestTarballFilename string
TestProvfileFilename string
}

func (suite *ServerTestSuite) doRequest(broken bool, method string, urlStr string, body io.Reader) gin.ResponseWriter {
func (suite *ServerTestSuite) doRequest(broken bool, disabled bool, method string, urlStr string, body io.Reader) gin.ResponseWriter {
c, _ := gin.CreateTestContext(httptest.NewRecorder())
c.Request, _ = http.NewRequest(method, urlStr, body)
if broken {
suite.BrokenServer.Router.HandleContext(c)

} else if disabled {
suite.DisabledAPIServer.Router.HandleContext(c)
} else {
suite.Server.Router.HandleContext(c)
}
Expand All @@ -56,19 +60,24 @@ func (suite *ServerTestSuite) SetupSuite() {

backend := storage.Backend(storage.NewLocalFilesystemBackend(suite.TempDirectory))

server, err := NewServer(ServerOptions{backend, false, false})
server, err := NewServer(ServerOptions{backend, false, false, true, ""})
suite.NotNil(server)
suite.Nil(err, "no error creating new server, logJson=false, debug=false")
suite.Nil(err, "no error creating new server, logJson=false, debug=false, disabled=false")

server, err = NewServer(ServerOptions{backend, true, true})
server, err = NewServer(ServerOptions{backend, true, true, true, ""})
suite.NotNil(server)
suite.Nil(err, "no error creating new server, logJson=true, debug=true")
suite.Nil(err, "no error creating new server, logJson=true, debug=true, disabled=false")

server, err = NewServer(ServerOptions{backend, false, true})
suite.Nil(err, "no error creating new server, logJson=false, debug=true")
server, err = NewServer(ServerOptions{backend, false, true, true, ""})
suite.Nil(err, "no error creating new server, logJson=false, debug=true, disabled=false")

suite.Server = server

disabledAPIServer, err := NewServer(ServerOptions{backend, false, true, false, ""})
suite.Nil(err, "no error creating new server, logJson=false, debug=true, disabled=true")

suite.DisabledAPIServer = disabledAPIServer

suite.TestTarballFilename = pathutil.Join(suite.TempDirectory, "mychart-0.1.0.tgz")
destFileTarball, err := os.Create(suite.TestTarballFilename)
suite.Nil(err, "no error creating new tarball in temp dir")
Expand All @@ -95,7 +104,7 @@ func (suite *ServerTestSuite) SetupSuite() {
defer os.RemoveAll(suite.BrokenTempDirectory)

brokenBackend := storage.Backend(storage.NewLocalFilesystemBackend(suite.BrokenTempDirectory))
brokenServer, err := NewServer(ServerOptions{brokenBackend, false, true})
brokenServer, err := NewServer(ServerOptions{brokenBackend, false, true, true, ""})
suite.Nil(err, "no error creating new server, logJson=false, debug=true")

suite.BrokenServer = brokenServer
Expand Down Expand Up @@ -139,101 +148,122 @@ func (suite *ServerTestSuite) TestRoutes() {
var res gin.ResponseWriter

// GET /charts/<filename>
res = suite.doRequest(false, "GET", "/charts/mychart-0.1.0.tgz", nil)
res = suite.doRequest(false, false, "GET", "/charts/mychart-0.1.0.tgz", nil)
suite.Equal(200, res.Status(), "200 GET /charts/mychart-0.1.0.tgz")

res = suite.doRequest(false, "GET", "/charts/mychart-0.1.0.tgz.prov", nil)
res = suite.doRequest(false, false, "GET", "/charts/mychart-0.1.0.tgz.prov", nil)
suite.Equal(200, res.Status(), "200 GET /charts/mychart-0.1.0.tgz.prov")

res = suite.doRequest(false, "GET", "/charts/fakechart-0.1.0.tgz", nil)
res = suite.doRequest(false, false, "GET", "/charts/fakechart-0.1.0.tgz", nil)
suite.Equal(404, res.Status(), "404 GET /charts/fakechart-0.1.0.tgz")

res = suite.doRequest(false, "GET", "/charts/fakechart-0.1.0.tgz.prov", nil)
res = suite.doRequest(false, false, "GET", "/charts/fakechart-0.1.0.tgz.prov", nil)
suite.Equal(404, res.Status(), "404 GET /charts/fakechart-0.1.0.tgz.prov")

res = suite.doRequest(false, "GET", "/charts/fakechart-0.1.0.bad", nil)
res = suite.doRequest(false, false, "GET", "/charts/fakechart-0.1.0.bad", nil)
suite.Equal(500, res.Status(), "500 GET /charts/fakechart-0.1.0.bad")

// GET /api/charts
res = suite.doRequest(false, "GET", "/api/charts", nil)
res = suite.doRequest(false, false, "GET", "/api/charts", nil)
suite.Equal(200, res.Status(), "200 GET /api/charts")

res = suite.doRequest(true, "GET", "/api/charts", nil)
res = suite.doRequest(true, false, "GET", "/api/charts", nil)
suite.Equal(500, res.Status(), "500 GET /api/charts")

// GET /api/charts/<chart>
res = suite.doRequest(false, "GET", "/api/charts/mychart", nil)
res = suite.doRequest(false, false, "GET", "/api/charts/mychart", nil)
suite.Equal(200, res.Status(), "200 GET /api/charts/mychart")

res = suite.doRequest(false, "GET", "/api/charts/fakechart", nil)
res = suite.doRequest(false, false, "GET", "/api/charts/fakechart", nil)
suite.Equal(404, res.Status(), "404 GET /api/charts/fakechart")

res = suite.doRequest(true, "GET", "/api/charts/mychart", nil)
res = suite.doRequest(true, false, "GET", "/api/charts/mychart", nil)
suite.Equal(500, res.Status(), "500 GET /api/charts/mychart")

// GET /api/charts/<chart>/<version>
res = suite.doRequest(false, "GET", "/api/charts/mychart/0.1.0", nil)
res = suite.doRequest(false, false, "GET", "/api/charts/mychart/0.1.0", nil)
suite.Equal(200, res.Status(), "200 GET /api/charts/mychart/0.1.0")

res = suite.doRequest(false, "GET", "/api/charts/mychart/latest", nil)
res = suite.doRequest(false, false, "GET", "/api/charts/mychart/latest", nil)
suite.Equal(200, res.Status(), "200 GET /api/charts/mychart/latest")

res = suite.doRequest(false, "GET", "/api/charts/mychart/0.0.0", nil)
res = suite.doRequest(false, false, "GET", "/api/charts/mychart/0.0.0", nil)
suite.Equal(404, res.Status(), "404 GET /api/charts/mychart/0.0.0")

res = suite.doRequest(false, "GET", "/api/charts/fakechart/0.1.0", nil)
res = suite.doRequest(false, false, "GET", "/api/charts/fakechart/0.1.0", nil)
suite.Equal(404, res.Status(), "404 GET /api/charts/fakechart/0.1.0")

res = suite.doRequest(true, "GET", "/api/charts/mychart/0.1.0", nil)
res = suite.doRequest(true, false, "GET", "/api/charts/mychart/0.1.0", nil)
suite.Equal(500, res.Status(), "500 GET /api/charts/mychart/0.1.0")

// DELETE /api/charts/<chart>/<version>
res = suite.doRequest(false, "DELETE", "/api/charts/mychart/0.1.0", nil)
res = suite.doRequest(false, false, "DELETE", "/api/charts/mychart/0.1.0", nil)
suite.Equal(200, res.Status(), "200 DELETE /api/charts/mychart/0.1.0")

res = suite.doRequest(false, "DELETE", "/api/charts/mychart/0.1.0", nil)
res = suite.doRequest(false, false, "DELETE", "/api/charts/mychart/0.1.0", nil)
suite.Equal(404, res.Status(), "404 DELETE /api/charts/mychart/0.1.0")

// GET /index.yaml
res = suite.doRequest(false, "GET", "/index.yaml", nil)
res = suite.doRequest(false, false, "GET", "/index.yaml", nil)
suite.Equal(200, res.Status(), "200 GET /index.yaml")

res = suite.doRequest(true, "GET", "/index.yaml", nil)
res = suite.doRequest(true, false, "GET", "/index.yaml", nil)
suite.Equal(500, res.Status(), "500 GET /index.yaml")

// POST /api/charts
body = bytes.NewBuffer([]byte{})
res = suite.doRequest(false, "POST", "/api/charts", body)
res = suite.doRequest(false, false, "POST", "/api/charts", body)
suite.Equal(500, res.Status(), "500 POST /api/charts")

// POST /api/prov
body = bytes.NewBuffer([]byte{})
res = suite.doRequest(false, "POST", "/api/prov", body)
res = suite.doRequest(false, false, "POST", "/api/prov", body)
suite.Equal(500, res.Status(), "500 POST /api/prov")

// POST /api/charts
content, err := ioutil.ReadFile(testTarballPath)
suite.Nil(err, "no error opening test tarball")

body = bytes.NewBuffer(content)
res = suite.doRequest(false, "POST", "/api/charts", body)
res = suite.doRequest(false, false, "POST", "/api/charts", body)
suite.Equal(201, res.Status(), "201 POST /api/charts")

body = bytes.NewBuffer(content)
res = suite.doRequest(false, "POST", "/api/charts", body)
res = suite.doRequest(false, false, "POST", "/api/charts", body)
suite.Equal(500, res.Status(), "500 POST /api/charts")

// POST /api/prov
content, err = ioutil.ReadFile(testProvfilePath)
suite.Nil(err, "no error opening test provenance file")

body = bytes.NewBuffer(content)
res = suite.doRequest(false, "POST", "/api/prov", body)
res = suite.doRequest(false, false, "POST", "/api/prov", body)
suite.Equal(201, res.Status(), "201 POST /api/prov")

body = bytes.NewBuffer(content)
res = suite.doRequest(false, "POST", "/api/prov", body)
res = suite.doRequest(false, false, "POST", "/api/prov", body)
suite.Equal(500, res.Status(), "500 POST /api/prov")

// Test that all /api routes disabled if EnableAPI=false
res = suite.doRequest(false, true, "GET", "/api/charts", nil)
suite.Equal(404, res.Status(), "404 GET /api/charts")

res = suite.doRequest(false, true, "GET", "/api/charts/mychart", nil)
suite.Equal(404, res.Status(), "404 GET /api/charts")

res = suite.doRequest(false, true, "GET", "/api/charts/mychart/0.1.0", nil)
suite.Equal(404, res.Status(), "404 GET /api/charts")

body = bytes.NewBuffer([]byte{})
res = suite.doRequest(false, true, "POST", "/api/charts", body)
suite.Equal(404, res.Status(), "404 POST /api/charts")

body = bytes.NewBuffer([]byte{})
res = suite.doRequest(false, true, "POST", "/api/prov", body)
suite.Equal(404, res.Status(), "404 POST /api/prov")

res = suite.doRequest(false, true, "DELETE", "/api/charts/mychart/0.1.0", nil)
suite.Equal(404, res.Status(), "404 DELETE /api/charts/mychart/0.1.0")
}

func TestServerTestSuite(t *testing.T) {
Expand Down
17 changes: 14 additions & 3 deletions pkg/repo/index.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package repo

import (
"strings"
"time"

"github.com/ghodss/yaml"
Expand All @@ -16,12 +17,14 @@ var (
// Index represents the repository index (index.yaml)
type Index struct {
*helm_repo.IndexFile
Raw []byte
Raw []byte
ChartURL string
}

// NewIndex creates a new instance of Index
func NewIndex() *Index {
index := Index{&helm_repo.IndexFile{}, []byte{}}
func NewIndex(chartURL string) *Index {
chartURL = strings.TrimSuffix(chartURL, "/")
index := Index{&helm_repo.IndexFile{}, []byte{}, chartURL}
index.Entries = map[string]helm_repo.ChartVersions{}
index.APIVersion = helm_repo.APIVersionV1
return &index
Expand Down Expand Up @@ -63,6 +66,7 @@ func (index *Index) AddEntry(chartVersion *helm_repo.ChartVersion) {
if _, ok := index.Entries[chartVersion.Name]; !ok {
index.Entries[chartVersion.Name] = helm_repo.ChartVersions{}
}
index.setChartURL(chartVersion)
index.Entries[chartVersion.Name] = append(index.Entries[chartVersion.Name], chartVersion)
}

Expand All @@ -72,6 +76,7 @@ func (index *Index) UpdateEntry(chartVersion *helm_repo.ChartVersion) {
if k == chartVersion.Name {
for i, cv := range index.Entries[chartVersion.Name] {
if cv.Version == chartVersion.Version {
index.setChartURL(chartVersion)
index.Entries[chartVersion.Name][i] = chartVersion
break
}
Expand All @@ -80,3 +85,9 @@ func (index *Index) UpdateEntry(chartVersion *helm_repo.ChartVersion) {
}
}
}

func (index *Index) setChartURL(chartVersion *helm_repo.ChartVersion) {
if index.ChartURL != "" {
chartVersion.URLs[0] = strings.Join([]string{index.ChartURL, chartVersion.URLs[0]}, "/")
}
}
18 changes: 16 additions & 2 deletions pkg/repo/index_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func getChartVersion(name string, patch int, created time.Time) *helm_repo.Chart
}
chartVersion := helm_repo.ChartVersion{
Metadata: &metadata,
URLs: []string{},
URLs: []string{fmt.Sprintf("charts/%s-%s.tgz", name, version)},
Created: created,
Removed: false,
Digest: "",
Expand All @@ -32,7 +32,7 @@ func getChartVersion(name string, patch int, created time.Time) *helm_repo.Chart
}

func (suite *IndexTestSuite) SetupSuite() {
suite.Index = NewIndex()
suite.Index = NewIndex("")
now := time.Now()
for _, name := range []string{"a", "b", "c"} {
for i := 0; i < 10; i++ {
Expand Down Expand Up @@ -71,6 +71,20 @@ func (suite *IndexTestSuite) TestRemove() {
suite.Index.RemoveEntry(chartVersion)
}

func (suite *IndexTestSuite) TestChartURLs() {
index := NewIndex("")
chartVersion := getChartVersion("a", 0, time.Now())
index.AddEntry(chartVersion)
suite.Equal("charts/a-1.0.0.tgz",
index.Entries["a"][0].URLs[0], "relative chart url")

index = NewIndex("http://mysite.com:8080/")
chartVersion = getChartVersion("a", 0, time.Now())
index.AddEntry(chartVersion)
suite.Equal("http://mysite.com:8080/charts/a-1.0.0.tgz",
index.Entries["a"][0].URLs[0], "absolute chart url")
}

func TestIndexTestSuite(t *testing.T) {
suite.Run(t, new(IndexTestSuite))
}

0 comments on commit 06ff31b

Please sign in to comment.