From 92a633a7cb0a6ab41a2dfb7784b82824d21a00f7 Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Thu, 17 May 2018 10:53:23 +0200 Subject: [PATCH 1/8] cmd/geth: add flags for metrics export --- cmd/geth/main.go | 14 +++++++++ cmd/utils/flags.go | 67 +++++++++++++++++++++++++++++++++++++++++- dashboard/dashboard.go | 28 ++++++++++++++++-- 3 files changed, 106 insertions(+), 3 deletions(-) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 09d9c493d1..57271e4de2 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -140,6 +140,15 @@ var ( utils.WhisperMaxMessageSizeFlag, utils.WhisperMinPOWFlag, } + + metricsFlags = []cli.Flag{ + utils.MetricsEnableInfluxDBExportFlag, + utils.MetricsInfluxDBEndpointFlag, + utils.MetricsInfluxDBDatabaseFlag, + utils.MetricsInfluxDBUsernameFlag, + utils.MetricsInfluxDBPasswordFlag, + utils.MetricsInfluxDBHostTagFlag, + } ) func init() { @@ -182,12 +191,17 @@ func init() { app.Flags = append(app.Flags, consoleFlags...) app.Flags = append(app.Flags, debug.Flags...) app.Flags = append(app.Flags, whisperFlags...) + app.Flags = append(app.Flags, metricsFlags...) app.Before = func(ctx *cli.Context) error { runtime.GOMAXPROCS(runtime.NumCPU()) if err := debug.Setup(ctx); err != nil { return err } + + // Start metrics export if enabled + utils.SetupMetrics(ctx) + // Start system runtime metrics collection go metrics.CollectProcessMetrics(3 * time.Second) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index ef5f6a9f08..e10e1d82d0 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -27,6 +27,7 @@ import ( "runtime" "strconv" "strings" + "time" "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -48,6 +49,7 @@ import ( "github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" + "github.com/ethereum/go-ethereum/metrics/influxdb" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p/discover" @@ -532,6 +534,41 @@ var ( Usage: "Minimum POW accepted", Value: whisper.DefaultMinimumPoW, } + + // Metrics flags + MetricsEnableInfluxDBExportFlag = cli.BoolFlag{ + Name: "metrics.influxdb.export", + Usage: "Enable metrics export/push to an external InfluxDB database", + } + MetricsInfluxDBEndpointFlag = cli.StringFlag{ + Name: "metrics.influxdb.endpoint", + Usage: "Metrics InfluxDB endpoint", + Value: "http://127.0.0.1:8086", + } + MetricsInfluxDBDatabaseFlag = cli.StringFlag{ + Name: "metrics.influxdb.database", + Usage: "Metrics InfluxDB database", + Value: "metrics", + } + MetricsInfluxDBUsernameFlag = cli.StringFlag{ + Name: "metrics.influxdb.username", + Usage: "Metrics InfluxDB username", + Value: "", + } + MetricsInfluxDBPasswordFlag = cli.StringFlag{ + Name: "metrics.influxdb.password", + Usage: "Metrics InfluxDB password", + Value: "", + } + // The `host` tag is part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB. + // It is used so that we can group all nodes and average a measurement across all of them, but also so + // that we can select a specific node and inspect its measurements. + // https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key + MetricsInfluxDBHostTagFlag = cli.StringFlag{ + Name: "metrics.influxdb.host.tag", + Usage: "Metrics InfluxDB `host` tag attached to all measurements", + Value: "localhost", + } ) // MakeDataDir retrieves the currently requested data directory, terminating @@ -1145,7 +1182,14 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) { // RegisterDashboardService adds a dashboard to the stack. func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config, commit string) { stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { - return dashboard.New(cfg, commit) + // Retrieve both eth and les services + var ethServ *eth.Ethereum + ctx.Service(ðServ) + + var lesServ *les.LightEthereum + ctx.Service(&lesServ) + + return dashboard.New(cfg, commit, ethServ, lesServ) }) } @@ -1181,6 +1225,27 @@ func SetupNetwork(ctx *cli.Context) { params.TargetGasLimit = ctx.GlobalUint64(TargetGasLimitFlag.Name) } +func SetupMetrics(ctx *cli.Context) { + if metrics.Enabled { + log.Info("Enabling metrics collection") + var ( + enableExport = ctx.GlobalBool(MetricsEnableInfluxDBExportFlag.Name) + endpoint = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name) + database = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name) + username = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name) + password = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name) + hosttag = ctx.GlobalString(MetricsInfluxDBHostTagFlag.Name) + ) + + if enableExport { + log.Info("Enabling metrics export to InfluxDB") + go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", map[string]string{ + "host": hosttag, + }) + } + } +} + // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { var ( diff --git a/dashboard/dashboard.go b/dashboard/dashboard.go index 399fa34c08..752f23a17c 100644 --- a/dashboard/dashboard.go +++ b/dashboard/dashboard.go @@ -33,6 +33,8 @@ import ( "time" "github.com/elastic/gosigar" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/p2p" @@ -64,6 +66,9 @@ type Dashboard struct { commit string lock sync.RWMutex // Lock protecting the dashboard's internals + ethServ *eth.Ethereum + lesServ *les.LightEthereum + quit chan chan error // Channel used for graceful exit wg sync.WaitGroup } @@ -76,7 +81,7 @@ type client struct { } // New creates a new dashboard instance with the given configuration. -func New(config *Config, commit string) (*Dashboard, error) { +func New(config *Config, commit string, _ethServ *eth.Ethereum, _lesserv *les.LightEthereum) (*Dashboard, error) { now := time.Now() db := &Dashboard{ conns: make(map[uint32]*client), @@ -92,7 +97,9 @@ func New(config *Config, commit string) (*Dashboard, error) { DiskRead: emptyChartEntries(now, diskReadSampleLimit, config.Refresh), DiskWrite: emptyChartEntries(now, diskWriteSampleLimit, config.Refresh), }, - commit: commit, + commit: commit, + ethServ: _ethServ, + lesServ: _lesserv, } return db, nil } @@ -306,6 +313,23 @@ func (db *Dashboard) collectData() { prevDiskRead = curDiskRead prevDiskWrite = curDiskWrite + // extract metrics from downloaded and push to registry + p := db.ethServ.Downloader().Progress() + + metrics.GetOrRegisterGauge("currentBlock", nil).Update(int64(p.CurrentBlock)) + metrics.GetOrRegisterGauge("startingBlock", nil).Update(int64(p.StartingBlock)) + metrics.GetOrRegisterGauge("highestBlock", nil).Update(int64(p.HighestBlock)) + metrics.GetOrRegisterGauge("pulledStates", nil).Update(int64(p.PulledStates)) + metrics.GetOrRegisterGauge("knownStates", nil).Update(int64(p.KnownStates)) + + syncing := db.ethServ.BlockChain().CurrentHeader().Number.Uint64() >= p.HighestBlock + + if syncing { + metrics.GetOrRegisterGauge("isSyncing", nil).Update(1) + } else { + metrics.GetOrRegisterGauge("isSyncing", nil).Update(0) + } + now := time.Now() runtime.ReadMemStats(&mem) From 84b99c0e192354a4236f73bed9f6be51df46ee2c Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Thu, 17 May 2018 13:10:06 +0200 Subject: [PATCH 2/8] cmd/stateth: initial commit for stateth app --- cmd/stateth/json.go | 2033 ++++++++++++++++++++++++++++++++++++++++ cmd/stateth/stateth.go | 255 +++++ 2 files changed, 2288 insertions(+) create mode 100644 cmd/stateth/json.go create mode 100644 cmd/stateth/stateth.go diff --git a/cmd/stateth/json.go b/cmd/stateth/json.go new file mode 100644 index 0000000000..d72df9b8a0 --- /dev/null +++ b/cmd/stateth/json.go @@ -0,0 +1,2033 @@ +package main + +var ( + jsonDashboard = `{ + "annotations": { + "list": [ + { + "$$hashKey": "object:448", + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 1, + "id": 5, + "iteration": 1526648602647, + "links": [], + "panels": [ + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 0 + }, + "id": 40, + "panels": [], + "title": "LocalStore", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 1 + }, + "id": 42, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.localstore.get.cachehit.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "LocalStore get cachehit", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 1 + }, + "id": 43, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.localstore.get.cachemiss.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "LocalStore get cachemiss", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 44, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.localstore.getorcreaterequest.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "Total LocalStore.GetOrCreateRequest", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 47, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.localstore.getorcreaterequest.errfetching.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "LocalStore GetOrCreateRequest ErrFetching", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 13 + }, + "id": 45, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.localstore.getorcreaterequest.hit.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "LocalStore.GetOrCreateRequest hit", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 13 + }, + "id": 49, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.localstore.getorcreaterequest.miss.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "LocalStore GetOrCreateRequest miss", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 19 + }, + "id": 48, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.localstore.get.error.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "LocalStore get error", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 19 + }, + "id": 46, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.localstore.get.errfetching.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "LocalStore get ErrFetching", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 25 + }, + "id": 27, + "panels": [], + "title": "LDBStore", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 26 + }, + "id": 29, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.ldbstore.get.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "LDBStore get", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 26 + }, + "id": 30, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.ldbstore.put.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "LDBStore put", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 32 + }, + "id": 31, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.ldbstore.synciterator.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "LDBStore SyncIterator", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 32 + }, + "id": 32, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.ldbstore.synciterator.seek.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "LDBStore SyncIterator Seek/Next", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "collapsed": false, + "gridPos": { + "h": 1, + "w": 24, + "x": 0, + "y": 38 + }, + "id": 34, + "panels": [], + "title": "LDBDatabase", + "type": "row" + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 39 + }, + "id": 36, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.ldbdatabase.get.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "LDBDatabase get", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 12, + "y": 39 + }, + "id": 37, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.ldbdatabase.write.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "LDBDatabase write", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + }, + { + "aliasColors": {}, + "bars": false, + "dashLength": 10, + "dashes": false, + "datasource": "metrics", + "fill": 1, + "gridPos": { + "h": 6, + "w": 12, + "x": 0, + "y": 45 + }, + "id": 38, + "legend": { + "alignAsTable": true, + "avg": false, + "current": false, + "max": false, + "min": false, + "rightSide": true, + "show": true, + "total": true, + "values": true + }, + "lines": true, + "linewidth": 1, + "links": [], + "nullPointMode": "null", + "percentage": false, + "pointradius": 5, + "points": false, + "renderer": "flot", + "seriesOverrides": [], + "spaceLength": 10, + "stack": false, + "steppedLine": false, + "targets": [ + { + "alias": "$tag_host", + "groupBy": [ + { + "params": [ + "$myinterval" + ], + "type": "time" + }, + { + "params": [ + "host" + ], + "type": "tag" + }, + { + "params": [ + "0" + ], + "type": "fill" + } + ], + "measurement": "swarm.ldbdatabase.newiterator.count", + "orderByTime": "ASC", + "policy": "default", + "refId": "A", + "resultFormat": "time_series", + "select": [ + [ + { + "params": [ + "value" + ], + "type": "field" + }, + { + "params": [], + "type": "sum" + } + ] + ], + "tags": [ + { + "key": "host", + "operator": "=~", + "value": "/^$host$/" + } + ] + } + ], + "thresholds": [], + "timeFrom": null, + "timeShift": null, + "title": "LDBDatabase NewIterator", + "tooltip": { + "shared": true, + "sort": 0, + "value_type": "individual" + }, + "type": "graph", + "xaxis": { + "buckets": null, + "mode": "time", + "name": null, + "show": true, + "values": [] + }, + "yaxes": [ + { + "format": "none", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + }, + { + "format": "short", + "label": null, + "logBase": 1, + "max": null, + "min": null, + "show": true + } + ] + } + ], + "refresh": "10s", + "schemaVersion": 16, + "style": "dark", + "tags": [], + "templating": { + "list": [ + { + "auto": false, + "auto_count": 30, + "auto_min": "10s", + "current": { + "text": "10s", + "value": "10s" + }, + "hide": 0, + "label": "resolution", + "name": "myinterval", + "options": [ + { + "selected": false, + "text": "5s", + "value": "5s" + }, + { + "selected": true, + "text": "10s", + "value": "10s" + }, + { + "selected": false, + "text": "30s", + "value": "30s" + }, + { + "selected": false, + "text": "100s", + "value": "100s" + } + ], + "query": "5s,10s,30s,100s", + "refresh": 2, + "type": "interval" + }, + { + "allValue": null, + "current": { + "text": "swarm_30399 + swarm_30400 + swarm_30401", + "value": [ + "swarm_30399", + "swarm_30400", + "swarm_30401" + ] + }, + "datasource": "metrics", + "hide": 0, + "includeAll": true, + "label": null, + "multi": true, + "name": "host", + "options": [], + "query": "SHOW TAG VALUES WITH KEY = \"host\"", + "refresh": 1, + "regex": "", + "sort": 1, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "swarm.http.request.GET.time.span", + "type": "query", + "useTags": false + } + ] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ], + "time_options": [ + "5m", + "15m", + "1h", + "6h", + "12h", + "24h", + "2d", + "7d", + "30d" + ] + }, + "timezone": "", + "title": "LDBStore and LDBDatabase", + "uid": "zS6beG7iz", + "version": 26 +} +` +) diff --git a/cmd/stateth/stateth.go b/cmd/stateth/stateth.go new file mode 100644 index 0000000000..b46a3b8e62 --- /dev/null +++ b/cmd/stateth/stateth.go @@ -0,0 +1,255 @@ +// Copyright 2018 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +// puppeth is a command to assemble and maintain private networks. +package main + +import ( + "encoding/json" + "fmt" + "os" + "os/exec" + "os/signal" + "strings" + "syscall" + "time" + + "github.com/ethereum/go-ethereum/log" + gapi "github.com/teemupo/go-grafana-api" + "gopkg.in/urfave/cli.v1" +) + +var ( + dockerPrefix string // unique prefix used for the created docker resources + grafanaPort int // expose port for the Grafana HTTP interface + influxdbPort int // expose port for the InfluxDB HTTP interface +) + +func main() { + app := cli.NewApp() + app.Name = "stateth" + app.Usage = "run a local grafana/influxdb setup for local Geth node stats visualization" + app.Version = "0.0.1" + app.Flags = []cli.Flag{ + cli.IntFlag{ + Name: "loglevel", + Value: 3, + Usage: "log level to emit to the screen", + }, + cli.IntFlag{ + Name: "influxdb-http-port", + Value: 8086, + Usage: "default influxdb http port", + }, + cli.IntFlag{ + Name: "grafana-http-port", + Value: 3000, + Usage: "default grafana http port", + }, + cli.StringFlag{ + Name: "docker-prefix", + Value: "stateth", + Usage: "prefix to be used for docker network and containers. must be unique.", + }, + } + app.Action = func(c *cli.Context) error { + log.Root().SetHandler(log.LvlFilterHandler(log.Lvl(c.Int("loglevel")), log.StreamHandler(os.Stdout, log.TerminalFormat(true)))) + + dockerPrefix = c.String("docker-prefix") + grafanaPort = c.Int("grafana-http-port") + influxdbPort = c.Int("influxdb-http-port") + + if err := runNetwork(c); err != nil { + return err + } + if err := runInfluxDB(c); err != nil { + return err + } + if err := runGrafana(c); err != nil { + return err + } + log.Info("waiting for grafana to boot up...") + time.Sleep(7 * time.Second) // give time to Grafana to boot up + if err := importGrafanaDatasource(c); err != nil { + return err + } + if err := importGrafanaDashboard(c); err != nil { + return err + } + + sigs := make(chan os.Signal, 1) + done := make(chan bool, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + + go func() { + sig := <-sigs + fmt.Println() + fmt.Println(sig) + done <- true + }() + + fmt.Println(fmt.Sprintf("grafana listening on http://localhost:%d", grafanaPort)) + fmt.Println("username: admin") + fmt.Println("password: admin") + fmt.Println() + fmt.Println("waiting for SIGINT or SIGTERM (CTRL^C) to stop service and remove containers...") + <-done + + if err := cleanupContainers(c); err != nil { + return err + } + return nil + } + + app.Run(os.Args) +} + +func runNetwork(c *cli.Context) error { + log.Info("creating docker network", "network", dockerPrefix) + command := strings.Split(fmt.Sprintf("docker network create %s", dockerPrefix), " ") + r, err := exec.Command(command[0], command[1:]...).CombinedOutput() + if err != nil { + log.Error(string(r)) + return err + } + return nil +} + +func runInfluxDB(c *cli.Context) error { + log.Info("pulling influxdb:1.5.2 docker image") + command := strings.Split("docker pull influxdb:1.5.2", " ") + r, err := exec.Command(command[0], command[1:]...).CombinedOutput() + if err != nil { + log.Error(err.Error()) + return err + } + + log.Info("running influxdb docker container", "container", fmt.Sprintf("%s_influxdb", dockerPrefix)) + command = strings.Split(fmt.Sprintf("docker run --network %s --name %s_influxdb -e INFLUXDB_DB=metrics -e INFLUXDB_ADMIN_USER=admin -e INFLUXDB_ADMIN_PASSWORD=admin -p %d:8086 -d influxdb:1.5.2", dockerPrefix, dockerPrefix, influxdbPort), " ") + r, err = exec.Command(command[0], command[1:]...).CombinedOutput() + if err != nil { + log.Error(string(r)) + return err + } + return nil +} + +func runGrafana(c *cli.Context) error { + log.Info("pulling grafana/grafana:5.1.3 docker image") + command := strings.Split("docker pull grafana/grafana:5.1.3", " ") + r, err := exec.Command(command[0], command[1:]...).CombinedOutput() + if err != nil { + log.Error(string(r)) + return err + } + + log.Info("running grafana docker container", "container", fmt.Sprintf("%s_grafana", dockerPrefix)) + command = strings.Split(fmt.Sprintf("docker run --network %s --name=%s_grafana -p %d:3000 -d grafana/grafana:5.1.3", dockerPrefix, dockerPrefix, grafanaPort), " ") + r, err = exec.Command(command[0], command[1:]...).CombinedOutput() + if err != nil { + log.Error(string(r)) + return err + } + return nil +} + +func cleanupContainers(c *cli.Context) error { + log.Info("removing influxdb container") + command := strings.Split(fmt.Sprintf("docker rm -f %s_influxdb", dockerPrefix), " ") + r, err := exec.Command(command[0], command[1:]...).CombinedOutput() + if err != nil { + log.Warn(string(r)) + } + + log.Info("removing grafana container") + command = strings.Split(fmt.Sprintf("docker rm -f %s_grafana", dockerPrefix), " ") + r, err = exec.Command(command[0], command[1:]...).CombinedOutput() + if err != nil { + log.Warn(string(r)) + } + + log.Info("removing network") + command = strings.Split(fmt.Sprintf("docker network rm %s", dockerPrefix), " ") + r, err = exec.Command(command[0], command[1:]...).CombinedOutput() + if err != nil { + log.Warn(string(r)) + } + + return nil +} + +func importGrafanaDatasource(c *cli.Context) error { + log.Info("importing grafana datasource") + gclient, err := gapi.New("admin:admin", fmt.Sprintf("http://localhost:%d", grafanaPort)) + if err != nil { + log.Warn(err.Error()) + return nil + } + + dataSource := &gapi.DataSource{ + Name: "metrics", + Type: "influxdb", + URL: "http://stateth_influxdb:8086", + Access: "proxy", + Database: "metrics", + User: "admin", + Password: "admin", + IsDefault: true, + BasicAuth: false, + } + + _, err = gclient.NewDataSource(dataSource) + if err != nil { + log.Warn(err.Error()) + return err + } + + return nil +} + +func importGrafanaDashboard(c *cli.Context) error { + log.Info("importing grafana dashboards") + gclient, err := gapi.New("admin:admin", fmt.Sprintf("http://localhost:%d", grafanaPort)) + if err != nil { + log.Warn(err.Error()) + return nil + } + + model := prepareDashboardModel(jsonDashboard) + + _, err = gclient.SaveDashboard(model, false) + if err != nil { + log.Warn(err.Error()) + return err + } + + return nil +} + +func prepareDashboardModel(configJSON string) map[string]interface{} { + configMap := map[string]interface{}{} + err := json.Unmarshal([]byte(configJSON), &configMap) + if err != nil { + panic("invalid JSON got into prepare func") + } + + delete(configMap, "id") + // Only exists in 5.0+ + delete(configMap, "uid") + configMap["version"] = 0 + + return configMap +} From 4a54cc776b7180362778faf94484b97b75a9a150 Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Fri, 18 May 2018 22:44:37 +0200 Subject: [PATCH 3/8] vendor: github.com/teemupo/go-grafana-api --- cmd/stateth/stateth.go | 23 +- .../github.com/teemupo/go-grafana-api/LICENSE | 202 ++++++++++++++++++ .../teemupo/go-grafana-api/README.md | 11 + .../teemupo/go-grafana-api/admin.go | 46 ++++ .../go-grafana-api/alertnotification.go | 112 ++++++++++ .../teemupo/go-grafana-api/client.go | 63 ++++++ .../teemupo/go-grafana-api/dashboard.go | 100 +++++++++ .../teemupo/go-grafana-api/datasource.go | 140 ++++++++++++ .../github.com/teemupo/go-grafana-api/orgs.go | 70 ++++++ .../github.com/teemupo/go-grafana-api/user.go | 39 ++++ vendor/vendor.json | 6 + 11 files changed, 804 insertions(+), 8 deletions(-) create mode 100644 vendor/github.com/teemupo/go-grafana-api/LICENSE create mode 100644 vendor/github.com/teemupo/go-grafana-api/README.md create mode 100644 vendor/github.com/teemupo/go-grafana-api/admin.go create mode 100644 vendor/github.com/teemupo/go-grafana-api/alertnotification.go create mode 100644 vendor/github.com/teemupo/go-grafana-api/client.go create mode 100644 vendor/github.com/teemupo/go-grafana-api/dashboard.go create mode 100644 vendor/github.com/teemupo/go-grafana-api/datasource.go create mode 100644 vendor/github.com/teemupo/go-grafana-api/orgs.go create mode 100644 vendor/github.com/teemupo/go-grafana-api/user.go diff --git a/cmd/stateth/stateth.go b/cmd/stateth/stateth.go index b46a3b8e62..325f5836f0 100644 --- a/cmd/stateth/stateth.go +++ b/cmd/stateth/stateth.go @@ -38,6 +38,13 @@ var ( influxdbPort int // expose port for the InfluxDB HTTP interface ) +const ( + influxdbAdminUser = "admin" // admin username for InfluxDB + influxdbAdminPass = "admin" // admin password for InfluxDB + grafanaUser = "admin" // default Grafana username - should not be changed here without first updating the docker image + grafanaPass = "admin" // default Grafana password - should not be changed here without first udpating the docker image +) + func main() { app := cli.NewApp() app.Name = "stateth" @@ -102,8 +109,8 @@ func main() { }() fmt.Println(fmt.Sprintf("grafana listening on http://localhost:%d", grafanaPort)) - fmt.Println("username: admin") - fmt.Println("password: admin") + fmt.Println(fmt.Sprintf("username: %s", grafanaUser)) + fmt.Println(fmt.Sprintf("password: %s", grafanaPass)) fmt.Println() fmt.Println("waiting for SIGINT or SIGTERM (CTRL^C) to stop service and remove containers...") <-done @@ -138,7 +145,7 @@ func runInfluxDB(c *cli.Context) error { } log.Info("running influxdb docker container", "container", fmt.Sprintf("%s_influxdb", dockerPrefix)) - command = strings.Split(fmt.Sprintf("docker run --network %s --name %s_influxdb -e INFLUXDB_DB=metrics -e INFLUXDB_ADMIN_USER=admin -e INFLUXDB_ADMIN_PASSWORD=admin -p %d:8086 -d influxdb:1.5.2", dockerPrefix, dockerPrefix, influxdbPort), " ") + command = strings.Split(fmt.Sprintf("docker run --network %s --name %s_influxdb -e INFLUXDB_DB=metrics -e INFLUXDB_ADMIN_USER=%s -e INFLUXDB_ADMIN_PASSWORD=%s -p %d:8086 -d influxdb:1.5.2", dockerPrefix, dockerPrefix, influxdbAdminUser, influxdbAdminPass, influxdbPort), " ") r, err = exec.Command(command[0], command[1:]...).CombinedOutput() if err != nil { log.Error(string(r)) @@ -193,7 +200,7 @@ func cleanupContainers(c *cli.Context) error { func importGrafanaDatasource(c *cli.Context) error { log.Info("importing grafana datasource") - gclient, err := gapi.New("admin:admin", fmt.Sprintf("http://localhost:%d", grafanaPort)) + gclient, err := gapi.New(fmt.Sprintf("%s:%s", grafanaUser, grafanaPass), fmt.Sprintf("http://localhost:%d", grafanaPort)) if err != nil { log.Warn(err.Error()) return nil @@ -202,11 +209,11 @@ func importGrafanaDatasource(c *cli.Context) error { dataSource := &gapi.DataSource{ Name: "metrics", Type: "influxdb", - URL: "http://stateth_influxdb:8086", + URL: fmt.Sprintf("http://%s_influxdb:%d", dockerPrefix, influxdbPort), Access: "proxy", Database: "metrics", - User: "admin", - Password: "admin", + User: influxdbAdminUser, + Password: influxdbAdminPass, IsDefault: true, BasicAuth: false, } @@ -222,7 +229,7 @@ func importGrafanaDatasource(c *cli.Context) error { func importGrafanaDashboard(c *cli.Context) error { log.Info("importing grafana dashboards") - gclient, err := gapi.New("admin:admin", fmt.Sprintf("http://localhost:%d", grafanaPort)) + gclient, err := gapi.New(fmt.Sprintf("%s:%s", grafanaUser, grafanaPass), fmt.Sprintf("http://localhost:%d", grafanaPort)) if err != nil { log.Warn(err.Error()) return nil diff --git a/vendor/github.com/teemupo/go-grafana-api/LICENSE b/vendor/github.com/teemupo/go-grafana-api/LICENSE new file mode 100644 index 0000000000..8f71f43fee --- /dev/null +++ b/vendor/github.com/teemupo/go-grafana-api/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + 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. + diff --git a/vendor/github.com/teemupo/go-grafana-api/README.md b/vendor/github.com/teemupo/go-grafana-api/README.md new file mode 100644 index 0000000000..581af01ddb --- /dev/null +++ b/vendor/github.com/teemupo/go-grafana-api/README.md @@ -0,0 +1,11 @@ +# grafana-api-golang-client + +Grafana HTTP API Client for Go + +## Tests + +To run the tests: + +``` +go test +``` diff --git a/vendor/github.com/teemupo/go-grafana-api/admin.go b/vendor/github.com/teemupo/go-grafana-api/admin.go new file mode 100644 index 0000000000..3da1ae9229 --- /dev/null +++ b/vendor/github.com/teemupo/go-grafana-api/admin.go @@ -0,0 +1,46 @@ +package gapi + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" + + "github.com/grafana/grafana/pkg/api/dtos" +) + +func (c *Client) CreateUserForm(settings dtos.AdminCreateUserForm) error { + data, err := json.Marshal(settings) + req, err := c.newRequest("POST", "/api/admin/users", bytes.NewBuffer(data)) + if err != nil { + return err + } + resp, err := c.Do(req) + if err != nil { + return err + } + data, err = ioutil.ReadAll(resp.Body) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + return err +} + +func (c *Client) DeleteUser(id int64) error { + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/admin/users/%d", id), nil) + if err != nil { + return err + } + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + return err +} diff --git a/vendor/github.com/teemupo/go-grafana-api/alertnotification.go b/vendor/github.com/teemupo/go-grafana-api/alertnotification.go new file mode 100644 index 0000000000..39a32b9f40 --- /dev/null +++ b/vendor/github.com/teemupo/go-grafana-api/alertnotification.go @@ -0,0 +1,112 @@ +package gapi + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" +) + +type AlertNotification struct { + Id int64 `json:"id,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + IsDefault bool `json:"isDefault"` + Settings interface{} `json:"settings"` +} + +func (c *Client) AlertNotification(id int64) (*AlertNotification, error) { + path := fmt.Sprintf("/api/alert-notifications/%d", id) + req, err := c.newRequest("GET", path, nil) + if err != nil { + return nil, err + } + + resp, err := c.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, errors.New(resp.Status) + } + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + result := &AlertNotification{} + err = json.Unmarshal(data, &result) + return result, err +} + +func (c *Client) NewAlertNotification(a *AlertNotification) (int64, error) { + data, err := json.Marshal(a) + if err != nil { + return 0, err + } + req, err := c.newRequest("POST", "/api/alert-notifications", bytes.NewBuffer(data)) + if err != nil { + return 0, err + } + + resp, err := c.Do(req) + if err != nil { + return 0, err + } + if resp.StatusCode != 200 { + return 0, errors.New(resp.Status) + } + + data, err = ioutil.ReadAll(resp.Body) + if err != nil { + return 0, err + } + + result := struct { + Id int64 `json:"id"` + }{} + err = json.Unmarshal(data, &result) + return result.Id, err +} + +func (c *Client) UpdateAlertNotification(a *AlertNotification) error { + path := fmt.Sprintf("/api/alert-notifications/%d", a.Id) + data, err := json.Marshal(a) + if err != nil { + return err + } + req, err := c.newRequest("PUT", path, bytes.NewBuffer(data)) + if err != nil { + return err + } + + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + + return nil +} + +func (c *Client) DeleteAlertNotification(id int64) error { + path := fmt.Sprintf("/api/alert-notifications/%d", id) + req, err := c.newRequest("DELETE", path, nil) + if err != nil { + return err + } + + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + + return nil +} diff --git a/vendor/github.com/teemupo/go-grafana-api/client.go b/vendor/github.com/teemupo/go-grafana-api/client.go new file mode 100644 index 0000000000..d92ba883a8 --- /dev/null +++ b/vendor/github.com/teemupo/go-grafana-api/client.go @@ -0,0 +1,63 @@ +package gapi + +import ( + "bytes" + "fmt" + "io" + "log" + "net/http" + "net/url" + "os" + "path" + "strings" +) + +type Client struct { + key string + baseURL url.URL + *http.Client +} + +//New creates a new grafana client +//auth can be in user:pass format, or it can be an api key +func New(auth, baseURL string) (*Client, error) { + u, err := url.Parse(baseURL) + if err != nil { + return nil, err + } + key := "" + if strings.Contains(auth, ":") { + split := strings.Split(auth, ":") + u.User = url.UserPassword(split[0], split[1]) + } else { + key = fmt.Sprintf("Bearer %s", auth) + } + return &Client{ + key, + *u, + &http.Client{}, + }, nil +} + +func (c *Client) newRequest(method, requestPath string, body io.Reader) (*http.Request, error) { + url := c.baseURL + url.Path = path.Join(url.Path, requestPath) + req, err := http.NewRequest(method, url.String(), body) + if err != nil { + return req, err + } + if c.key != "" { + req.Header.Add("Authorization", c.key) + } + + if os.Getenv("GF_LOG") != "" { + if body == nil { + log.Println("request to ", url.String(), "with no body data") + } else { + log.Println("request to ", url.String(), "with body data", body.(*bytes.Buffer).String()) + } + } + + req.Header.Add("Content-Type", "application/json") + return req, err +} diff --git a/vendor/github.com/teemupo/go-grafana-api/dashboard.go b/vendor/github.com/teemupo/go-grafana-api/dashboard.go new file mode 100644 index 0000000000..ca45dc9a07 --- /dev/null +++ b/vendor/github.com/teemupo/go-grafana-api/dashboard.go @@ -0,0 +1,100 @@ +package gapi + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" +) + +type DashboardMeta struct { + IsStarred bool `json:"isStarred"` + Slug string `json:"slug"` +} + +type DashboardSaveResponse struct { + Slug string `json:"slug"` + Status string `json:"status"` + Version int64 `json:"version"` +} + +type Dashboard struct { + Meta DashboardMeta `json:"meta"` + Model map[string]interface{} `json:"dashboard"` +} + +func (c *Client) SaveDashboard(model map[string]interface{}, overwrite bool) (*DashboardSaveResponse, error) { + wrapper := map[string]interface{}{ + "dashboard": model, + "overwrite": overwrite, + } + data, err := json.Marshal(wrapper) + if err != nil { + return nil, err + } + req, err := c.newRequest("POST", "/api/dashboards/db", bytes.NewBuffer(data)) + if err != nil { + return nil, err + } + + resp, err := c.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, errors.New(resp.Status) + } + + data, err = ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + result := &DashboardSaveResponse{} + err = json.Unmarshal(data, &result) + return result, err +} + +func (c *Client) Dashboard(slug string) (*Dashboard, error) { + path := fmt.Sprintf("/api/dashboards/db/%s", slug) + req, err := c.newRequest("GET", path, nil) + if err != nil { + return nil, err + } + + resp, err := c.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, errors.New(resp.Status) + } + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + result := &Dashboard{} + err = json.Unmarshal(data, &result) + return result, err +} + +func (c *Client) DeleteDashboard(slug string) error { + path := fmt.Sprintf("/api/dashboards/db/%s", slug) + req, err := c.newRequest("DELETE", path, nil) + if err != nil { + return err + } + + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + + return nil +} diff --git a/vendor/github.com/teemupo/go-grafana-api/datasource.go b/vendor/github.com/teemupo/go-grafana-api/datasource.go new file mode 100644 index 0000000000..ab42b88e60 --- /dev/null +++ b/vendor/github.com/teemupo/go-grafana-api/datasource.go @@ -0,0 +1,140 @@ +package gapi + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" +) + +type DataSource struct { + Id int64 `json:"id,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + URL string `json:"url"` + Access string `json:"access"` + + Database string `json:"database,omitempty"` + User string `json:"user,omitempty"` + Password string `json:"password,omitempty"` + + OrgId int64 `json:"orgId,omitempty"` + IsDefault bool `json:"isDefault"` + + BasicAuth bool `json:"basicAuth"` + BasicAuthUser string `json:"basicAuthUser,omitempty"` + BasicAuthPassword string `json:"basicAuthPassword,omitempty"` + + JSONData JSONData `json:"jsonData,omitempty"` + SecureJSONData SecureJSONData `json:"secureJsonData,omitempty"` +} + +// JSONData is a representation of the datasource `jsonData` property +type JSONData struct { + AssumeRoleArn string `json:"assumeRoleArn,omitempty"` + AuthType string `json:"authType,omitempty"` + CustomMetricsNamespaces string `json:"customMetricsNamespaces,omitempty"` + DefaultRegion string `json:"defaultRegion,omitempty"` +} + +// SecureJSONData is a representation of the datasource `secureJsonData` property +type SecureJSONData struct { + AccessKey string `json:"accessKey,omitempty"` + SecretKey string `json:"secretKey,omitempty"` +} + +func (c *Client) NewDataSource(s *DataSource) (int64, error) { + data, err := json.Marshal(s) + if err != nil { + return 0, err + } + req, err := c.newRequest("POST", "/api/datasources", bytes.NewBuffer(data)) + if err != nil { + return 0, err + } + + resp, err := c.Do(req) + if err != nil { + return 0, err + } + if resp.StatusCode != 200 { + return 0, errors.New(resp.Status) + } + + data, err = ioutil.ReadAll(resp.Body) + if err != nil { + return 0, err + } + + result := struct { + Id int64 `json:"id"` + }{} + err = json.Unmarshal(data, &result) + return result.Id, err +} + +func (c *Client) UpdateDataSource(s *DataSource) error { + path := fmt.Sprintf("/api/datasources/%d", s.Id) + data, err := json.Marshal(s) + if err != nil { + return err + } + req, err := c.newRequest("PUT", path, bytes.NewBuffer(data)) + if err != nil { + return err + } + + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + + return nil +} + +func (c *Client) DataSource(id int64) (*DataSource, error) { + path := fmt.Sprintf("/api/datasources/%d", id) + req, err := c.newRequest("GET", path, nil) + if err != nil { + return nil, err + } + + resp, err := c.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, errors.New(resp.Status) + } + + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + result := &DataSource{} + err = json.Unmarshal(data, &result) + return result, err +} + +func (c *Client) DeleteDataSource(id int64) error { + path := fmt.Sprintf("/api/datasources/%d", id) + req, err := c.newRequest("DELETE", path, nil) + if err != nil { + return err + } + + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + + return nil +} diff --git a/vendor/github.com/teemupo/go-grafana-api/orgs.go b/vendor/github.com/teemupo/go-grafana-api/orgs.go new file mode 100644 index 0000000000..5a38732c70 --- /dev/null +++ b/vendor/github.com/teemupo/go-grafana-api/orgs.go @@ -0,0 +1,70 @@ +package gapi + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "io/ioutil" +) + +type Org struct { + Id int64 + Name string +} + +func (c *Client) Orgs() ([]Org, error) { + orgs := make([]Org, 0) + + req, err := c.newRequest("GET", "/api/orgs/", nil) + if err != nil { + return orgs, err + } + resp, err := c.Do(req) + if err != nil { + return orgs, err + } + if resp.StatusCode != 200 { + return orgs, errors.New(resp.Status) + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return orgs, err + } + err = json.Unmarshal(data, &orgs) + return orgs, err +} + +func (c *Client) NewOrg(name string) error { + settings := map[string]string{ + "name": name, + } + data, err := json.Marshal(settings) + req, err := c.newRequest("POST", "/api/orgs", bytes.NewBuffer(data)) + if err != nil { + return err + } + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + return err +} + +func (c *Client) DeleteOrg(id int64) error { + req, err := c.newRequest("DELETE", fmt.Sprintf("/api/orgs/%d", id), nil) + if err != nil { + return err + } + resp, err := c.Do(req) + if err != nil { + return err + } + if resp.StatusCode != 200 { + return errors.New(resp.Status) + } + return err +} diff --git a/vendor/github.com/teemupo/go-grafana-api/user.go b/vendor/github.com/teemupo/go-grafana-api/user.go new file mode 100644 index 0000000000..13a6e6ff4f --- /dev/null +++ b/vendor/github.com/teemupo/go-grafana-api/user.go @@ -0,0 +1,39 @@ +package gapi + +import ( + "encoding/json" + "errors" + "io/ioutil" +) + +type User struct { + Id int64 + Email string + Name string + Login string + IsAdmin bool +} + +func (c *Client) Users() ([]User, error) { + users := make([]User, 0) + req, err := c.newRequest("GET", "/api/users", nil) + if err != nil { + return users, err + } + resp, err := c.Do(req) + if err != nil { + return users, err + } + if resp.StatusCode != 200 { + return users, errors.New(resp.Status) + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return users, err + } + err = json.Unmarshal(data, &users) + if err != nil { + return users, err + } + return users, err +} diff --git a/vendor/vendor.json b/vendor/vendor.json index fdc7789364..7bb4459da4 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -489,6 +489,12 @@ "revision": "ae970a0732be3a1f5311da86118d37b9f4bd2a5a", "revisionTime": "2018-05-02T07:23:49Z" }, + { + "checksumSHA1": "2OAzyUvaUKVZkRx9f8NlbHT9cc0=", + "path": "github.com/teemupo/go-grafana-api", + "revision": "7380665c19d6fb0b587e654f25d2604787d890c8", + "revisionTime": "2018-02-22T10:42:15Z" + }, { "checksumSHA1": "TT1rac6kpQp2vz24m5yDGUNQ/QQ=", "path": "golang.org/x/crypto/cast5", From a62d5123cd0218e43401ade71200476adca380ca Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Fri, 18 May 2018 23:00:30 +0200 Subject: [PATCH 4/8] dashboard: fix names in constructor --- dashboard/dashboard.go | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/dashboard/dashboard.go b/dashboard/dashboard.go index 752f23a17c..249ac03a3d 100644 --- a/dashboard/dashboard.go +++ b/dashboard/dashboard.go @@ -81,7 +81,7 @@ type client struct { } // New creates a new dashboard instance with the given configuration. -func New(config *Config, commit string, _ethServ *eth.Ethereum, _lesserv *les.LightEthereum) (*Dashboard, error) { +func New(config *Config, commit string, ethServ *eth.Ethereum, lesServ *les.LightEthereum) (*Dashboard, error) { now := time.Now() db := &Dashboard{ conns: make(map[uint32]*client), @@ -98,8 +98,8 @@ func New(config *Config, commit string, _ethServ *eth.Ethereum, _lesserv *les.Li DiskWrite: emptyChartEntries(now, diskWriteSampleLimit, config.Refresh), }, commit: commit, - ethServ: _ethServ, - lesServ: _lesserv, + ethServ: ethServ, + lesServ: lesServ, } return db, nil } @@ -313,7 +313,7 @@ func (db *Dashboard) collectData() { prevDiskRead = curDiskRead prevDiskWrite = curDiskWrite - // extract metrics from downloaded and push to registry + // extract measurements from eth.Downloader and push to metrics registry p := db.ethServ.Downloader().Progress() metrics.GetOrRegisterGauge("currentBlock", nil).Update(int64(p.CurrentBlock)) @@ -322,14 +322,6 @@ func (db *Dashboard) collectData() { metrics.GetOrRegisterGauge("pulledStates", nil).Update(int64(p.PulledStates)) metrics.GetOrRegisterGauge("knownStates", nil).Update(int64(p.KnownStates)) - syncing := db.ethServ.BlockChain().CurrentHeader().Number.Uint64() >= p.HighestBlock - - if syncing { - metrics.GetOrRegisterGauge("isSyncing", nil).Update(1) - } else { - metrics.GetOrRegisterGauge("isSyncing", nil).Update(0) - } - now := time.Now() runtime.ReadMemStats(&mem) From beb509ffce28eeb3f7951d803df72d45d294d16c Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Fri, 18 May 2018 23:11:35 +0200 Subject: [PATCH 5/8] cmd/stateth: proper geth dashboard with current block number --- cmd/stateth/json.go | 1962 ++-------------------------------------- cmd/stateth/stateth.go | 4 +- cmd/utils/flags.go | 6 +- 3 files changed, 87 insertions(+), 1885 deletions(-) diff --git a/cmd/stateth/json.go b/cmd/stateth/json.go index d72df9b8a0..462d67a5f1 100644 --- a/cmd/stateth/json.go +++ b/cmd/stateth/json.go @@ -1,11 +1,12 @@ package main var ( - jsonDashboard = `{ + jsonDashboard = ` +{ "annotations": { "list": [ { - "$$hashKey": "object:448", + "$$hashKey": "object:452", "builtIn": 1, "datasource": "-- Grafana --", "enable": true, @@ -19,8 +20,8 @@ var ( "editable": true, "gnetId": null, "graphTooltip": 1, - "id": 5, - "iteration": 1526648602647, + "id": 1, + "iteration": 1526677592883, "links": [], "panels": [ { @@ -31,72 +32,90 @@ var ( "x": 0, "y": 0 }, - "id": 40, + "id": 51, "panels": [], - "title": "LocalStore", + "title": "Geth", "type": "row" }, { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, + "cacheTimeout": null, + "colorBackground": false, + "colorValue": false, + "colors": [ + "#299c46", + "rgba(237, 129, 40, 0.89)", + "#d44a3a" + ], + "datasource": null, + "format": "none", + "gauge": { + "maxValue": 100, + "minValue": 0, + "show": false, + "thresholdLabels": false, + "thresholdMarkers": true + }, "gridPos": { - "h": 6, - "w": 12, + "h": 4, + "w": 5, "x": 0, "y": 1 }, - "id": 42, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, + "id": 53, + "interval": null, "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, + "mappingType": 1, + "mappingTypes": [ + { + "$$hashKey": "object:731", + "name": "value to text", + "value": 1 + }, + { + "$$hashKey": "object:732", + "name": "range to text", + "value": 2 + } + ], + "maxDataPoints": 100, + "nullPointMode": "connected", + "nullText": null, + "postfix": "", + "postfixFontSize": "50%", + "prefix": "", + "prefixFontSize": "50%", + "rangeMaps": [ + { + "from": "null", + "text": "N/A", + "to": "null" + } + ], + "sparkline": { + "fillColor": "rgba(31, 118, 189, 0.18)", + "full": true, + "lineColor": "rgb(31, 120, 193)", + "show": true + }, + "tableColumn": "", "targets": [ { - "alias": "$tag_host", + "$$hashKey": "object:668", "groupBy": [ { "params": [ - "$myinterval" + "$__interval" ], "type": "time" }, { "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" + "null" ], "type": "fill" } ], - "measurement": "swarm.localstore.get.cachehit.count", + "measurement": "geth.currentBlock.gauge", "orderByTime": "ASC", "policy": "default", "refId": "A", @@ -111,1819 +130,29 @@ var ( }, { "params": [], - "type": "sum" + "type": "last" } ] ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] + "tags": [] } ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LocalStore get cachehit", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ + "thresholds": "", + "title": "Current block number", + "type": "singlestat", + "valueFontSize": "100%", + "valueMaps": [ { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 1 - }, - "id": 43, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.get.cachemiss.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] + "$$hashKey": "object:734", + "op": "=", + "text": "N/A", + "value": "null" } ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LocalStore get cachemiss", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 7 - }, - "id": 44, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.getorcreaterequest.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "Total LocalStore.GetOrCreateRequest", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 7 - }, - "id": 47, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.getorcreaterequest.errfetching.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LocalStore GetOrCreateRequest ErrFetching", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 13 - }, - "id": 45, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.getorcreaterequest.hit.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LocalStore.GetOrCreateRequest hit", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 13 - }, - "id": 49, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.getorcreaterequest.miss.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LocalStore GetOrCreateRequest miss", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 19 - }, - "id": 48, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.get.error.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LocalStore get error", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 19 - }, - "id": 46, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.localstore.get.errfetching.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LocalStore get ErrFetching", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 25 - }, - "id": 27, - "panels": [], - "title": "LDBStore", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 26 - }, - "id": 29, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbstore.get.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBStore get", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 26 - }, - "id": 30, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbstore.put.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBStore put", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 32 - }, - "id": 31, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbstore.synciterator.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBStore SyncIterator", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 32 - }, - "id": 32, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbstore.synciterator.seek.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBStore SyncIterator Seek/Next", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 38 - }, - "id": 34, - "panels": [], - "title": "LDBDatabase", - "type": "row" - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 39 - }, - "id": 36, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbdatabase.get.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBDatabase get", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 12, - "y": 39 - }, - "id": 37, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbdatabase.write.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBDatabase write", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] - }, - { - "aliasColors": {}, - "bars": false, - "dashLength": 10, - "dashes": false, - "datasource": "metrics", - "fill": 1, - "gridPos": { - "h": 6, - "w": 12, - "x": 0, - "y": 45 - }, - "id": 38, - "legend": { - "alignAsTable": true, - "avg": false, - "current": false, - "max": false, - "min": false, - "rightSide": true, - "show": true, - "total": true, - "values": true - }, - "lines": true, - "linewidth": 1, - "links": [], - "nullPointMode": "null", - "percentage": false, - "pointradius": 5, - "points": false, - "renderer": "flot", - "seriesOverrides": [], - "spaceLength": 10, - "stack": false, - "steppedLine": false, - "targets": [ - { - "alias": "$tag_host", - "groupBy": [ - { - "params": [ - "$myinterval" - ], - "type": "time" - }, - { - "params": [ - "host" - ], - "type": "tag" - }, - { - "params": [ - "0" - ], - "type": "fill" - } - ], - "measurement": "swarm.ldbdatabase.newiterator.count", - "orderByTime": "ASC", - "policy": "default", - "refId": "A", - "resultFormat": "time_series", - "select": [ - [ - { - "params": [ - "value" - ], - "type": "field" - }, - { - "params": [], - "type": "sum" - } - ] - ], - "tags": [ - { - "key": "host", - "operator": "=~", - "value": "/^$host$/" - } - ] - } - ], - "thresholds": [], - "timeFrom": null, - "timeShift": null, - "title": "LDBDatabase NewIterator", - "tooltip": { - "shared": true, - "sort": 0, - "value_type": "individual" - }, - "type": "graph", - "xaxis": { - "buckets": null, - "mode": "time", - "name": null, - "show": true, - "values": [] - }, - "yaxes": [ - { - "format": "none", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - }, - { - "format": "short", - "label": null, - "logBase": 1, - "max": null, - "min": null, - "show": true - } - ] + "valueName": "avg" } ], - "refresh": "10s", + "refresh": "5s", "schemaVersion": 16, "style": "dark", "tags": [], @@ -1965,33 +194,6 @@ var ( "query": "5s,10s,30s,100s", "refresh": 2, "type": "interval" - }, - { - "allValue": null, - "current": { - "text": "swarm_30399 + swarm_30400 + swarm_30401", - "value": [ - "swarm_30399", - "swarm_30400", - "swarm_30401" - ] - }, - "datasource": "metrics", - "hide": 0, - "includeAll": true, - "label": null, - "multi": true, - "name": "host", - "options": [], - "query": "SHOW TAG VALUES WITH KEY = \"host\"", - "refresh": 1, - "regex": "", - "sort": 1, - "tagValuesQuery": "", - "tags": [], - "tagsQuery": "swarm.http.request.GET.time.span", - "type": "query", - "useTags": false } ] }, @@ -2025,9 +227,9 @@ var ( ] }, "timezone": "", - "title": "LDBStore and LDBDatabase", - "uid": "zS6beG7iz", - "version": 26 + "title": "Geth", + "uid": "dUpKvj7mz", + "version": 7 } ` ) diff --git a/cmd/stateth/stateth.go b/cmd/stateth/stateth.go index 325f5836f0..976de3de84 100644 --- a/cmd/stateth/stateth.go +++ b/cmd/stateth/stateth.go @@ -39,8 +39,8 @@ var ( ) const ( - influxdbAdminUser = "admin" // admin username for InfluxDB - influxdbAdminPass = "admin" // admin password for InfluxDB + influxdbAdminUser = "test" // admin username for InfluxDB + influxdbAdminPass = "test" // admin password for InfluxDB grafanaUser = "admin" // default Grafana username - should not be changed here without first updating the docker image grafanaPass = "admin" // default Grafana password - should not be changed here without first udpating the docker image ) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index e10e1d82d0..f22fb5620b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -543,7 +543,7 @@ var ( MetricsInfluxDBEndpointFlag = cli.StringFlag{ Name: "metrics.influxdb.endpoint", Usage: "Metrics InfluxDB endpoint", - Value: "http://127.0.0.1:8086", + Value: "http://localhost:8086", } MetricsInfluxDBDatabaseFlag = cli.StringFlag{ Name: "metrics.influxdb.database", @@ -553,12 +553,12 @@ var ( MetricsInfluxDBUsernameFlag = cli.StringFlag{ Name: "metrics.influxdb.username", Usage: "Metrics InfluxDB username", - Value: "", + Value: "test", } MetricsInfluxDBPasswordFlag = cli.StringFlag{ Name: "metrics.influxdb.password", Usage: "Metrics InfluxDB password", - Value: "", + Value: "test", } // The `host` tag is part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB. // It is used so that we can group all nodes and average a measurement across all of them, but also so From 2bb5aca217abdc09f88433153902028f35dee3b4 Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Sat, 19 May 2018 01:03:47 +0200 Subject: [PATCH 6/8] vendor: update go-grafana-api to not require unneeded dependencies --- .../teemupo/go-grafana-api/README_ethereum.md | 1 + .../teemupo/go-grafana-api/admin.go | 25 ------------------- 2 files changed, 1 insertion(+), 25 deletions(-) create mode 100644 vendor/github.com/teemupo/go-grafana-api/README_ethereum.md diff --git a/vendor/github.com/teemupo/go-grafana-api/README_ethereum.md b/vendor/github.com/teemupo/go-grafana-api/README_ethereum.md new file mode 100644 index 0000000000..927a077acb --- /dev/null +++ b/vendor/github.com/teemupo/go-grafana-api/README_ethereum.md @@ -0,0 +1 @@ +Removed Client.CreateUserForm due to "github.com/grafana/grafana/pkg/api/dtos" dependency. diff --git a/vendor/github.com/teemupo/go-grafana-api/admin.go b/vendor/github.com/teemupo/go-grafana-api/admin.go index 3da1ae9229..50557bc5ee 100644 --- a/vendor/github.com/teemupo/go-grafana-api/admin.go +++ b/vendor/github.com/teemupo/go-grafana-api/admin.go @@ -1,35 +1,10 @@ package gapi import ( - "bytes" - "encoding/json" "errors" "fmt" - "io/ioutil" - - "github.com/grafana/grafana/pkg/api/dtos" ) -func (c *Client) CreateUserForm(settings dtos.AdminCreateUserForm) error { - data, err := json.Marshal(settings) - req, err := c.newRequest("POST", "/api/admin/users", bytes.NewBuffer(data)) - if err != nil { - return err - } - resp, err := c.Do(req) - if err != nil { - return err - } - data, err = ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - if resp.StatusCode != 200 { - return errors.New(resp.Status) - } - return err -} - func (c *Client) DeleteUser(id int64) error { req, err := c.newRequest("DELETE", fmt.Sprintf("/api/admin/users/%d", id), nil) if err != nil { From 574840773cefeb83e38ce172b78516c68e806ed9 Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Sat, 19 May 2018 01:09:33 +0200 Subject: [PATCH 7/8] cmd/stateth: fix linter error --- cmd/stateth/stateth.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/cmd/stateth/stateth.go b/cmd/stateth/stateth.go index 976de3de84..43c1b8ec96 100644 --- a/cmd/stateth/stateth.go +++ b/cmd/stateth/stateth.go @@ -115,10 +115,7 @@ func main() { fmt.Println("waiting for SIGINT or SIGTERM (CTRL^C) to stop service and remove containers...") <-done - if err := cleanupContainers(c); err != nil { - return err - } - return nil + return cleanupContainers(c) } app.Run(os.Args) From dd20d01b62ca55cfaca9a776520fd15ad7923ca2 Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Tue, 29 May 2018 15:40:38 +0300 Subject: [PATCH 8/8] cmd/stateth: add flag for dashboards folder. extract json from binary into json file --- .../{json.go => grafana_dashboards/geth.json} | 8 +--- cmd/stateth/stateth.go | 46 +++++++++++++++---- 2 files changed, 39 insertions(+), 15 deletions(-) rename cmd/stateth/{json.go => grafana_dashboards/geth.json} (99%) diff --git a/cmd/stateth/json.go b/cmd/stateth/grafana_dashboards/geth.json similarity index 99% rename from cmd/stateth/json.go rename to cmd/stateth/grafana_dashboards/geth.json index 462d67a5f1..6e269e7f4d 100644 --- a/cmd/stateth/json.go +++ b/cmd/stateth/grafana_dashboards/geth.json @@ -1,7 +1,3 @@ -package main - -var ( - jsonDashboard = ` { "annotations": { "list": [ @@ -231,5 +227,5 @@ var ( "uid": "dUpKvj7mz", "version": 7 } -` -) + + diff --git a/cmd/stateth/stateth.go b/cmd/stateth/stateth.go index 43c1b8ec96..0d3d6e9dc2 100644 --- a/cmd/stateth/stateth.go +++ b/cmd/stateth/stateth.go @@ -20,6 +20,7 @@ package main import ( "encoding/json" "fmt" + "io/ioutil" "os" "os/exec" "os/signal" @@ -33,9 +34,10 @@ import ( ) var ( - dockerPrefix string // unique prefix used for the created docker resources - grafanaPort int // expose port for the Grafana HTTP interface - influxdbPort int // expose port for the InfluxDB HTTP interface + dockerPrefix string // unique prefix used for the created docker resources + dashboardsFolder string // folder containing all dashboards to be imported in Grafana + grafanaPort int // expose port for the Grafana HTTP interface + influxdbPort int // expose port for the InfluxDB HTTP interface ) const ( @@ -66,6 +68,11 @@ func main() { Value: 3000, Usage: "default grafana http port", }, + cli.StringFlag{ + Name: "grafana-dashboards-folder", + Value: os.Getenv("GOPATH") + "/src/github.com/ethereum/go-ethereum/cmd/stateth/grafana_dashboards", + Usage: "default grafana dashboards folder", + }, cli.StringFlag{ Name: "docker-prefix", Value: "stateth", @@ -78,6 +85,7 @@ func main() { dockerPrefix = c.String("docker-prefix") grafanaPort = c.Int("grafana-http-port") influxdbPort = c.Int("influxdb-http-port") + dashboardsFolder = c.String("grafana-dashboards-folder") if err := runNetwork(c); err != nil { return err @@ -93,7 +101,7 @@ func main() { if err := importGrafanaDatasource(c); err != nil { return err } - if err := importGrafanaDashboard(c); err != nil { + if err := importGrafanaDashboards(c); err != nil { return err } @@ -224,7 +232,7 @@ func importGrafanaDatasource(c *cli.Context) error { return nil } -func importGrafanaDashboard(c *cli.Context) error { +func importGrafanaDashboards(c *cli.Context) error { log.Info("importing grafana dashboards") gclient, err := gapi.New(fmt.Sprintf("%s:%s", grafanaUser, grafanaPass), fmt.Sprintf("http://localhost:%d", grafanaPort)) if err != nil { @@ -232,12 +240,32 @@ func importGrafanaDashboard(c *cli.Context) error { return nil } - model := prepareDashboardModel(jsonDashboard) - - _, err = gclient.SaveDashboard(model, false) + files, err := ioutil.ReadDir(dashboardsFolder) if err != nil { log.Warn(err.Error()) - return err + return nil + } + + for _, f := range files { + name := f.Name() + if strings.Contains(name, "json") { + log.Info("importing dashboard", "dashboard", name) + + blob, err := ioutil.ReadFile(dashboardsFolder + "/" + name) + if err != nil { + log.Warn(err.Error()) + return nil + } + + model := prepareDashboardModel(string(blob)) + + _, err = gclient.SaveDashboard(model, false) + if err != nil { + log.Warn(err.Error()) + return nil + } + + } } return nil