Merge branch 'master' into mssql_datasource

This commit is contained in:
Marcus Efraimsson 2018-03-15 09:53:19 +01:00
commit d2267643ed
28 changed files with 3089 additions and 24 deletions

View File

@ -15,9 +15,13 @@
* **Units**: Second to HH:mm:ss formatter [#11107](https://github.com/grafana/grafana/issues/11107), thx [@gladdiologist](https://github.com/gladdiologist) * **Units**: Second to HH:mm:ss formatter [#11107](https://github.com/grafana/grafana/issues/11107), thx [@gladdiologist](https://github.com/gladdiologist)
* **Singlestat**: Add color to prefix and postfix in singlestat panel [#11143](https://github.com/grafana/grafana/pull/11143), thx [@ApsOps](https://github.com/ApsOps) * **Singlestat**: Add color to prefix and postfix in singlestat panel [#11143](https://github.com/grafana/grafana/pull/11143), thx [@ApsOps](https://github.com/ApsOps)
# 5.0.2 (unrelease) # 5.0.2 (2018-03-14)
* **Mysql**: Mysql panic occurring occasionally upon Grafana dashboard access [#11155](https://github.com/grafana/grafana/issues/11155)
* **Dashboards**: Should be possible to browse dashboard using only uid [#11231](https://github.com/grafana/grafana/issues/11231)
* **Alerting**: Fixes bug where alerts from hidden panels where deleted [#11222](https://github.com/grafana/grafana/issues/11222)
* **Import**: Fixes bug where dashboards with alerts couldn't be imported [#11227](https://github.com/grafana/grafana/issues/11227)
* **Teams**: Remove quota restrictions from teams [#11220](https://github.com/grafana/grafana/issues/11220) * **Teams**: Remove quota restrictions from teams [#11220](https://github.com/grafana/grafana/issues/11220)
* **Render**: Fixes bug with legacy url redirection for panel rendering [#11180](https://github.com/grafana/grafana/issues/11180)
# 5.0.1 (2018-03-08) # 5.0.1 (2018-03-08)

View File

@ -9,9 +9,6 @@ Graphite, Elasticsearch, OpenTSDB, Prometheus and InfluxDB.
![](http://docs.grafana.org/assets/img/features/dashboard_ex1.png) ![](http://docs.grafana.org/assets/img/features/dashboard_ex1.png)
## Grafana v5 Alpha Preview
Grafana master is now v5.0 alpha. This is going to be the biggest and most foundational release Grafana has ever had, coming with a ton of UX improvements, a new dashboard grid engine, dashboard folders, user teams and permissions. Checkout out this [video preview](https://www.youtube.com/watch?v=BC_YRNpqj5k) of Grafana v5.
## Installation ## Installation
Head to [docs.grafana.org](http://docs.grafana.org/installation/) and [download](https://grafana.com/get) Head to [docs.grafana.org](http://docs.grafana.org/installation/) and [download](https://grafana.com/get)
the latest release. the latest release.
@ -27,7 +24,7 @@ the latest master builds [here](https://grafana.com/grafana/download)
### Dependencies ### Dependencies
- Go 1.9 - Go 1.10
- NodeJS LTS - NodeJS LTS
### Building the backend ### Building the backend

View File

@ -6,3 +6,10 @@
- "9300:9300" - "9300:9300"
volumes: volumes:
- ./blocks/elastic/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml - ./blocks/elastic/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
fake-elastic-data:
image: grafana/fake-data-gen
network_mode: bridge
environment:
FD_DATASOURCE: elasticsearch
FD_PORT: 9200

View File

@ -6,3 +6,10 @@
ports: ports:
- "10200:9200" - "10200:9200"
- "10300:9300" - "10300:9300"
fake-elastic5-data:
image: grafana/fake-data-gen
network_mode: bridge
environment:
FD_DATASOURCE: elasticsearch
FD_PORT: 10200

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
graphite11:
image: graphiteapp/graphite-statsd
ports:
- "8180:80"
- "2103-2104:2003-2004"
- "2123-2124:2023-2024"
- "8225:8125/udp"
- "8226:8126"
fake-graphite11-data:
image: grafana/fake-data-gen
network_mode: bridge
environment:
FD_DATASOURCE: graphite
FD_PORT: 2103
FD_GRAPHITE_VERSION: 1.1
depends_on:
- graphite11

View File

@ -28,4 +28,4 @@
build: blocks/prometheus_random_data build: blocks/prometheus_random_data
network_mode: host network_mode: host
ports: ports:
- "8080:8080" - "8081:8080"

View File

@ -36,4 +36,4 @@ scrape_configs:
- job_name: 'prometheus-random-data' - job_name: 'prometheus-random-data'
static_configs: static_configs:
- targets: ['127.0.0.1:8080'] - targets: ['127.0.0.1:8081']

View File

@ -28,4 +28,4 @@
build: blocks/prometheus_random_data build: blocks/prometheus_random_data
network_mode: host network_mode: host
ports: ports:
- "8080:8080" - "8081:8080"

View File

@ -36,4 +36,4 @@ scrape_configs:
- job_name: 'prometheus-random-data' - job_name: 'prometheus-random-data'
static_configs: static_configs:
- targets: ['127.0.0.1:8080'] - targets: ['127.0.0.1:8081']

View File

@ -58,6 +58,8 @@ Recipient | allows you to override the Slack recipient.
Mention | make it possible to include a mention in the Slack notification sent by Grafana. Ex @here or @channel Mention | make it possible to include a mention in the Slack notification sent by Grafana. Ex @here or @channel
Token | If provided, Grafana will upload the generated image via Slack's file.upload API method, not the external image destination. Token | If provided, Grafana will upload the generated image via Slack's file.upload API method, not the external image destination.
If you are using the token for a slack bot, then you have to invite the bot to the channel you want to send notifications and add the channel to the recipient field.
### PagerDuty ### PagerDuty
To set up PagerDuty, all you have to do is to provide an API key. To set up PagerDuty, all you have to do is to provide an API key.

View File

@ -15,7 +15,7 @@ weight = 1
Description | Download Description | Download
------------ | ------------- ------------ | -------------
Stable for Debian-based Linux | [grafana_5.0.1_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.1_amd64.deb) Stable for Debian-based Linux | [grafana_5.0.2_amd64.deb](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.2_amd64.deb)
Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing
installation. installation.
@ -24,9 +24,9 @@ installation.
```bash ```bash
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.1_amd64.deb wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_5.0.2_amd64.deb
sudo apt-get install -y adduser libfontconfig sudo apt-get install -y adduser libfontconfig
sudo dpkg -i grafana_5.0.1_amd64.deb sudo dpkg -i grafana_5.0.2_amd64.deb
``` ```
## APT Repository ## APT Repository

View File

@ -83,7 +83,7 @@ $ docker run \
-d \ -d \
-p 3000:3000 \ -p 3000:3000 \
--name grafana \ --name grafana \
grafana/grafana:4.5.2 grafana/grafana:5.0.2
``` ```
## Configuring AWS Credentials for CloudWatch Support ## Configuring AWS Credentials for CloudWatch Support

View File

@ -15,7 +15,7 @@ weight = 2
Description | Download Description | Download
------------ | ------------- ------------ | -------------
Stable for CentOS / Fedora / OpenSuse / Redhat Linux | [5.0.1 (x86-64 rpm)](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.1-1.x86_64.rpm) Stable for CentOS / Fedora / OpenSuse / Redhat Linux | [5.0.2 (x86-64 rpm)](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.2-1.x86_64.rpm)
Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing
@ -26,7 +26,7 @@ installation.
You can install Grafana using Yum directly. You can install Grafana using Yum directly.
```bash ```bash
$ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.1-1.x86_64.rpm $ sudo yum install https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.2-1.x86_64.rpm
``` ```
Or install manually using `rpm`. Or install manually using `rpm`.
@ -34,15 +34,15 @@ Or install manually using `rpm`.
#### On CentOS / Fedora / Redhat: #### On CentOS / Fedora / Redhat:
```bash ```bash
$ wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.1-1.x86_64.rpm $ wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.2-1.x86_64.rpm
$ sudo yum install initscripts fontconfig $ sudo yum install initscripts fontconfig
$ sudo rpm -Uvh grafana-5.0.1-1.x86_64.rpm $ sudo rpm -Uvh grafana-5.0.2-1.x86_64.rpm
``` ```
#### On OpenSuse: #### On OpenSuse:
```bash ```bash
$ sudo rpm -i --nodeps grafana-5.0.1-1.x86_64.rpm $ sudo rpm -i --nodeps grafana-5.0.2-1.x86_64.rpm
``` ```
## Install via YUM Repository ## Install via YUM Repository

View File

@ -13,7 +13,7 @@ weight = 3
Description | Download Description | Download
------------ | ------------- ------------ | -------------
Latest stable package for Windows | [grafana-5.0.1.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.1.windows-x64.zip) Latest stable package for Windows | [grafana-5.0.2.windows-x64.zip](https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.0.2.windows-x64.zip)
Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing Read [Upgrading Grafana]({{< relref "installation/upgrading.md" >}}) for tips and guidance on updating an existing
installation. installation.

View File

@ -1,5 +1,5 @@
#! /usr/bin/env bash #! /usr/bin/env bash
version=5.0.1 version=5.0.2
wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_${version}_amd64.deb wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana_${version}_amd64.deb

View File

@ -66,6 +66,7 @@ func (hs *HttpServer) registerRoutes() {
r.Get("/plugins/:id/page/:page", reqSignedIn, Index) r.Get("/plugins/:id/page/:page", reqSignedIn, Index)
r.Get("/d/:uid/:slug", reqSignedIn, Index) r.Get("/d/:uid/:slug", reqSignedIn, Index)
r.Get("/d/:uid", reqSignedIn, Index)
r.Get("/dashboard/db/:slug", reqSignedIn, redirectFromLegacyDashboardUrl, Index) r.Get("/dashboard/db/:slug", reqSignedIn, redirectFromLegacyDashboardUrl, Index)
r.Get("/dashboard/script/*", reqSignedIn, Index) r.Get("/dashboard/script/*", reqSignedIn, Index)
r.Get("/dashboard-solo/snapshot/*", Index) r.Get("/dashboard-solo/snapshot/*", Index)

View File

@ -72,7 +72,9 @@ func RenderToPng(params *RenderOpts) (string, error) {
localDomain = setting.HttpAddr localDomain = setting.HttpAddr
} }
url := fmt.Sprintf("%s://%s:%s/%s", setting.Protocol, localDomain, setting.HttpPort, params.Path) // &render=1 signals to the legacy redirect layer to
// avoid redirect these requests.
url := fmt.Sprintf("%s://%s:%s/%s&render=1", setting.Protocol, localDomain, setting.HttpPort, params.Path)
binPath, _ := filepath.Abs(filepath.Join(setting.PhantomDir, executable)) binPath, _ := filepath.Abs(filepath.Join(setting.PhantomDir, executable))
scriptPath, _ := filepath.Abs(filepath.Join(setting.PhantomDir, "render.js")) scriptPath, _ := filepath.Abs(filepath.Join(setting.PhantomDir, "render.js"))

View File

@ -6,6 +6,7 @@ import (
"github.com/grafana/grafana/pkg/bus" "github.com/grafana/grafana/pkg/bus"
m "github.com/grafana/grafana/pkg/models" m "github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/setting"
"gopkg.in/macaron.v1" "gopkg.in/macaron.v1"
) )
@ -36,9 +37,14 @@ func RedirectFromLegacyDashboardUrl() macaron.Handler {
func RedirectFromLegacyDashboardSoloUrl() macaron.Handler { func RedirectFromLegacyDashboardSoloUrl() macaron.Handler {
return func(c *m.ReqContext) { return func(c *m.ReqContext) {
slug := c.Params("slug") slug := c.Params("slug")
renderRequest := c.QueryBool("render")
if slug != "" { if slug != "" {
if url, err := getDashboardUrlBySlug(c.OrgId, slug); err == nil { if url, err := getDashboardUrlBySlug(c.OrgId, slug); err == nil {
if renderRequest && strings.Contains(url, setting.AppSubUrl) {
url = strings.Replace(url, setting.AppSubUrl, "", 1)
}
url = strings.Replace(url, "/d/", "/d-solo/", 1) url = strings.Replace(url, "/d/", "/d-solo/", 1)
url = fmt.Sprintf("%s?%s", url, c.Req.URL.RawQuery) url = fmt.Sprintf("%s?%s", url, c.Req.URL.RawQuery)
c.Redirect(url, 301) c.Redirect(url, 301)

View File

@ -80,7 +80,7 @@ func ImportDashboard(cmd *ImportDashboardCommand) error {
User: cmd.User, User: cmd.User,
} }
savedDash, err := dashboards.NewService().SaveDashboard(dto) savedDash, err := dashboards.NewService().ImportDashboard(dto)
if err != nil { if err != nil {
return err return err

View File

@ -74,6 +74,21 @@ func (e *DashAlertExtractor) GetAlertFromPanels(jsonWithPanels *simplejson.Json)
for _, panelObj := range jsonWithPanels.Get("panels").MustArray() { for _, panelObj := range jsonWithPanels.Get("panels").MustArray() {
panel := simplejson.NewFromAny(panelObj) panel := simplejson.NewFromAny(panelObj)
collapsedJson, collapsed := panel.CheckGet("collapsed")
// check if the panel is collapsed
if collapsed && collapsedJson.MustBool() {
// extract alerts from sub panels for collapsed panels
als, err := e.GetAlertFromPanels(panel)
if err != nil {
return nil, err
}
alerts = append(alerts, als...)
continue
}
jsonAlert, hasAlert := panel.CheckGet("alert") jsonAlert, hasAlert := panel.CheckGet("alert")
if !hasAlert { if !hasAlert {

View File

@ -22,6 +22,7 @@ func TestAlertRuleExtraction(t *testing.T) {
defaultDs := &m.DataSource{Id: 12, OrgId: 1, Name: "I am default", IsDefault: true} defaultDs := &m.DataSource{Id: 12, OrgId: 1, Name: "I am default", IsDefault: true}
graphite2Ds := &m.DataSource{Id: 15, OrgId: 1, Name: "graphite2"} graphite2Ds := &m.DataSource{Id: 15, OrgId: 1, Name: "graphite2"}
influxDBDs := &m.DataSource{Id: 16, OrgId: 1, Name: "InfluxDB"} influxDBDs := &m.DataSource{Id: 16, OrgId: 1, Name: "InfluxDB"}
prom := &m.DataSource{Id: 17, OrgId: 1, Name: "Prometheus"}
bus.AddHandler("test", func(query *m.GetDataSourcesQuery) error { bus.AddHandler("test", func(query *m.GetDataSourcesQuery) error {
query.Result = []*m.DataSource{defaultDs, graphite2Ds} query.Result = []*m.DataSource{defaultDs, graphite2Ds}
@ -38,6 +39,10 @@ func TestAlertRuleExtraction(t *testing.T) {
if query.Name == influxDBDs.Name { if query.Name == influxDBDs.Name {
query.Result = influxDBDs query.Result = influxDBDs
} }
if query.Name == prom.Name {
query.Result = prom
}
return nil return nil
}) })
@ -214,5 +219,26 @@ func TestAlertRuleExtraction(t *testing.T) {
} }
}) })
}) })
Convey("Should be able to extract collapsed panels", func() {
json, err := ioutil.ReadFile("./test-data/collapsed-panels.json")
So(err, ShouldBeNil)
dashJson, err := simplejson.NewJson(json)
So(err, ShouldBeNil)
dash := m.NewDashboardFromJson(dashJson)
extractor := NewDashAlertExtractor(dash, 1)
alerts, err := extractor.GetAlerts()
Convey("Get rules without error", func() {
So(err, ShouldBeNil)
})
Convey("should be able to extract collapsed alerts", func() {
So(len(alerts), ShouldEqual, 4)
})
})
}) })
} }

View File

@ -0,0 +1,597 @@
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"gnetId": null,
"graphTooltip": 0,
"id": 127,
"links": [],
"panels": [
{
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 0
},
"id": 9,
"title": "Row title",
"type": "row"
},
{
"alert": {
"conditions": [
{
"evaluator": {
"params": [
200
],
"type": "gt"
},
"operator": {
"type": "and"
},
"query": {
"params": [
"A",
"5m",
"now"
]
},
"reducer": {
"params": [],
"type": "avg"
},
"type": "query"
}
],
"executionErrorState": "alerting",
"frequency": "10s",
"handler": 1,
"name": "Panel Title alert",
"noDataState": "no_data",
"notifications": []
},
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 1
},
"id": 10,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "go_goroutines",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{job}}",
"refId": "A"
}
],
"thresholds": [
{
"colorMode": "critical",
"fill": true,
"line": true,
"op": "gt",
"value": 200
}
],
"timeFrom": null,
"timeShift": null,
"title": "Panel Title",
"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
}
]
},
{
"gridPos": {
"h": 9,
"w": 12,
"x": 12,
"y": 1
},
"id": 14,
"limit": 10,
"links": [],
"onlyAlertsOnDashboard": true,
"show": "current",
"sortOrder": 1,
"stateFilter": [],
"title": "Panel Title",
"type": "alertlist"
},
{
"collapsed": true,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 10
},
"id": 6,
"panels": [
{
"alert": {
"conditions": [
{
"evaluator": {
"params": [
200
],
"type": "gt"
},
"operator": {
"type": "and"
},
"query": {
"params": [
"A",
"5m",
"now"
]
},
"reducer": {
"params": [],
"type": "avg"
},
"type": "query"
}
],
"executionErrorState": "alerting",
"frequency": "10s",
"handler": 1,
"name": "Panel 2 alert",
"noDataState": "no_data",
"notifications": []
},
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 11
},
"id": 11,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "go_goroutines",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{job}}",
"refId": "A"
}
],
"thresholds": [
{
"colorMode": "critical",
"fill": true,
"line": true,
"op": "gt",
"value": 200
}
],
"timeFrom": null,
"timeShift": null,
"title": "Panel 2",
"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
}
]
},
{
"alert": {
"conditions": [
{
"evaluator": {
"params": [
200
],
"type": "gt"
},
"operator": {
"type": "and"
},
"query": {
"params": [
"A",
"5m",
"now"
]
},
"reducer": {
"params": [],
"type": "avg"
},
"type": "query"
}
],
"executionErrorState": "alerting",
"frequency": "10s",
"handler": 1,
"name": "Panel 4 alert",
"noDataState": "no_data",
"notifications": []
},
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 9,
"w": 12,
"x": 12,
"y": 11
},
"id": 15,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "go_goroutines",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{job}}",
"refId": "A"
}
],
"thresholds": [
{
"colorMode": "critical",
"fill": true,
"line": true,
"op": "gt",
"value": 200
}
],
"timeFrom": null,
"timeShift": null,
"title": "Panel 4",
"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
}
]
}
],
"title": "Row title",
"type": "row"
},
{
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 11
},
"id": 4,
"title": "Row title",
"type": "row"
},
{
"alert": {
"conditions": [
{
"evaluator": {
"params": [
200
],
"type": "gt"
},
"operator": {
"type": "and"
},
"query": {
"params": [
"A",
"5m",
"now"
]
},
"reducer": {
"params": [],
"type": "avg"
},
"type": "query"
}
],
"executionErrorState": "alerting",
"frequency": "10s",
"handler": 1,
"name": "Panel 3 alert",
"noDataState": "no_data",
"notifications": []
},
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": "Prometheus",
"fill": 1,
"gridPos": {
"h": 9,
"w": 12,
"x": 0,
"y": 12
},
"id": 12,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": true,
"total": false,
"values": false
},
"lines": true,
"linewidth": 1,
"links": [],
"nullPointMode": "null",
"percentage": false,
"pointradius": 5,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"expr": "go_goroutines",
"format": "time_series",
"intervalFactor": 1,
"legendFormat": "{{job}}",
"refId": "A"
}
],
"thresholds": [
{
"colorMode": "critical",
"fill": true,
"line": true,
"op": "gt",
"value": 200
}
],
"timeFrom": null,
"timeShift": null,
"title": "Panel 3",
"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
}
]
}
],
"schemaVersion": 16,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"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": "New dashboard Copy",
"uid": "6v5pg36zk",
"version": 17
}

View File

@ -13,6 +13,7 @@ import (
// DashboardService service for operating on dashboards // DashboardService service for operating on dashboards
type DashboardService interface { type DashboardService interface {
SaveDashboard(dto *SaveDashboardDTO) (*models.Dashboard, error) SaveDashboard(dto *SaveDashboardDTO) (*models.Dashboard, error)
ImportDashboard(dto *SaveDashboardDTO) (*models.Dashboard, error)
} }
// DashboardProvisioningService service for operating on provisioned dashboards // DashboardProvisioningService service for operating on provisioned dashboards
@ -214,6 +215,20 @@ func (dr *dashboardServiceImpl) SaveDashboard(dto *SaveDashboardDTO) (*models.Da
return cmd.Result, nil return cmd.Result, nil
} }
func (dr *dashboardServiceImpl) ImportDashboard(dto *SaveDashboardDTO) (*models.Dashboard, error) {
cmd, err := dr.buildSaveDashboardCommand(dto, false)
if err != nil {
return nil, err
}
err = bus.Dispatch(cmd)
if err != nil {
return nil, err
}
return cmd.Result, nil
}
type FakeDashboardService struct { type FakeDashboardService struct {
SaveDashboardResult *models.Dashboard SaveDashboardResult *models.Dashboard
SaveDashboardError error SaveDashboardError error
@ -230,6 +245,10 @@ func (s *FakeDashboardService) SaveDashboard(dto *SaveDashboardDTO) (*models.Das
return s.SaveDashboardResult, s.SaveDashboardError return s.SaveDashboardResult, s.SaveDashboardError
} }
func (s *FakeDashboardService) ImportDashboard(dto *SaveDashboardDTO) (*models.Dashboard, error) {
return s.SaveDashboard(dto)
}
func MockDashboardService(mock *FakeDashboardService) { func MockDashboardService(mock *FakeDashboardService) {
NewService = func() DashboardService { NewService = func() DashboardService {
return mock return mock

View File

@ -105,6 +105,18 @@ type SessionWrapper struct {
} }
func (s *SessionWrapper) Start(c *macaron.Context) error { func (s *SessionWrapper) Start(c *macaron.Context) error {
// See https://github.com/grafana/grafana/issues/11155 for details on why
// a recover and retry is needed
defer func() error {
if err := recover(); err != nil {
var retryErr error
s.session, retryErr = s.manager.Start(c)
return retryErr
}
return nil
}()
var err error var err error
s.session, err = s.manager.Start(c) s.session, err = s.manager.Start(c)
return err return err

View File

@ -22,6 +22,12 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
reloadOnSearch: false, reloadOnSearch: false,
pageClass: 'page-dashboard', pageClass: 'page-dashboard',
}) })
.when('/d/:uid', {
templateUrl: 'public/app/partials/dashboard.html',
controller: 'LoadDashboardCtrl',
reloadOnSearch: false,
pageClass: 'page-dashboard',
})
.when('/dashboard/:type/:slug', { .when('/dashboard/:type/:slug', {
templateUrl: 'public/app/partials/dashboard.html', templateUrl: 'public/app/partials/dashboard.html',
controller: 'LoadDashboardCtrl', controller: 'LoadDashboardCtrl',
@ -98,6 +104,11 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
controller: 'FolderDashboardsCtrl', controller: 'FolderDashboardsCtrl',
controllerAs: 'ctrl', controllerAs: 'ctrl',
}) })
.when('/dashboards/f/:uid', {
templateUrl: 'public/app/features/dashboard/partials/folder_dashboards.html',
controller: 'FolderDashboardsCtrl',
controllerAs: 'ctrl',
})
.when('/org', { .when('/org', {
templateUrl: 'public/app/features/org/partials/orgDetails.html', templateUrl: 'public/app/features/org/partials/orgDetails.html',
controller: 'OrgDetailsCtrl', controller: 'OrgDetailsCtrl',

View File

@ -15,6 +15,7 @@
<link rel="icon" type="image/png" href="public/img/fav32.png"> <link rel="icon" type="image/png" href="public/img/fav32.png">
<link rel="mask-icon" href="public/img/grafana_mask_icon.svg" color="#F05A28"> <link rel="mask-icon" href="public/img/grafana_mask_icon.svg" color="#F05A28">
<link rel="apple-touch-icon" href="public/img/fav32.png">
</head> </head>