diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a7c0c7d44..15c44c78b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ We use *breaking* word for marking changes that are not backward compatible (rel - [#1253](https://github.com/improbable-eng/thanos/pull/1253) Add support for specifying a maximum amount of retries when using Azure Blob storage (default: no retries). +- [#1248](https://github.com/improbable-eng/thanos/pull/1248) Add a web UI to show the state of remote storage. + ## [v0.5.0](https://github.com/improbable-eng/thanos/releases/tag/v0.5.0) - 2019.06.05 TL;DR: Store LRU cache is no longer leaking, Upgraded Thanos UI to Prometheus 2.9, Fixed auto-downsampling, Moved to Go 1.12.5 and more. diff --git a/cmd/thanos/bucket.go b/cmd/thanos/bucket.go index 1baecebb3e..65f2e2f411 100644 --- a/cmd/thanos/bucket.go +++ b/cmd/thanos/bucket.go @@ -4,25 +4,31 @@ import ( "context" "encoding/json" "fmt" + "net" + "net/http" "os" "sort" "strings" "text/template" "time" - "github.com/go-kit/kit/log" "github.com/improbable-eng/thanos/pkg/block" "github.com/improbable-eng/thanos/pkg/block/metadata" "github.com/improbable-eng/thanos/pkg/objstore" "github.com/improbable-eng/thanos/pkg/objstore/client" "github.com/improbable-eng/thanos/pkg/runutil" + "github.com/improbable-eng/thanos/pkg/ui" "github.com/improbable-eng/thanos/pkg/verifier" + + "github.com/go-kit/kit/log" + "github.com/go-kit/kit/log/level" "github.com/oklog/run" "github.com/oklog/ulid" "github.com/olekukonko/tablewriter" opentracing "github.com/opentracing/opentracing-go" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/route" "github.com/prometheus/tsdb/labels" "golang.org/x/text/language" "golang.org/x/text/message" @@ -53,6 +59,7 @@ func registerBucket(m map[string]setupFunc, app *kingpin.Application, name strin registerBucketVerify(m, cmd, name, objStoreConfig) registerBucketLs(m, cmd, name, objStoreConfig) registerBucketInspect(m, cmd, name, objStoreConfig) + registerBucketWeb(m, cmd, name, objStoreConfig) return } @@ -291,6 +298,115 @@ func registerBucketInspect(m map[string]setupFunc, root *kingpin.CmdClause, name } } +// registerBucketWeb exposes a web interface for the state of remote store like `pprof web` +func registerBucketWeb(m map[string]setupFunc, root *kingpin.CmdClause, name string, objStoreConfig *pathOrContent) { + cmd := root.Command("web", "Web interface for remote storage bucket") + bind := cmd.Flag("listen", "HTTP host:port to listen on").Default("0.0.0.0:8080").String() + interval := cmd.Flag("refresh", "Refresh interval to download metadata from remote storage").Default("30m").Duration() + timeout := cmd.Flag("timeout", "Timeout to download metadata from remote storage").Default("5m").Duration() + label := cmd.Flag("label", "Prometheus label to use as timeline title").String() + + m[name+" web"] = func(g *run.Group, logger log.Logger, reg *prometheus.Registry, _ opentracing.Tracer, _ bool) error { + ctx, cancel := context.WithCancel(context.Background()) + + router := route.New() + bucketUI := ui.NewBucketUI(logger, *label) + bucketUI.Register(router) + + if *interval < 5*time.Minute { + level.Warn(logger).Log("msg", "Refreshing more often than 5m could lead to large data transfers") + } + + if *timeout < time.Minute { + level.Warn(logger).Log("msg", "Timeout less than 1m could lead to frequent failures") + } + + if *interval < (*timeout * 2) { + level.Warn(logger).Log("msg", "Refresh interval should be at least 2 times the timeout") + } + + g.Add(func() error { + return refresh(ctx, logger, bucketUI, *interval, *timeout, name, reg, objStoreConfig) + }, func(error) { + cancel() + }) + + l, err := net.Listen("tcp", *bind) + if err != nil { + return errors.Wrapf(err, "listen HTTP on address %s", *bind) + } + + g.Add(func() error { + level.Info(logger).Log("msg", "Listening for query and metrics", "address", *bind) + return errors.Wrap(http.Serve(l, router), "serve web") + }, func(error) { + runutil.CloseWithLogOnErr(logger, l, "http listener") + }) + + return nil + } +} + +// refresh metadata from remote storage periodically and update UI. +func refresh(ctx context.Context, logger log.Logger, bucketUI *ui.Bucket, duration time.Duration, timeout time.Duration, name string, reg *prometheus.Registry, objStoreConfig *pathOrContent) error { + confContentYaml, err := objStoreConfig.Content() + if err != nil { + return err + } + + bkt, err := client.NewBucket(logger, confContentYaml, reg, name) + if err != nil { + return errors.Wrap(err, "bucket client") + } + + defer runutil.CloseWithLogOnErr(logger, bkt, "bucket client") + return runutil.Repeat(duration, ctx.Done(), func() error { + return runutil.RetryWithLog(logger, time.Minute, ctx.Done(), func() error { + iterCtx, iterCancel := context.WithTimeout(ctx, timeout) + defer iterCancel() + + blocks, err := download(iterCtx, logger, bkt) + if err != nil { + bucketUI.Set("[]", err) + return err + } + + data, err := json.Marshal(blocks) + if err != nil { + bucketUI.Set("[]", err) + return err + } + bucketUI.Set(string(data), nil) + return nil + }) + }) +} + +func download(ctx context.Context, logger log.Logger, bkt objstore.Bucket) (blocks []metadata.Meta, err error) { + level.Info(logger).Log("msg", "synchronizing block metadata") + + if err = bkt.Iter(ctx, "", func(name string) error { + id, ok := block.IsBlockDir(name) + if !ok { + return nil + } + + meta, err := block.DownloadMeta(ctx, logger, bkt, id) + if err != nil { + return err + } + + blocks = append(blocks, meta) + return nil + }); err != nil { + level.Error(logger).Log("err", err, "msg", "Failed to downloaded block metadata") + return blocks, err + } + + level.Info(logger).Log("msg", "downloaded blocks meta.json", "num", len(blocks)) + return blocks, nil +} + func printTable(blockMetas []*metadata.Meta, selectorLabels labels.Labels, sortBy []string) error { header := inspectColumns diff --git a/docs/components/bucket.md b/docs/components/bucket.md index 6ca7a02ec5..426b019058 100644 --- a/docs/components/bucket.md +++ b/docs/components/bucket.md @@ -65,6 +65,9 @@ Subcommands: bucket inspect [] Inspect all blocks in the bucket in detailed, table-like way + bucket web [] + Web interface for remote storage bucket + ``` diff --git a/pkg/runutil/runutil.go b/pkg/runutil/runutil.go index aa0d1b13d5..ae63cae4a2 100644 --- a/pkg/runutil/runutil.go +++ b/pkg/runutil/runutil.go @@ -52,7 +52,7 @@ import ( tsdberrors "github.com/prometheus/tsdb/errors" ) -// Repeat executes f every interval seconds until stopc is closed. +// Repeat executes f every interval seconds until stopc is closed or f returns an error. // It executes f once right after being called. func Repeat(interval time.Duration, stopc <-chan struct{}, f func() error) error { tick := time.NewTicker(interval) diff --git a/pkg/ui/bindata.go b/pkg/ui/bindata.go index e8ae6e7550..6788fe411f 100644 --- a/pkg/ui/bindata.go +++ b/pkg/ui/bindata.go @@ -2,6 +2,8 @@ // sources: // pkg/ui/templates/_base.html // pkg/ui/templates/alerts.html +// pkg/ui/templates/bucket.html +// pkg/ui/templates/bucket_menu.html // pkg/ui/templates/graph.html // pkg/ui/templates/query_menu.html // pkg/ui/templates/rule_menu.html @@ -15,6 +17,7 @@ // pkg/ui/static/img/ajax-loader.gif // pkg/ui/static/img/favicon.ico // pkg/ui/static/js/alerts.js +// pkg/ui/static/js/bucket.js // pkg/ui/static/js/graph.js // pkg/ui/static/js/graph_template.handlebar // pkg/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-grid.css @@ -157,7 +160,7 @@ func pkgUiTemplates_baseHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/templates/_base.html", size: 1478, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/templates/_base.html", size: 1478, mode: os.FileMode(420), modTime: time.Unix(1560335869, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -177,7 +180,47 @@ func pkgUiTemplatesAlertsHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/templates/alerts.html", size: 2698, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/templates/alerts.html", size: 2698, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _pkgUiTemplatesBucketHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x7c\x93\x4d\x8f\xda\x3c\x10\xc7\xef\x7c\x8a\x91\xa5\xe7\xb6\x60\x1e\x75\x7b\x61\x09\x55\x5b\xf5\xb6\x87\xaa\x87\x5e\xaa\x1e\x9c\x78\xc0\x66\x8d\x9d\xda\x43\x58\x64\xf9\xbb\x57\xb1\x93\x40\xda\x55\x39\x18\xcf\xdb\x7f\xe6\x37\x98\x18\x25\xee\xb5\x45\x60\x0a\x85\x64\x29\x2d\x00\x00\xb6\x27\x24\x01\x8a\xa8\x5d\xe2\xaf\xb3\xee\x2a\xe6\x71\xef\x31\x28\x06\x8d\xb3\x84\x96\x2a\xf6\x6e\xbd\x66\x7c\xb7\x28\xf9\xa1\xf1\xba\x25\xa0\x6b\x8b\x15\x23\x7c\x25\x7e\x14\x9d\x28\x5e\x06\xc1\x37\x15\xeb\xd5\xc2\x86\xf3\xcb\xe5\xb2\x3a\x04\x12\xa4\x9b\x55\xe3\x4e\xbc\x51\xc2\x53\xe0\xc6\x09\x89\x7e\x75\x0c\x6c\xb7\xe5\xa5\x70\x37\xd3\xce\x22\x31\x42\x2b\x48\x7d\xf5\xb8\xd7\xaf\x90\x12\x2f\x42\xfc\x18\x78\x7d\x6e\x5e\x90\x56\xc7\xf0\xa1\xab\x62\x84\xfa\xac\x8d\xfc\x8e\x3e\x68\x67\x21\xa5\x7b\xd5\x18\xd1\xca\x94\x16\x8b\x1b\xfc\x40\x35\xf1\xff\x93\xa7\xcc\x05\x9d\xf0\x40\x4a\x58\x17\xa0\x82\x58\x7c\xfd\xc7\x88\x1a\xcd\x06\x62\x5c\x3d\xf7\xb7\x94\x1e\x6e\x31\xf4\x3e\x47\xbe\x78\x3f\xf3\x0f\xeb\x45\xf9\x91\x72\xfc\xdb\xcd\x9e\xe5\xd5\xc6\x35\x2f\x21\xa7\x7c\xca\xd7\x61\x60\x48\x4f\x65\xf0\x09\xb2\x98\x52\x77\xa0\x65\xc5\xd0\x7b\x06\x8d\x11\x21\x54\x99\x55\x68\x8b\x9e\x41\xa0\xab\xc1\x8a\x49\x1d\x5a\x23\xae\x1b\xb0\xce\xe2\xd3\xc8\x37\xd6\x0f\x65\xc2\xa0\x27\xc8\xe7\xf2\x22\xbc\xd5\xf6\xc0\xc0\xbb\xbe\x3e\x3b\xfb\x0d\x4b\xdd\x0d\x3f\x5a\xb9\x2e\xfe\x14\x99\x7a\x2f\xf7\xe6\xac\x25\xcb\xc3\x7d\x76\xa7\x56\x34\xa4\x9d\x0d\xd3\x48\x0a\xf5\x41\xd1\x06\xfe\x5f\xaf\xff\x7b\x82\x8b\x96\xa4\x06\x63\xea\x33\x27\x34\x78\x40\x2b\xff\x86\x1c\x1b\xbd\x89\x0a\xad\x90\x52\xdb\xc3\x92\x5c\xbb\x81\xf7\xeb\xf6\x75\x46\xaf\x1e\x77\xf0\x9c\x75\x61\xcb\xd5\xe3\x5d\x84\x44\x6d\x70\xec\x55\x8c\x7c\x2e\x03\x79\xdd\xa2\x1c\x2c\xe5\x3a\xf4\x63\xe4\x74\x27\x5d\x44\x6a\x27\xaf\xbb\x2d\x2f\xdf\x37\x71\x9e\x0b\xde\x58\x64\x66\xb8\x25\xf6\xef\xf2\x47\x7f\x2c\x85\x6d\x94\xf3\x55\x20\xe1\xe9\x27\xc4\x19\x64\x9a\xf2\x15\x9d\xcc\x43\xdf\x0b\xe2\x6c\xbd\x69\x7c\x3a\x45\x7e\xfc\x7b\xfc\x0e\x00\x00\xff\xff\x04\x8a\x02\x92\x1b\x04\x00\x00") + +func pkgUiTemplatesBucketHtmlBytes() ([]byte, error) { + return bindataRead( + _pkgUiTemplatesBucketHtml, + "pkg/ui/templates/bucket.html", + ) +} + +func pkgUiTemplatesBucketHtml() (*asset, error) { + bytes, err := pkgUiTemplatesBucketHtmlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "pkg/ui/templates/bucket.html", size: 1051, mode: os.FileMode(420), modTime: time.Unix(1561717107, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _pkgUiTemplatesBucket_menuHtml = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x6c\x92\x31\x8f\x9c\x30\x10\x85\xfb\xfd\x15\x23\xa7\x76\xdc\x47\xb0\x45\xaa\x94\x29\x4e\x69\xa3\x31\x1e\x60\xb4\xde\xb1\x65\x0c\xd9\x08\xf1\xdf\x23\xc3\x72\x61\xb9\xab\xc0\x4f\x6f\xe6\xcd\x37\xf6\x3c\x3b\x6a\x59\x08\x94\xe0\xa4\x96\xe5\x52\x09\x4e\xd0\x78\x1c\x86\xba\x48\x16\x13\xb4\xfc\x20\xa7\x73\x88\xb0\x09\x9a\x1e\x11\xc5\xe9\xe1\xbe\x0b\x0e\xd3\x0d\x6c\xb7\x7e\xd5\xf5\x02\x00\x50\x39\x7e\xef\xd3\x04\xc9\xc8\x42\x49\xb7\x7e\x64\xf7\x74\xac\x2e\x3b\xe6\x1c\x04\xf2\xdf\x48\xb5\xda\x0e\xea\x35\x5e\xe7\xd0\x75\x9e\x92\x02\x87\x19\x9f\xa7\xd2\xd3\x7b\x8c\x03\xed\x32\xa6\x8e\x72\xad\xbe\x08\x4e\xba\xe4\x91\x64\x05\x98\x18\x9f\xd3\x92\xab\x55\x8b\xbe\x14\xac\x6a\xf1\xa4\xe0\xb7\x98\x53\x85\x47\x4b\xbe\x56\x6f\x6b\x54\x61\xe4\x0e\x33\x07\x39\x0c\xbe\x0e\x3f\x44\x94\xcf\x87\xd5\xdc\x14\x7b\x65\x8a\xe5\x80\x6b\x36\xc4\x83\x82\xa7\x06\x36\xa1\x38\x05\x7d\xa2\xb6\x56\xf3\x0c\x11\x73\xff\x33\x51\xcb\x0f\x58\x16\xa3\xae\x6f\x3d\x4a\x18\xe0\xfb\xd8\xdc\x28\xc3\x2f\xa6\x3f\x94\x2a\x83\x87\x8e\x65\xf1\xec\x4e\x5c\xaf\x21\xfb\xf2\xe0\x7d\x8b\x27\xb2\xd1\x9f\x2a\xca\xeb\x78\xf5\xac\x3e\xcf\x07\x9f\xe6\x4c\xf7\x4f\x5c\x1f\x38\xb5\x67\xb9\xed\x8c\x7d\xce\x71\xf8\x66\x4c\xc7\xb9\x1f\xed\xd7\x26\xdc\x0d\xdf\x63\x0a\x16\xad\x27\x4d\xd2\x99\xbc\x22\x2b\xd8\xef\xf8\xb7\xf5\x28\x37\x75\xfd\x41\x3e\xbe\xa0\xff\x5f\xb3\xe7\x13\x90\x19\xfd\xf1\x1a\x1c\x4f\xcf\x67\xba\xfd\x56\x46\x70\xba\x5e\xe6\x99\xc4\x2d\xcb\xe5\x5f\x00\x00\x00\xff\xff\x11\xd5\x16\x14\x16\x03\x00\x00") + +func pkgUiTemplatesBucket_menuHtmlBytes() ([]byte, error) { + return bindataRead( + _pkgUiTemplatesBucket_menuHtml, + "pkg/ui/templates/bucket_menu.html", + ) +} + +func pkgUiTemplatesBucket_menuHtml() (*asset, error) { + bytes, err := pkgUiTemplatesBucket_menuHtmlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "pkg/ui/templates/bucket_menu.html", size: 790, mode: os.FileMode(420), modTime: time.Unix(1560872416, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -197,7 +240,7 @@ func pkgUiTemplatesGraphHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/templates/graph.html", size: 2298, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/templates/graph.html", size: 2298, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -217,7 +260,7 @@ func pkgUiTemplatesQuery_menuHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/templates/query_menu.html", size: 1369, mode: os.FileMode(420), modTime: time.Unix(1559650443, 0)} + info := bindataFileInfo{name: "pkg/ui/templates/query_menu.html", size: 1369, mode: os.FileMode(420), modTime: time.Unix(1559826401, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -237,7 +280,7 @@ func pkgUiTemplatesRule_menuHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/templates/rule_menu.html", size: 966, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/templates/rule_menu.html", size: 966, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -257,7 +300,7 @@ func pkgUiTemplatesRulesHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/templates/rules.html", size: 1946, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/templates/rules.html", size: 1946, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -277,7 +320,7 @@ func pkgUiTemplatesStatusHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/templates/status.html", size: 1272, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/templates/status.html", size: 1272, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -297,7 +340,7 @@ func pkgUiTemplatesStoresHtml() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/templates/stores.html", size: 2082, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/templates/stores.html", size: 2082, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -317,7 +360,7 @@ func pkgUiStaticCssAlertsCss() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/css/alerts.css", size: 401, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/css/alerts.css", size: 401, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -337,7 +380,7 @@ func pkgUiStaticCssGraphCss() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/css/graph.css", size: 3844, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/css/graph.css", size: 3844, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -357,7 +400,7 @@ func pkgUiStaticCssPrometheusCss() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/css/prometheus.css", size: 470, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/css/prometheus.css", size: 470, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -377,7 +420,7 @@ func pkgUiStaticCssRulesCss() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/css/rules.css", size: 195, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/css/rules.css", size: 195, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -397,7 +440,7 @@ func pkgUiStaticImgAjaxLoaderGif() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/img/ajax-loader.gif", size: 847, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/img/ajax-loader.gif", size: 847, mode: os.FileMode(420), modTime: time.Unix(1556637801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -417,7 +460,7 @@ func pkgUiStaticImgFaviconIco() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/img/favicon.ico", size: 15886, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/img/favicon.ico", size: 15886, mode: os.FileMode(420), modTime: time.Unix(1556637801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -437,7 +480,27 @@ func pkgUiStaticJsAlertsJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/js/alerts.js", size: 1152, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/js/alerts.js", size: 1152, mode: os.FileMode(420), modTime: time.Unix(1556637801, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _pkgUiStaticJsBucketJs = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\x56\x4d\x6f\xe3\x36\x13\xbe\xfb\x57\xcc\xfa\x35\x20\x09\xeb\x57\x76\x80\x9e\xe2\x28\xc0\x36\xbb\x87\x16\x8b\xa6\xd8\xe4\xd4\x20\x80\x69\x71\x64\xb1\xa6\x48\x95\x1c\xc5\xf1\x1a\xfa\xef\x05\x29\xc9\x96\x1d\x25\x9b\x2d\xe1\x83\x45\x72\x9e\xf9\x7a\x38\x33\x6b\xad\xd7\x12\xe3\x34\x67\x86\x6c\x2c\x35\xe3\x61\x90\x56\xc6\xa0\xa2\x60\x0a\xfb\x11\x00\x40\x50\xb2\x74\xc3\xd6\x68\x83\x4b\x78\x08\x48\x14\x28\x85\xc2\xe0\x71\x54\x47\x8b\xd1\x29\x80\x45\xba\x55\x5f\x35\xe3\x37\x4c\xca\x15\x4b\x37\x21\x37\x6c\x1b\x2d\x46\xa3\xac\x52\x29\x09\xad\xc0\x6d\x84\x51\x0b\x2d\x32\x08\x29\x67\x4a\xdb\xd8\x60\x66\xd0\xe6\xc8\x3f\x11\x24\x09\x8c\xe7\xf3\xf9\xc5\xff\xfd\xef\x7e\x3e\xbf\xf4\xbf\xbf\xc6\x9d\x9c\x5b\xad\x1c\x1a\x03\x09\x8c\xef\x76\x2a\xcd\x8d\x56\xe2\xbb\x50\x6b\x58\x49\x9d\x6e\x2c\x64\x46\x17\x60\xb0\xd0\x84\x60\x49\x1b\xb6\xc6\xf1\xc2\x03\xd4\xa3\x73\xfd\x0e\xe7\x43\x02\xaa\x92\xb2\xaf\x65\x12\x8e\xff\x87\xc6\x8c\xa3\xd8\xe6\x7a\x1b\x46\x71\x26\x14\x0f\x83\x98\x49\x34\x14\x44\x31\xe1\x33\x85\xbf\xdf\xdd\xfe\x11\x5b\x32\x42\xad\x45\xb6\xeb\x21\x4e\x3d\xde\x14\x7e\x89\xa2\xc5\x01\xd2\x22\xdd\x8b\x02\x75\x45\x61\x17\x95\xb0\xaf\xd2\x2d\xa9\x53\xe6\x0e\x62\x83\x3e\x29\x3d\xf1\x7a\x0a\x17\xf3\xf9\x7c\xee\xa2\xea\xbf\x01\xa5\xc5\x41\x93\x73\xc1\x31\xec\xee\xb9\xf5\xc4\x0c\xa4\x5a\x11\x13\x0a\x5d\xd8\xb8\x4e\xab\x02\x15\xc5\x6b\xa4\x2f\x12\xdd\xdf\x5f\x77\xbf\xf1\x30\xb8\xd1\x45\xc9\xbc\x69\x36\xe8\xe9\xf6\xf2\x2e\xd5\x90\x80\xc2\x2d\xb4\xd9\x7f\x12\xb6\x62\x52\x7c\x6f\x4c\xbe\x6f\x19\x12\x1e\x34\x9d\x21\x70\x46\xec\x9e\xad\x24\xbe\x85\xf2\xb9\xbb\x14\x9e\x49\x93\x20\x89\x16\x12\xd8\xd7\x3d\xcf\x0e\x98\x31\xe3\xfc\x46\xcb\xaa\x50\xe1\x9e\x76\x25\x5e\x42\xd0\x64\x26\x98\x82\xe0\x97\x10\x7c\xc3\x52\x8a\x94\x05\x75\x0f\xf7\xfd\xd2\x5f\xd9\x0a\xe5\xbb\x65\x39\x23\xec\x24\xef\x88\x19\xfa\x4f\x92\x5f\x14\xf7\x72\xc3\x82\xdf\xf4\xd6\x76\x94\x6b\x78\x7f\xc2\xa4\xb8\x60\xe5\x91\x67\xfc\x9c\x68\x6e\xcd\x66\x70\xef\x82\x0a\xc2\x02\xe5\x08\x99\x30\x96\x20\xf5\x06\x81\xce\xfc\x5e\xf7\xec\xe3\x01\xe9\x21\xc0\x4f\x50\x29\xf1\x4f\x85\xf0\xa7\xd1\x05\x52\x8e\x95\x05\xe9\x62\xe7\xde\x2d\x81\xe0\xa8\x48\x64\x02\x2d\x20\x4b\x73\xb0\x39\x33\xdc\xe9\xaf\x2c\xf2\x21\x3c\x66\x5b\x33\xbc\x9d\x19\x94\x06\x2d\x2a\x9a\x82\xa6\x1c\xcd\x56\x58\x04\x26\x65\xa3\xc2\x02\x33\x08\x5c\xd8\x52\xb2\xdd\x30\x1c\x3e\x13\x1a\xc5\xa4\xdc\x39\x64\x06\x12\xd7\xa8\xf8\x4b\xe7\x1a\x7d\x09\xbc\xfa\x50\xbb\xd5\xab\x24\x8d\x9b\x1f\x12\x18\x8f\x5f\xbb\x0d\x2d\x97\x37\xb8\x73\xaf\x30\xee\x4b\xda\x87\xfe\xd7\xe3\xe2\x55\x00\xa7\xd2\x03\x24\x50\x29\x8e\x99\x50\x38\x98\xde\x13\x7f\x72\xa3\xb7\xb0\xf4\x2c\x86\xc9\xbe\xaf\xa9\x06\xa5\x09\x32\x5d\x29\x0e\x42\xc1\x64\x7f\xbb\xfa\x1b\x53\x8a\x37\xb8\xb3\xe1\x99\x89\x51\xbd\x7c\xdd\xae\x17\x05\x69\x68\x19\xa4\xca\x28\x17\x80\x37\x80\x06\x4f\x7e\x08\xdf\xe5\xac\x29\x14\x0f\xc7\xba\x7c\xee\xc4\x0f\x62\xdb\xe2\xfc\x4c\x74\x5b\xcd\x77\x5e\x65\xd8\x0f\x60\x63\x4c\x14\x4b\x54\x6b\xca\xe1\x23\x5c\x44\xaf\x6b\x3f\x60\xbd\x69\x7d\xe7\xe2\xcf\x06\x10\x8e\xe1\x7f\x43\xfe\xa5\x6c\x7d\xd2\x4a\xba\xd5\xb0\x3d\x81\xa5\xbc\x84\xc9\x9e\xc7\xe9\xa1\x73\xc4\x12\x9f\x50\xd6\x53\x30\x68\x9b\xb3\xd6\x01\xae\xb7\xca\xb2\xa2\x94\x18\x1b\xb4\x5a\x56\xee\xf6\x10\xa3\x5a\x2b\x1f\xbc\x99\xd3\x46\xd5\xd4\xb7\x8c\xcf\x8c\x30\xe4\x71\x21\x94\xeb\x36\xd1\xe9\x26\x7b\xf6\x9b\x67\xe9\xad\xa3\xbe\xf9\xbe\x8b\xc5\x7e\x18\x39\x54\xd3\xfe\xf9\x6c\x06\x77\xb9\xde\x1e\x0a\x45\x5b\x21\x1c\x31\x94\xee\xed\x36\xf5\x66\x8b\x06\x5d\x5f\x3f\x16\x90\x17\xf5\x20\x19\xaa\x07\xae\x55\x37\xc0\x87\x01\xe3\xd4\xe8\x4c\x1b\x08\x25\x12\x3c\x6c\x70\x37\x85\x27\x26\x2b\x7c\x74\x35\xb9\xe5\x16\x2a\x32\x02\x0f\xf4\x1a\x22\xa8\x7b\xf0\x09\x2c\xaf\xc8\x5c\xc3\x15\xe5\x60\x53\x5d\x62\x32\x36\x7a\x3b\xbe\x9e\xec\x3d\x62\x7d\x35\xa3\xdc\x9d\xf2\xeb\xc9\x7e\x83\x3b\xf7\xcd\xaf\xe1\x6a\x46\xe6\x7a\x20\x2d\x47\xab\x81\x7c\x1b\xa7\x95\xe6\xbb\x71\x14\xb3\xb2\x44\xc5\x43\xa3\xb7\x67\x6e\x1c\xc9\x54\xb7\xe3\x57\xdd\x1b\x09\x8f\x1c\x2f\x58\xd9\xb9\xe0\x5b\xbd\x9b\xec\xda\x89\xed\xbd\x91\x70\x10\x27\x63\x22\x7c\x4c\x60\xd9\xb8\xe5\x58\xd8\x38\x0c\xcb\x6e\x0e\xec\xf1\x8c\x16\xa3\x7a\xf4\x6f\x00\x00\x00\xff\xff\x46\xd5\x4b\x47\x12\x0b\x00\x00") + +func pkgUiStaticJsBucketJsBytes() ([]byte, error) { + return bindataRead( + _pkgUiStaticJsBucketJs, + "pkg/ui/static/js/bucket.js", + ) +} + +func pkgUiStaticJsBucketJs() (*asset, error) { + bytes, err := pkgUiStaticJsBucketJsBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "pkg/ui/static/js/bucket.js", size: 2834, mode: os.FileMode(420), modTime: time.Unix(1561655919, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -457,7 +520,7 @@ func pkgUiStaticJsGraphJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/js/graph.js", size: 37691, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/js/graph.js", size: 37691, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -477,7 +540,7 @@ func pkgUiStaticJsGraph_templateHandlebar() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/js/graph_template.handlebar", size: 9000, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/js/graph_template.handlebar", size: 9000, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -497,7 +560,7 @@ func pkgUiStaticVendorBootstrap413CssBootstrapGridCss() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-grid.css", size: 37644, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-grid.css", size: 37644, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -517,7 +580,7 @@ func pkgUiStaticVendorBootstrap413CssBootstrapGridMinCss() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-grid.min.css", size: 28977, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-grid.min.css", size: 28977, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -537,7 +600,7 @@ func pkgUiStaticVendorBootstrap413CssBootstrapRebootCss() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-reboot.css", size: 4896, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-reboot.css", size: 4896, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -557,7 +620,7 @@ func pkgUiStaticVendorBootstrap413CssBootstrapRebootMinCss() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-reboot.min.css", size: 4019, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-reboot.min.css", size: 4019, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -577,7 +640,7 @@ func pkgUiStaticVendorBootstrap413CssBootstrapMinCss() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/css/bootstrap.min.css", size: 140936, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/css/bootstrap.min.css", size: 140936, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -597,7 +660,7 @@ func pkgUiStaticVendorBootstrap413JsBootstrapBundleJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/js/bootstrap.bundle.js", size: 212345, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/js/bootstrap.bundle.js", size: 212345, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -617,7 +680,7 @@ func pkgUiStaticVendorBootstrap413JsBootstrapBundleMinJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/js/bootstrap.bundle.min.js", size: 70966, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/js/bootstrap.bundle.min.js", size: 70966, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -637,7 +700,7 @@ func pkgUiStaticVendorBootstrap413JsBootstrapMinJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/js/bootstrap.min.js", size: 51039, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap-4.1.3/js/bootstrap.min.js", size: 51039, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -657,7 +720,7 @@ func pkgUiStaticVendorBootstrap3TypeaheadBootstrap3TypeaheadMinJs() (*asset, err return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap3-typeahead/bootstrap3-typeahead.min.js", size: 13238, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap3-typeahead/bootstrap3-typeahead.min.js", size: 13238, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -677,7 +740,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsCssBootstrapGlyphiconsCss() (*asset, e return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/css/bootstrap-glyphicons.css", size: 14523, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/css/bootstrap-glyphicons.css", size: 14523, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -697,7 +760,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsCssBootstrapGlyphiconsMinCss() (*asset return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/css/bootstrap-glyphicons.min.css", size: 11830, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/css/bootstrap-glyphicons.min.css", size: 11830, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -717,7 +780,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaBrands400Eot() (*ass return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.eot", size: 98620, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.eot", size: 98620, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -737,7 +800,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaBrands400Svg() (*ass return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.svg", size: 507478, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.svg", size: 507478, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -757,7 +820,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaBrands400Ttf() (*ass return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.ttf", size: 98384, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.ttf", size: 98384, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -777,7 +840,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaBrands400Woff() (*as return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.woff", size: 63712, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.woff", size: 63712, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -797,7 +860,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaBrands400Woff2() (*a return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.woff2", size: 54420, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-brands-400.woff2", size: 54420, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -817,7 +880,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaRegular400Eot() (*as return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.eot", size: 31156, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.eot", size: 31156, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -837,7 +900,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaRegular400Svg() (*as return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.svg", size: 107199, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.svg", size: 107199, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -857,7 +920,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaRegular400Ttf() (*as return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.ttf", size: 30928, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.ttf", size: 30928, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -877,7 +940,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaRegular400Woff() (*a return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.woff", size: 14712, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.woff", size: 14712, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -897,7 +960,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaRegular400Woff2() (* return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.woff2", size: 12220, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-regular-400.woff2", size: 12220, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -917,7 +980,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaSolid900Eot() (*asse return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.eot", size: 102152, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.eot", size: 102152, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -937,7 +1000,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaSolid900Svg() (*asse return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.svg", size: 378215, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.svg", size: 378215, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -957,7 +1020,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaSolid900Ttf() (*asse return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.ttf", size: 101932, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.ttf", size: 101932, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -977,7 +1040,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaSolid900Woff() (*ass return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.woff", size: 48704, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.woff", size: 48704, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -997,7 +1060,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsFontawesomeFaSolid900Woff2() (*as return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.woff2", size: 38784, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/fontawesome/fa-solid-900.woff2", size: 38784, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1017,7 +1080,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsGlyphiconsGlyphiconsHalflingsRegu return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.eot", size: 20127, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.eot", size: 20127, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1037,7 +1100,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsGlyphiconsGlyphiconsHalflingsRegu return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.svg", size: 108738, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.svg", size: 108738, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1057,7 +1120,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsGlyphiconsGlyphiconsHalflingsRegu return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.ttf", size: 45404, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.ttf", size: 45404, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1077,7 +1140,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsGlyphiconsGlyphiconsHalflingsRegu return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.woff", size: 23424, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.woff", size: 23424, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1097,7 +1160,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsFontsGlyphiconsGlyphiconsHalflingsRegu return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.woff2", size: 18028, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/fonts/glyphicons/glyphicons-halflings-regular.woff2", size: 18028, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1117,7 +1180,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsMapsGlyphiconsFontawesomeCss() (*asset return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/maps/glyphicons-fontawesome.css", size: 51062, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/maps/glyphicons-fontawesome.css", size: 51062, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1137,7 +1200,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsMapsGlyphiconsFontawesomeLess() (*asse return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/maps/glyphicons-fontawesome.less", size: 53867, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/maps/glyphicons-fontawesome.less", size: 53867, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1157,7 +1220,7 @@ func pkgUiStaticVendorBootstrap4GlyphiconsMapsGlyphiconsFontawesomeMinCss() (*as return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/maps/glyphicons-fontawesome.min.css", size: 42307, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/bootstrap4-glyphicons/maps/glyphicons-fontawesome.min.css", size: 42307, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1177,7 +1240,7 @@ func pkgUiStaticVendorEonasdanBootstrapDatetimepickerBootstrapDatetimepickerMinC return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/eonasdan-bootstrap-datetimepicker/bootstrap-datetimepicker.min.css", size: 7771, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/eonasdan-bootstrap-datetimepicker/bootstrap-datetimepicker.min.css", size: 7771, mode: os.FileMode(420), modTime: time.Unix(1556637801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1197,7 +1260,7 @@ func pkgUiStaticVendorEonasdanBootstrapDatetimepickerBootstrapDatetimepickerMinJ return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/eonasdan-bootstrap-datetimepicker/bootstrap-datetimepicker.min.js", size: 48881, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/eonasdan-bootstrap-datetimepicker/bootstrap-datetimepicker.min.js", size: 48881, mode: os.FileMode(420), modTime: time.Unix(1556637801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1217,7 +1280,7 @@ func pkgUiStaticVendorFuzzyFuzzyJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/fuzzy/fuzzy.js", size: 5669, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/fuzzy/fuzzy.js", size: 5669, mode: os.FileMode(420), modTime: time.Unix(1556637801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1237,7 +1300,7 @@ func pkgUiStaticVendorJsJquery331MinJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/js/jquery-3.3.1.min.js", size: 86927, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/js/jquery-3.3.1.min.js", size: 86927, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1257,7 +1320,7 @@ func pkgUiStaticVendorJsJqueryHotkeysJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/js/jquery.hotkeys.js", size: 4490, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/js/jquery.hotkeys.js", size: 4490, mode: os.FileMode(420), modTime: time.Unix(1556637801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1277,7 +1340,7 @@ func pkgUiStaticVendorJsJqueryMinJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/js/jquery.min.js", size: 86671, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/js/jquery.min.js", size: 86671, mode: os.FileMode(420), modTime: time.Unix(1556637801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1297,7 +1360,7 @@ func pkgUiStaticVendorJsJquerySelectionJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/js/jquery.selection.js", size: 12881, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/js/jquery.selection.js", size: 12881, mode: os.FileMode(420), modTime: time.Unix(1556637801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1317,7 +1380,7 @@ func pkgUiStaticVendorJsPopperMinJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/js/popper.min.js", size: 19236, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/js/popper.min.js", size: 19236, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1337,7 +1400,7 @@ func pkgUiStaticVendorMomentMomentTimezoneWithDataMinJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/moment/moment-timezone-with-data.min.js", size: 184495, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/moment/moment-timezone-with-data.min.js", size: 184495, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1357,7 +1420,7 @@ func pkgUiStaticVendorMomentMomentMinJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/moment/moment.min.js", size: 51825, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/moment/moment.min.js", size: 51825, mode: os.FileMode(420), modTime: time.Unix(1559745993, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1377,7 +1440,7 @@ func pkgUiStaticVendorMustacheMustacheMinJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/mustache/mustache.min.js", size: 9528, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/mustache/mustache.min.js", size: 9528, mode: os.FileMode(420), modTime: time.Unix(1556637801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1397,7 +1460,7 @@ func pkgUiStaticVendorRickshawRickshawMinCss() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/rickshaw/rickshaw.min.css", size: 6102, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/rickshaw/rickshaw.min.css", size: 6102, mode: os.FileMode(420), modTime: time.Unix(1556637801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1417,7 +1480,7 @@ func pkgUiStaticVendorRickshawRickshawMinJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/rickshaw/rickshaw.min.js", size: 76322, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/rickshaw/rickshaw.min.js", size: 76322, mode: os.FileMode(420), modTime: time.Unix(1556637801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1437,7 +1500,7 @@ func pkgUiStaticVendorRickshawVendorD3LayoutMinJs() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/rickshaw/vendor/d3.layout.min.js", size: 17514, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/rickshaw/vendor/d3.layout.min.js", size: 17514, mode: os.FileMode(420), modTime: time.Unix(1556637801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1457,7 +1520,7 @@ func pkgUiStaticVendorRickshawVendorD3V3Js() (*asset, error) { return nil, err } - info := bindataFileInfo{name: "pkg/ui/static/vendor/rickshaw/vendor/d3.v3.js", size: 144718, mode: os.FileMode(420), modTime: time.Unix(1559649862, 0)} + info := bindataFileInfo{name: "pkg/ui/static/vendor/rickshaw/vendor/d3.v3.js", size: 144718, mode: os.FileMode(420), modTime: time.Unix(1556637801, 0)} a := &asset{bytes: bytes, info: info} return a, nil } @@ -1516,6 +1579,8 @@ func AssetNames() []string { var _bindata = map[string]func() (*asset, error){ "pkg/ui/templates/_base.html": pkgUiTemplates_baseHtml, "pkg/ui/templates/alerts.html": pkgUiTemplatesAlertsHtml, + "pkg/ui/templates/bucket.html": pkgUiTemplatesBucketHtml, + "pkg/ui/templates/bucket_menu.html": pkgUiTemplatesBucket_menuHtml, "pkg/ui/templates/graph.html": pkgUiTemplatesGraphHtml, "pkg/ui/templates/query_menu.html": pkgUiTemplatesQuery_menuHtml, "pkg/ui/templates/rule_menu.html": pkgUiTemplatesRule_menuHtml, @@ -1529,6 +1594,7 @@ var _bindata = map[string]func() (*asset, error){ "pkg/ui/static/img/ajax-loader.gif": pkgUiStaticImgAjaxLoaderGif, "pkg/ui/static/img/favicon.ico": pkgUiStaticImgFaviconIco, "pkg/ui/static/js/alerts.js": pkgUiStaticJsAlertsJs, + "pkg/ui/static/js/bucket.js": pkgUiStaticJsBucketJs, "pkg/ui/static/js/graph.js": pkgUiStaticJsGraphJs, "pkg/ui/static/js/graph_template.handlebar": pkgUiStaticJsGraph_templateHandlebar, "pkg/ui/static/vendor/bootstrap-4.1.3/css/bootstrap-grid.css": pkgUiStaticVendorBootstrap413CssBootstrapGridCss, @@ -1638,6 +1704,7 @@ var _bintree = &bintree{nil, map[string]*bintree{ }}, "js": &bintree{nil, map[string]*bintree{ "alerts.js": &bintree{pkgUiStaticJsAlertsJs, map[string]*bintree{}}, + "bucket.js": &bintree{pkgUiStaticJsBucketJs, map[string]*bintree{}}, "graph.js": &bintree{pkgUiStaticJsGraphJs, map[string]*bintree{}}, "graph_template.handlebar": &bintree{pkgUiStaticJsGraph_templateHandlebar, map[string]*bintree{}}, }}, @@ -1728,14 +1795,16 @@ var _bintree = &bintree{nil, map[string]*bintree{ }}, }}, "templates": &bintree{nil, map[string]*bintree{ - "_base.html": &bintree{pkgUiTemplates_baseHtml, map[string]*bintree{}}, - "alerts.html": &bintree{pkgUiTemplatesAlertsHtml, map[string]*bintree{}}, - "graph.html": &bintree{pkgUiTemplatesGraphHtml, map[string]*bintree{}}, - "query_menu.html": &bintree{pkgUiTemplatesQuery_menuHtml, map[string]*bintree{}}, - "rule_menu.html": &bintree{pkgUiTemplatesRule_menuHtml, map[string]*bintree{}}, - "rules.html": &bintree{pkgUiTemplatesRulesHtml, map[string]*bintree{}}, - "status.html": &bintree{pkgUiTemplatesStatusHtml, map[string]*bintree{}}, - "stores.html": &bintree{pkgUiTemplatesStoresHtml, map[string]*bintree{}}, + "_base.html": &bintree{pkgUiTemplates_baseHtml, map[string]*bintree{}}, + "alerts.html": &bintree{pkgUiTemplatesAlertsHtml, map[string]*bintree{}}, + "bucket.html": &bintree{pkgUiTemplatesBucketHtml, map[string]*bintree{}}, + "bucket_menu.html": &bintree{pkgUiTemplatesBucket_menuHtml, map[string]*bintree{}}, + "graph.html": &bintree{pkgUiTemplatesGraphHtml, map[string]*bintree{}}, + "query_menu.html": &bintree{pkgUiTemplatesQuery_menuHtml, map[string]*bintree{}}, + "rule_menu.html": &bintree{pkgUiTemplatesRule_menuHtml, map[string]*bintree{}}, + "rules.html": &bintree{pkgUiTemplatesRulesHtml, map[string]*bintree{}}, + "status.html": &bintree{pkgUiTemplatesStatusHtml, map[string]*bintree{}}, + "stores.html": &bintree{pkgUiTemplatesStoresHtml, map[string]*bintree{}}, }}, }}, }}, diff --git a/pkg/ui/bucket.go b/pkg/ui/bucket.go new file mode 100644 index 0000000000..0e4d3a91d1 --- /dev/null +++ b/pkg/ui/bucket.go @@ -0,0 +1,49 @@ +package ui + +import ( + "html/template" + "net/http" + "time" + + "github.com/go-kit/kit/log" + "github.com/prometheus/client_golang/prometheus" + "github.com/prometheus/common/route" +) + +// Bucket is a web UI representing state of buckets as a timeline. +type Bucket struct { + *BaseUI + // Unique Prometheus label that identifies each shard, used as the title. If + // not present, all labels are displayed externally as a legend. + Label string + Blocks template.JS + RefreshedAt time.Time + Err error +} + +func NewBucketUI(logger log.Logger, label string) *Bucket { + return &Bucket{ + BaseUI: NewBaseUI(logger, "bucket_menu.html", queryTmplFuncs()), + Blocks: "[]", + Label: label, + } +} + +// Register registers http routes for bucket UI. +func (b *Bucket) Register(r *route.Router) { + instrf := prometheus.InstrumentHandlerFunc + + r.Get("/", instrf("root", b.root)) + r.Get("/static/*filepath", instrf("static", b.serveStaticAsset)) +} + +// Handle / of bucket UIs +func (b *Bucket) root(w http.ResponseWriter, r *http.Request) { + b.executeTemplate(w, "bucket.html", "", b) +} + +func (b *Bucket) Set(data string, err error) { + b.RefreshedAt = time.Now() + b.Blocks = template.JS(string(data)) + b.Err = err +} diff --git a/pkg/ui/static/js/bucket.js b/pkg/ui/static/js/bucket.js new file mode 100644 index 0000000000..9221301d76 --- /dev/null +++ b/pkg/ui/static/js/bucket.js @@ -0,0 +1,78 @@ +google.charts.load('current', { + 'packages': ['timeline'] +}); +google.charts.setOnLoadCallback(draw); + +function draw() { + if (thanos.refreshedAt == "0001-01-01T00:00:00Z") { + thanos.err = "Synchronizing blocks from remote storage"; + } + + if (thanos.err != null) { + $("#err").show().find('.alert').text(JSON.stringify(thanos.err, null, 4)); + setTimeout(function() { + location.reload(); + }, 10000); + + } else { + $("#err").hide(); + + var container = document.getElementById('Compactions'); + var chart = new google.visualization.Timeline(container); + var dataTable = new google.visualization.DataTable(); + var titles = {}; + + dataTable.addColumn({type: 'string', id: 'Replica'}); + dataTable.addColumn({type: 'string', id: 'Label'}); + dataTable.addColumn({type: 'date', id: 'Start'}); + dataTable.addColumn({type: 'date', id: 'End'}); + + dataTable.addRows(thanos.blocks + .map(function(d) { + // Title is the first column of the timeline. + // + // A unique Prometheus label that identifies each shard is used + // as the title if present, otherwise all labels are displayed + // externally as a legend. + title = function() { + if (thanos.label != "") { + var key = d.thanos.labels[thanos.label]; + if (key == undefined) { + throw `Label ${thanos.label} not found in ${Object.keys(d.thanos.labels)}`; + } else { + return key; + } + } else { + title = titles[stringify(d.thanos.labels)]; + if (title == undefined) { + title = String(Object.keys(titles).length + 1); + titles[stringify(d.thanos.labels)] = title; + } + return title; + } + }(); + + label = `l: ${d.compaction.level}, res: ${d.thanos.downsample.resolution}`; + return [title, label, new Date(d.minTime), new Date(d.maxTime)]; + })); + + chart.draw(dataTable); + + // Show external legend if no external labels were set. + if (thanos.label == "") { + $("#legend").show(); + for (let [key, value] of Object.entries(titles)) { + row = ` ${value} ${key} `; + $("#legend table tbody").append(row); + } + } + } +} + +function stringify(map) { + var t = ""; + for (let [key, value] of Object.entries(map)) { + t += `${key}: ${value} `; + } + return t; +} diff --git a/pkg/ui/templates/bucket.html b/pkg/ui/templates/bucket.html new file mode 100644 index 0000000000..88031f4fc6 --- /dev/null +++ b/pkg/ui/templates/bucket.html @@ -0,0 +1,40 @@ +{{define "head"}} + + + + +{{end}} + +{{define "content"}} + + + + +
+ + + + + + +{{end}} diff --git a/pkg/ui/templates/bucket_menu.html b/pkg/ui/templates/bucket_menu.html new file mode 100644 index 0000000000..47e8d011c4 --- /dev/null +++ b/pkg/ui/templates/bucket_menu.html @@ -0,0 +1,17 @@ +{{define "nav"}} + +{{end}} diff --git a/scripts/genflagdocs.sh b/scripts/genflagdocs.sh index ffa77fd9c9..c4584d2a8e 100755 --- a/scripts/genflagdocs.sh +++ b/scripts/genflagdocs.sh @@ -39,7 +39,7 @@ for x in "${commands[@]}"; do ./thanos "${x}" --help &> "docs/components/flags/${x}.txt" done -bucketCommands=("verify" "ls" "inspect") +bucketCommands=("verify" "ls" "inspect" "web") for x in "${bucketCommands[@]}"; do ./thanos bucket "${x}" --help &> "docs/components/flags/bucket_${x}.txt" done