Commit d2267643 by Marcus Efraimsson

Merge branch 'master' into mssql_datasource

parents 3d0f97aa eef01e37
...@@ -15,9 +15,13 @@ ...@@ -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)
......
...@@ -9,9 +9,6 @@ Graphite, Elasticsearch, OpenTSDB, Prometheus and InfluxDB. ...@@ -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) ...@@ -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
......
...@@ -6,3 +6,10 @@ ...@@ -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
...@@ -6,3 +6,10 @@ ...@@ -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
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
\ No newline at end of file
...@@ -28,4 +28,4 @@ ...@@ -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"
...@@ -36,4 +36,4 @@ scrape_configs: ...@@ -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']
...@@ -28,4 +28,4 @@ ...@@ -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"
...@@ -36,4 +36,4 @@ scrape_configs: ...@@ -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']
...@@ -58,6 +58,8 @@ Recipient | allows you to override the Slack recipient. ...@@ -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.
......
...@@ -15,7 +15,7 @@ weight = 1 ...@@ -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. ...@@ -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
......
...@@ -83,7 +83,7 @@ $ docker run \ ...@@ -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
......
...@@ -15,7 +15,7 @@ weight = 2 ...@@ -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. ...@@ -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`. ...@@ -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
......
...@@ -13,7 +13,7 @@ weight = 3 ...@@ -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.
......
#! /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
......
...@@ -66,6 +66,7 @@ func (hs *HttpServer) registerRoutes() { ...@@ -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)
......
...@@ -72,7 +72,9 @@ func RenderToPng(params *RenderOpts) (string, error) { ...@@ -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"))
......
...@@ -6,6 +6,7 @@ import ( ...@@ -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 { ...@@ -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)
......
...@@ -80,7 +80,7 @@ func ImportDashboard(cmd *ImportDashboardCommand) error { ...@@ -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
......
...@@ -74,6 +74,21 @@ func (e *DashAlertExtractor) GetAlertFromPanels(jsonWithPanels *simplejson.Json) ...@@ -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 {
......
...@@ -22,6 +22,7 @@ func TestAlertRuleExtraction(t *testing.T) { ...@@ -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) { ...@@ -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) { ...@@ -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)
})
})
}) })
} }
...@@ -13,6 +13,7 @@ import ( ...@@ -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 ...@@ -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 ...@@ -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
......
...@@ -105,6 +105,18 @@ type SessionWrapper struct { ...@@ -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
......
...@@ -22,6 +22,12 @@ export function setupAngularRoutes($routeProvider, $locationProvider) { ...@@ -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) { ...@@ -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',
......
...@@ -15,6 +15,7 @@ ...@@ -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>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment