Commit db11c6fb authored by Bruce Flynn's avatar Bruce Flynn
Browse files

Update chart index on interval rather than on upload

parent 9bdb8747
Pipeline #31505 failed with stage
......@@ -8,6 +8,7 @@ import (
"os"
"os/exec"
"path"
"time"
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
......@@ -20,7 +21,7 @@ func httpFail(w http.ResponseWriter, r *http.Request, msg string, err error) {
http.Error(w, msg, http.StatusInternalServerError)
}
func updateIndex() error {
func updateIndex(url, dir string) error {
cmd := exec.Command("helm", "repo", "index", "--url", url, dir)
cmd.Stderr = os.Stderr
err := cmd.Run()
......@@ -30,92 +31,32 @@ func updateIndex() error {
return nil
}
func handleUpload(w http.ResponseWriter, r *http.Request) {
p := path.Join(dir, r.URL.Path)
st, err := os.Stat(p)
// got an error and the file exists... something interesting perhaps?
if err != nil && !os.IsNotExist(err) {
http.Error(w, "InternalServerError", http.StatusInternalServerError)
return
}
// got a stat result, file must exist already and we should not overwrite
if st != nil {
http.Error(w, "File exists", http.StatusForbidden)
return
}
// file does not exist, proceed with upload
f, err := os.Create(p)
if err != nil {
httpFail(w, r, "Could not complete upload", err)
return
}
if _, err := io.Copy(f, r.Body); err != nil {
httpFail(w, r, "Could not complete upload", err)
return
}
err = updateIndex()
if err != nil {
httpFail(w, r, "Could not update index", err)
// best-effort to remove the file if we could not update the index
os.Remove(p)
return
}
log.Printf("successfully handled chart %s", path.Base(p))
}
func handleGetHome(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(fmt.Sprintf(`
<div>
<h1>Chart Repository</h1>
<p>
To add this repostory to Helm, run:
<code>
<pre>
helm repo add &lt;name&gt; %s
</pre>
</code>
</p>
<h3>API</h3>
<dl>
<dt>GET /index.yaml</dt>
<dd>Get chart index file used by Helm</dd>
<dt>GET /<version>-<version>.tgz</dt>
<dd>Get a Heml chart package</dd>
<dt>PUT /<version>-<version>.tgz</dt>
<dd>Upload a new chart package to the index</dd>
<dt>GET /files</dt>
<dd>Basic file listing of chart directory</code></dd>
<dt>GET /status</dt>
<dd>Health check that simply returns <code>OK!</code></dd>
</dl>
</div>
`, url)))
}
func createUploadHandler(dir string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
p := path.Join(dir, r.URL.Path)
st, err := os.Stat(p)
// got an error and the file exists... something interesting perhaps?
if err != nil && !os.IsNotExist(err) {
http.Error(w, "InternalServerError", http.StatusInternalServerError)
return
}
// got a stat result, file must exist already and we should not overwrite
if st != nil {
http.Error(w, "File exists", http.StatusForbidden)
return
}
func handleGetFile(w http.ResponseWriter, r *http.Request) {
p := path.Join(dir, r.URL.Path)
st, err := os.Stat(p)
if err != nil && os.IsNotExist(err) || st != nil && st.IsDir() {
http.Error(w, "Not Found", http.StatusNotFound)
return
}
f, err := os.Open(p)
if err != nil {
httpFail(w, r, "InternalServerError", err)
return
}
if _, err := io.Copy(w, f); err != nil {
httpFail(w, r, "InternalServerError", err)
return
// file does not exist, proceed with upload
f, err := os.Create(p)
if err != nil {
httpFail(w, r, "Could not complete upload", err)
return
}
if _, err := io.Copy(f, r.Body); err != nil {
httpFail(w, r, "Could not complete upload", err)
return
}
log.Printf("successfully handled chart %s", path.Base(p))
}
}
......@@ -132,9 +73,6 @@ func getEnvDefault(name, def string) string {
}
var (
dir string
host string
url string
buildStr string
)
......@@ -157,6 +95,10 @@ Options can also be specified as environment variables $CHART_SVR_<name>
fmt.Fprintf(os.Stderr, "\n%s\n", buildStr)
}
var (
dir, host, url string
)
pflag.StringVar(&dir, "dir", getEnvDefault("CHART_SVR_DIR", "."), "Chart report dir")
pflag.StringVar(&host, "host", getEnvDefault("CHART_SVR_HOST", ":8080"), "Host to bind to [<host>]:<port>")
pflag.StringVar(&url, "url", getEnvDefault("CHART_SVR_URL", ""), "Externally accessible URL to the chart repository")
......@@ -178,11 +120,21 @@ Options can also be specified as environment variables $CHART_SVR_<name>
r := mux.NewRouter()
r.HandleFunc("/status", handleStatus).Methods("GET")
// Limit to only index.yaml and chart (.tgz) files
r.HandleFunc(`/{chart:.*-.*.tgz}`, handleUpload).Methods("PUT")
r.HandleFunc(`/{chart:.*-.*.tgz}`, createUploadHandler(dir)).Methods("PUT")
r.PathPrefix("/").Handler(http.FileServer(http.Dir(dir)))
h := handlers.CombinedLoggingHandler(os.Stdout, handlers.CORS()(r))
go func() {
tick := time.NewTicker(time.Minute)
for {
<-tick.C
if err := updateIndex(url, dir); err != nil {
log.Printf("failed to update chart index at %s: %s", dir, err)
}
}
}()
log.Printf("serving charts from %s on %s", dir, host)
log.Fatal(http.ListenAndServe(host, h))
}
Supports Markdown
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