Merge pull request #1208 from prometheus/assets

Simplify asset handling
This commit is contained in:
Fabian Reinartz 2015-11-11 18:02:16 +01:00
commit 307d9fad46
45 changed files with 1029 additions and 1206 deletions

4
.gitignore vendored
View file

@ -21,11 +21,8 @@
.idea
.DS_Store
._*
.nfs.*
/.git
[568a].out
_cgo_*
core
*-stamp
@ -38,6 +35,5 @@ benchmark.txt
.#*
command-line-arguments.test
*BACKUP*
*BASE*
*LOCAL*
*REMOTE*

View file

@ -14,7 +14,12 @@
GO := GO15VENDOREXPERIMENT=1 go
pkgs = $(shell $(GO) list ./... | grep -v /vendor/)
all: format build test
ifdef DEBUG
bindata_flags = -debug
endif
all: assets format build test
test:
@echo ">> running tests"
@ -38,8 +43,7 @@ docker:
assets:
@echo ">> writing assets"
@$(GO) get -u github.com/jteeuwen/go-bindata/...
@$(GO) generate ./web/blob
@$(GO) fmt ./web/blob >/dev/null
@go-bindata $(bindata_flags) -pkg ui -o web/ui/bindata.go -ignore '(.*\.map|bootstrap\.js|bootstrap-theme\.css|bootstrap\.css)' web/ui/templates/... web/ui/static/...
.PHONY: all format build test vet docker assets

View file

@ -82,10 +82,6 @@ func init() {
&cfg.web.MetricsPath, "web.telemetry-path", "/metrics",
"Path under which to expose metrics.",
)
cfg.fs.BoolVar(
&cfg.web.UseLocalAssets, "web.use-local-assets", false,
"Read assets/templates from file instead of binary.",
)
cfg.fs.StringVar(
&cfg.web.UserAssetsPath, "web.user-assets", "",
"Path to static asset directory, available at /user.",

1
web/blob/.gitignore vendored
View file

@ -1 +0,0 @@
protocol_buffer.descriptor

View file

@ -1,63 +0,0 @@
package blob
//go:generate go-bindata -pkg blob -o files.go -ignore '(.*\.map|bootstrap\.js|bootstrap-theme\.css|bootstrap\.css)' templates/... static/...
import (
"fmt"
"io"
"net/http"
"strings"
"github.com/prometheus/common/log"
"github.com/prometheus/common/route"
)
// Sub-directories for templates and static content.
const (
TemplateFiles = "templates"
StaticFiles = "static"
)
var mimeMap = map[string]string{
"css": "text/css",
"js": "text/javascript",
"descriptor": "application/vnd.google.protobuf;proto=google.protobuf.FileDescriptorSet",
}
// GetFile retrieves the content of an embedded file.
func GetFile(bucket string, name string) ([]byte, error) {
data, err := Asset(fmt.Sprintf("%s/%s", bucket, name))
if err != nil {
return nil, err
}
return data, nil
}
// Handler implements http.Handler.
type Handler struct{}
func (h Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := route.Context(r)
name := strings.Trim(route.Param(ctx, "filepath"), "/")
if name == "" {
name = "index.html"
}
file, err := GetFile(StaticFiles, name)
if err != nil {
if err != io.EOF {
log.Warn("Could not get file: ", err)
}
w.WriteHeader(http.StatusNotFound)
return
}
contentType := http.DetectContentType(file)
if strings.Contains(contentType, "text/plain") || strings.Contains(contentType, "application/octet-stream") {
parts := strings.Split(name, ".")
contentType = mimeMap[parts[len(parts)-1]]
}
w.Header().Set("Content-Type", contentType)
w.Header().Set("Cache-Control", "public, max-age=259200")
w.Write(file)
}

File diff suppressed because one or more lines are too long

982
web/ui/bindata.go Normal file

File diff suppressed because one or more lines are too long

View file

Before

Width:  |  Height:  |  Size: 847 B

After

Width:  |  Height:  |  Size: 847 B

View file

@ -14,6 +14,7 @@
package web
import (
"bytes"
"encoding/json"
"fmt"
"io"
@ -46,7 +47,7 @@ import (
"github.com/prometheus/prometheus/version"
"github.com/prometheus/prometheus/web/api/legacy"
"github.com/prometheus/prometheus/web/api/v1"
"github.com/prometheus/prometheus/web/blob"
"github.com/prometheus/prometheus/web/ui"
)
var localhostRepresentations = []string{"127.0.0.1", "localhost"}
@ -181,11 +182,7 @@ func New(st local.Storage, qe *promql.Engine, rm *rules.Manager, status *Prometh
router.Get("/consoles/*filepath", instrf("consoles", h.consoles))
if o.UseLocalAssets {
router.Get("/static/*filepath", instrf("static", route.FileServe("web/blob/static")))
} else {
router.Get("/static/*filepath", instrh("static", blob.Handler{}))
}
router.Get("/static/*filepath", instrf("static", serveStaticAsset))
if o.UserAssetsPath != "" {
router.Get("/user/*filepath", instrf("user", route.FileServe(o.UserAssetsPath)))
@ -203,6 +200,28 @@ func New(st local.Storage, qe *promql.Engine, rm *rules.Manager, status *Prometh
return h
}
func serveStaticAsset(w http.ResponseWriter, req *http.Request) {
fp := route.Param(route.Context(req), "filepath")
fp = filepath.Join("web/ui/static", fp)
info, err := ui.AssetInfo(fp)
if err != nil {
log.With("file", fp).Warn("Could not get file info: ", err)
w.WriteHeader(http.StatusNotFound)
return
}
file, err := ui.Asset(fp)
if err != nil {
if err != io.EOF {
log.With("file", fp).Warn("Could not get file: ", err)
}
w.WriteHeader(http.StatusNotFound)
return
}
http.ServeContent(w, req, info.Name(), info.ModTime(), bytes.NewReader(file))
}
// ListenError returns the receive-only channel that signals errors while starting the web server.
func (h *Handler) ListenError() <-chan error {
return h.listenErrCh
@ -237,7 +256,7 @@ func (h *Handler) alerts(w http.ResponseWriter, r *http.Request) {
rules.StateFiring: "danger",
},
}
h.executeTemplate(w, "alerts", alertStatus)
h.executeTemplate(w, "alerts.html", alertStatus)
}
func (h *Handler) consoles(w http.ResponseWriter, r *http.Request) {
@ -291,14 +310,14 @@ func (h *Handler) consoles(w http.ResponseWriter, r *http.Request) {
}
func (h *Handler) graph(w http.ResponseWriter, r *http.Request) {
h.executeTemplate(w, "graph", nil)
h.executeTemplate(w, "graph.html", nil)
}
func (h *Handler) status(w http.ResponseWriter, r *http.Request) {
h.statusInfo.mu.RLock()
defer h.statusInfo.mu.RUnlock()
h.executeTemplate(w, "status", struct {
h.executeTemplate(w, "status.html", struct {
Status *PrometheusStatus
Info map[string]string
}{
@ -324,23 +343,6 @@ func (h *Handler) reload(w http.ResponseWriter, r *http.Request) {
h.reloadCh <- struct{}{}
}
func (h *Handler) getTemplateFile(name string) (string, error) {
if h.options.UseLocalAssets {
file, err := ioutil.ReadFile(fmt.Sprintf("web/blob/templates/%s.html", name))
if err != nil {
log.Errorf("Could not read %s template: %s", name, err)
return "", err
}
return string(file), nil
}
file, err := blob.GetFile(blob.TemplateFiles, name+".html")
if err != nil {
log.Errorf("Could not read %s template: %s", name, err)
return "", err
}
return string(file), nil
}
func (h *Handler) consolesPath() string {
if _, err := os.Stat(h.options.ConsoleTemplatesPath + "/index.html"); !os.IsNotExist(err) {
return h.options.ExternalURL.Path + "/consoles/index.html"
@ -353,18 +355,6 @@ func (h *Handler) consolesPath() string {
return ""
}
func (h *Handler) getTemplate(name string) (string, error) {
baseTmpl, err := h.getTemplateFile("_base")
if err != nil {
return "", fmt.Errorf("error reading base template: %s", err)
}
pageTmpl, err := h.getTemplateFile(name)
if err != nil {
return "", fmt.Errorf("error reading page template %s: %s", name, err)
}
return baseTmpl + pageTmpl, nil
}
func tmplFuncs(consolesPath string, opts *Options) template_text.FuncMap {
return template_text.FuncMap{
"since": time.Since,
@ -439,6 +429,18 @@ func tmplFuncs(consolesPath string, opts *Options) template_text.FuncMap {
}
}
func (h *Handler) getTemplate(name string) (string, error) {
baseTmpl, err := ui.Asset("web/ui/templates/_base.html")
if err != nil {
return "", fmt.Errorf("error reading base template: %s", err)
}
pageTmpl, err := ui.Asset(filepath.Join("web/ui/templates", name))
if err != nil {
return "", fmt.Errorf("error reading page template %s: %s", name, err)
}
return string(baseTmpl) + string(pageTmpl), nil
}
func (h *Handler) executeTemplate(w http.ResponseWriter, name string, data interface{}) {
text, err := h.getTemplate(name)
if err != nil {