From 05bed2fd8abc55d62f7465b4ed09c157ad11c4ea Mon Sep 17 00:00:00 2001 From: Torkel Odegaard Date: Tue, 21 Apr 2015 08:20:34 +0200 Subject: [PATCH 01/54] Fixed folder location for readme and license files in bin tar / zip package --- tasks/options/compress.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/options/compress.js b/tasks/options/compress.js index 28ee6318fcf..4dc77ec82f8 100644 --- a/tasks/options/compress.js +++ b/tasks/options/compress.js @@ -16,7 +16,7 @@ module.exports = function(config) { { expand: true, src: ['LICENSE.md', 'README.md', 'NOTICE.md'], - dest: '<%= pkg.name %>/', + dest: '<%= pkg.name %>-<%= pkg.version %>/', } ] } From 5bddf79d097a05121369337f7c622b101ff94d3e Mon Sep 17 00:00:00 2001 From: Torkel Odegaard Date: Tue, 21 Apr 2015 08:56:32 +0200 Subject: [PATCH 02/54] Correctly determine arch for windows builds --- Gruntfile.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 9303913733d..43cb1f09bd1 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,7 +1,6 @@ /* jshint node:true */ 'use strict'; module.exports = function (grunt) { - var os = require('os'); var config = { pkg: grunt.file.readJSON('package.json'), @@ -13,6 +12,10 @@ module.exports = function (grunt) { platform: process.platform.replace('win32', 'windows'), }; + if (process.platform.match(/^win/)) { + config.arch = process.env.hasOwnProperty('ProgramFiles(x86)') ? 'x64' : 'x86'; + } + config.pkg.version = grunt.option('pkgVer') || config.pkg.version; // load plugins @@ -35,7 +38,6 @@ module.exports = function (grunt) { // Merge that object with what with whatever we have here loadConfig(config,'./tasks/options/'); - // pass the config to grunt grunt.initConfig(config); }; From 74c5015648ca4cd1f8b9579144be3208cc2be545 Mon Sep 17 00:00:00 2001 From: carl bergquist Date: Tue, 21 Apr 2015 08:30:49 +0200 Subject: [PATCH 03/54] Change default values for linewidth and fill. --- public/app/panels/graph/module.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/app/panels/graph/module.js b/public/app/panels/graph/module.js index 4fd56fb69b4..b9fff58f670 100644 --- a/public/app/panels/graph/module.js +++ b/public/app/panels/graph/module.js @@ -67,9 +67,9 @@ function (angular, app, $, _, kbn, moment, TimeSeries, PanelMeta) { // show/hide lines lines : true, // fill factor - fill : 0, + fill : 1, // line width in pixels - linewidth : 1, + linewidth : 2, // show hide points points : false, // point radius in pixels From 73b512859ac6fa39d58599b5c07e355a342dd0af Mon Sep 17 00:00:00 2001 From: Torkel Odegaard Date: Tue, 21 Apr 2015 09:48:50 +0200 Subject: [PATCH 04/54] Small ui align fix to graph axis and grid edit ui --- public/app/panels/graph/axisEditor.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/public/app/panels/graph/axisEditor.html b/public/app/panels/graph/axisEditor.html index 1d8e459be3b..ae69ec60929 100644 --- a/public/app/panels/graph/axisEditor.html +++ b/public/app/panels/graph/axisEditor.html @@ -228,10 +228,10 @@
    -
  • +
  • Decimals
  • -
  • +
  • @@ -242,4 +242,3 @@
- From dfa5b005cc12cd53078328d2b7729f72e4181a8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 21 Apr 2015 10:20:55 +0200 Subject: [PATCH 05/54] Updated docs makefile --- docs/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Makefile b/docs/Makefile index fcb1708f916..d44bc545e2c 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -44,7 +44,7 @@ docs-test: docs-build $(DOCKER_RUN_DOCS) "$(DOCKER_DOCS_IMAGE)" ./test.sh docs-build: - git fetch https://github.com/grafana/grafana.git docs-1.x && git diff --name-status FETCH_HEAD...HEAD -- . > changed-files + git fetch https://github.com/grafana/grafana.git docs-2.0 && git diff --name-status FETCH_HEAD...HEAD -- . > changed-files echo "$(GIT_BRANCH)" > GIT_BRANCH echo "$(GITCOMMIT)" > GITCOMMIT docker build -t "$(DOCKER_DOCS_IMAGE)" . From b25411ef6b5dc89f0de1cbd3f3b7dfa0555c81aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 21 Apr 2015 10:23:10 +0200 Subject: [PATCH 06/54] Updated license link on docs page --- docs/sources/index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/sources/index.md b/docs/sources/index.md index ece3285d284..24ba087575e 100644 --- a/docs/sources/index.md +++ b/docs/sources/index.md @@ -4,9 +4,9 @@ page_keywords: grafana, introduction, documentation, about # About Grafana -Grafana is a leading open source applications for visualizing large-scale measurement data. +Grafana is a leading open source applications for visualizing large-scale measurement data. -It provides a powerful and elegant way to create, share, and explore data and dashboards from your disparate metric databases, either with your team or the world. +It provides a powerful and elegant way to create, share, and explore data and dashboards from your disparate metric databases, either with your team or the world. Grafana is most commonly used for Internet infrastructure and application analytics, but many use it in other domains including industrial sensors, home automation, weather, and process control. @@ -16,7 +16,7 @@ Version 2.0 was released in April 2015: Grafana now ships with its own backend s ## Community Resources, Feedback, and Support -Thousands of organizations large and small rely on Grafana, and we have a vibrant and active community that constantly inspires us. +Thousands of organizations large and small rely on Grafana, and we have a vibrant and active community that constantly inspires us. Please don't hesitate to [open a new issue on Github](https://github.com/grafana/grafana/issues) with your suggestions, ideas, and bug reports. @@ -35,4 +35,4 @@ If you have any trouble with Grafana, whether you can't get it set up or you jus ## License -By utilizing this software, you agree to the terms of the included license. Grafana is licensed under the Apache 2.0 agreement. See [LICENSE](https://github.com/grafana/grafana/blob/master/LICENSE.mdhttps://github.com/grafana/grafana/blob/master/LICENSE.md) for the full license terms. +By utilizing this software, you agree to the terms of the included license. Grafana is licensed under the Apache 2.0 agreement. See [LICENSE](https://github.com/grafana/grafana/blob/master/LICENSE.md) for the full license terms. From 6df299886e46c05096732233649c23d28cb5ad29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 21 Apr 2015 13:30:15 +0200 Subject: [PATCH 07/54] Updated windows install instructions --- docs/sources/installation/windows.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/sources/installation/windows.md b/docs/sources/installation/windows.md index e2acb76311a..1606b5f5dfd 100644 --- a/docs/sources/installation/windows.md +++ b/docs/sources/installation/windows.md @@ -6,8 +6,23 @@ page_keywords: grafana, installation, windows guide # Installing on Windows -There are currently no binary build for Windows. But read the [build from source](../project/building_from_source) -page for instructions on how to build it yourself. +## Download + +Description | Download +------------ | ------------- +Zip package for Windows | [grafana.2.0.1.windows-x64.zip](https://grafanarel.s3.amazonaws.com/winbuilds/dist/grafana-2.0.1.windows-x64.zip) + +## Configure +The zip file contains a folder with the current grafana version. Extract this folder to anywhere you want Grafana to run from. +Go into the `conf` directory and copy `sample.ini` to `custom.ini`. You should edit `custom.ini`, never `defaults.ini`. + +The default grafana port is `3000`, this port requires extra permissions on windows. Edit `custom.ini` and uncomment the `http_port` +config and change it to something like `8080` or similar. That port should not require extra windows privileges. + +Start grafana by executing `grafana-server.exe`, preferbly from the command line. If you want to run Grafana as +windows service, download [NSSM](https://nssm.cc/). It is very easy add grafana as windows service using that tool. + +Read more about the [configuration options](configuration.md). ## Building on Windows From 6fb6e44eced3771766cafe93e4307612464ea49a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 21 Apr 2015 17:17:08 +0200 Subject: [PATCH 08/54] updated rpm install docs --- docs/sources/installation/rpm.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/sources/installation/rpm.md b/docs/sources/installation/rpm.md index 1f8277a4907..b0f0db098e0 100644 --- a/docs/sources/installation/rpm.md +++ b/docs/sources/installation/rpm.md @@ -30,9 +30,9 @@ Add the following to a new file at `/etc/yum.repos.d/grafana.repo` name=grafana baseurl=https://packagecloud.io/grafana/stable/el/6/$basearch repo_gpgcheck=1 - gpgcheck=0 enabled=1 - gpgkey=https://packagecloud.io/gpg.key + gpgcheck=1 + gpgkey=https://packagecloud.io/gpg.key https://grafanarel.s3.amazonaws.com/RPM-GPG-KEY-grafana sslverify=1 sslcacert=/etc/pki/tls/certs/ca-bundle.crt From dabdf1b7fd1453b6114b65bdb77fee3404c93eee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 21 Apr 2015 18:46:44 +0200 Subject: [PATCH 09/54] Graph Panel + Legend Table mode: Many series casued zero height graph, now legend will never reduce the height of the graph below 50% of row height, Fixes #1832 --- CHANGELOG.md | 7 +++++- build.go | 40 ++++++++++++++++++++++++-------- latest.json | 2 +- package.json | 2 +- public/app/panels/graph/graph.js | 7 +++--- 5 files changed, 42 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acbe07795be..8935cdc2676 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ -# 2.0.0 (2015-04-20) +# 2.0.2 (unreleased) + +**Fixes** +- [Issue #1832](https://github.com/grafana/grafana/issues/1832). Graph Panel + Legend Table mode: Many series casued zero height graph, now legend will never reduce the height of the graph below 50% of row height. + +# 2.0.1 (2015-04-20) **Fixes** - [Issue #1784](https://github.com/grafana/grafana/issues/1784). Data source proxy: Fixed issue with using data source proxy when grafana is behind nginx suburl diff --git a/build.go b/build.go index d7b53d7ea3a..8269e5316ae 100644 --- a/build.go +++ b/build.go @@ -19,16 +19,21 @@ import ( "strconv" "strings" "time" + + "github.com/blang/semver" ) var ( - versionRe = regexp.MustCompile(`-[0-9]{1,3}-g[0-9a-f]{5,10}`) - goarch string - goos string - version string = "v1" - race bool - workingDir string - serverBinaryName string = "grafana-server" + versionRe = regexp.MustCompile(`-[0-9]{1,3}-g[0-9a-f]{5,10}`) + goarch string + goos string + version string = "v1" + // deb & rpm does not support semver so have to handle their version a little differently + linuxPackageVersion string = "v1" + linuxPackageIteration string = "" + race bool + workingDir string + serverBinaryName string = "grafana-server" ) const minGoVersion = 1.3 @@ -40,7 +45,7 @@ func main() { ensureGoPath() readVersionFromPackageJson() - log.Printf("Version: %s\n", version) + log.Printf("Version: %s, Linux Version: %s, Package Iteration: %s\n", version, linuxPackageVersion, linuxPackageIteration) flag.StringVar(&goarch, "goarch", runtime.GOARCH, "GOARCH") flag.StringVar(&goos, "goos", runtime.GOOS, "GOOS") @@ -70,7 +75,7 @@ func main() { case "package": //verifyGitRepoIsClean() - grunt("release", "--pkgVer="+version) + grunt("release") createLinuxPackages() case "latest": @@ -107,6 +112,17 @@ func readVersionFromPackageJson() { } version = jsonObj["version"].(string) + linuxPackageVersion = version + linuxPackageIteration = "" + + // handle pre version stuff (deb / rpm does not support semver) + versionInfo, _ := semver.Make(version) + + if len(versionInfo.Pre) > 0 { + linuxPackageIteration = versionInfo.Pre[0].VersionStr + versionInfo.Pre = make([]semver.PRVersion, 0) + linuxPackageVersion = versionInfo.String() + } } type linuxPackageOptions struct { @@ -208,10 +224,14 @@ func createPackage(options linuxPackageOptions) { "--config-files", options.systemdServiceFilePath, "--after-install", options.postinstSrc, "--name", "grafana", - "--version", version, + "--version", linuxPackageVersion, "-p", "./dist", } + if linuxPackageIteration != "" { + args = append(args, "--iteration", linuxPackageIteration) + } + // add dependenciesj for _, dep := range options.depends { args = append(args, "--depends", dep) diff --git a/latest.json b/latest.json index 7f8c221daf3..a6613c11634 100644 --- a/latest.json +++ b/latest.json @@ -1,3 +1,3 @@ { - "version": "2.0.0-beta3", + "version": "2.0.1", } diff --git a/package.json b/package.json index ace54af3be9..618a2340950 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "company": "Coding Instinct AB" }, "name": "grafana", - "version": "2.0.1", + "version": "2.0.2-pre1", "repository": { "type": "git", "url": "http://github.com/torkelo/grafana.git" diff --git a/public/app/panels/graph/graph.js b/public/app/panels/graph/graph.js index a26aa7a656e..795aee03c20 100755 --- a/public/app/panels/graph/graph.js +++ b/public/app/panels/graph/graph.js @@ -63,12 +63,13 @@ function (angular, $, kbn, moment, _, GraphTooltip) { render_panel(); }); - function getLegendHeight() { + function getLegendHeight(panelHeight) { if (!scope.panel.legend.show || scope.panel.legend.rightSide) { return 0; } if (scope.panel.legend.alignAsTable) { - return 30 + (25 * data.length); + var total = 30 + (25 * data.length); + return Math.min(total, Math.floor(panelHeight/2)); } else { return 26; } @@ -84,7 +85,7 @@ function (angular, $, kbn, moment, _, GraphTooltip) { graphHeight -= 5; // padding graphHeight -= scope.panel.title ? 24 : 9; // subtract panel title bar - graphHeight = graphHeight - getLegendHeight(); // subtract one line legend + graphHeight = graphHeight - getLegendHeight(graphHeight); // subtract one line legend elem.css('height', graphHeight + 'px'); From 8ff316252e1276675f7cfb6ed57cd90df9b0ee14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 21 Apr 2015 21:17:32 +0200 Subject: [PATCH 10/54] Update info text in grafana test data source, Fixes #1840 --- .../plugins/datasource/grafana/partials/query.editor.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/public/app/plugins/datasource/grafana/partials/query.editor.html b/public/app/plugins/datasource/grafana/partials/query.editor.html index 0d6d21d0ad2..2ab843827e2 100644 --- a/public/app/plugins/datasource/grafana/partials/query.editor.html +++ b/public/app/plugins/datasource/grafana/partials/query.editor.html @@ -6,12 +6,11 @@

This is just a test data source that generates random walk series. If this is your only data source - open the left side menu and navigate to the data sources admin screen and add your data sources. You can change - data source using the button to the left of the Add query button. + open the left side menu and navigate to the data sources admin screen and add your data sources (you need to be + logged in to do this). You can change data source using the button to the left of the Add query button.

- From dc88fff70455bae3a4ca4c5376da74ee533cf67d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 22 Apr 2015 07:50:23 +0200 Subject: [PATCH 11/54] Migration: Import dashboards from Elasticsearch was capped at 100, now capped at 10000, Fixes #1843 --- README.md | 2 +- public/app/plugins/datasource/elasticsearch/datasource.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c0b4f128c77..bd178eddbdd 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ bra run ### Running ``` -./grafana web +./grafana ``` Open grafana in your browser (default http://localhost:3000) and login with admin user (default user/pass = admin/admin). diff --git a/public/app/plugins/datasource/elasticsearch/datasource.js b/public/app/plugins/datasource/elasticsearch/datasource.js index e13542de7af..957d8b7ffe7 100644 --- a/public/app/plugins/datasource/elasticsearch/datasource.js +++ b/public/app/plugins/datasource/elasticsearch/datasource.js @@ -74,7 +74,7 @@ function (angular, _, config, kbn, moment) { var data = { "fields": [timeField, "_source"], "query" : { "filtered": { "query" : query, "filter": filter } }, - "size": 100 + "size": 10000 }; return this._request('POST', '/_search', annotation.index, data).then(function(results) { From e438d21cc00287ee92998ce9af1035b45f2a65fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 22 Apr 2015 08:26:49 +0200 Subject: [PATCH 12/54] fixed minor issue in build file --- build.go | 1 + 1 file changed, 1 insertion(+) diff --git a/build.go b/build.go index 8269e5316ae..ffcd4ac0764 100644 --- a/build.go +++ b/build.go @@ -279,6 +279,7 @@ func grunt(params ...string) { func setup() { runPrint("go", "get", "-v", "github.com/tools/godep") + runPrint("go", "get", "-v", "github.com/blang/semver") runPrint("go", "get", "-v", "github.com/mattn/go-sqlite3") runPrint("go", "install", "-v", "github.com/mattn/go-sqlite3") } From 90a77bdf855b0e775762d4ec8126790d8e6013b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 22 Apr 2015 08:47:53 +0200 Subject: [PATCH 13/54] Fixed failure loop in init.d script when grafana will not start (due to permission issue or other), Fixes #1837 --- packaging/deb/init.d/grafana-server | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packaging/deb/init.d/grafana-server b/packaging/deb/init.d/grafana-server index 2e98f12aece..6daebdb4331 100755 --- a/packaging/deb/init.d/grafana-server +++ b/packaging/deb/init.d/grafana-server @@ -87,6 +87,7 @@ case "$1" in # check if pid file has been written two if ! [[ -s $PID_FILE ]]; then log_end_msg 1 + exit 1 fi i=0 @@ -96,7 +97,10 @@ case "$1" in do sleep 1 i=$(($i + 1)) - [ $i -gt $timeout ] && log_end_msg 1 + if [ $i -gt $timeout ]; then + log_end_msg 1 + exit 1 + fi done fi log_end_msg $return From f8cfbedefd208fe5bdd1e05aac1060abcfd4ca55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 22 Apr 2015 08:56:14 +0200 Subject: [PATCH 14/54] Removed semver dependency from go build script --- build.go | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/build.go b/build.go index ffcd4ac0764..d14b1458586 100644 --- a/build.go +++ b/build.go @@ -19,8 +19,6 @@ import ( "strconv" "strings" "time" - - "github.com/blang/semver" ) var ( @@ -116,12 +114,11 @@ func readVersionFromPackageJson() { linuxPackageIteration = "" // handle pre version stuff (deb / rpm does not support semver) - versionInfo, _ := semver.Make(version) + parts := strings.Split(version, "-") - if len(versionInfo.Pre) > 0 { - linuxPackageIteration = versionInfo.Pre[0].VersionStr - versionInfo.Pre = make([]semver.PRVersion, 0) - linuxPackageVersion = versionInfo.String() + if len(parts) > 1 { + linuxPackageVersion = parts[0] + linuxPackageIteration = parts[1] } } From a11b180480c1563b4c20b3b6cfa81facf0f9bd3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 22 Apr 2015 12:27:12 +0200 Subject: [PATCH 15/54] Snapshots: Fixed issue with snapshoting dashboards with an interval template variable, Fixes #1846 --- CHANGELOG.md | 1 + public/app/features/templating/templateValuesSrv.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8935cdc2676..01ef2c4505b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ **Fixes** - [Issue #1832](https://github.com/grafana/grafana/issues/1832). Graph Panel + Legend Table mode: Many series casued zero height graph, now legend will never reduce the height of the graph below 50% of row height. +- [Issue #1846](https://github.com/grafana/grafana/issues/1846). Snapshots: Fixed issue with snapshoting dashboards with an interval template variable # 2.0.1 (2015-04-20) diff --git a/public/app/features/templating/templateValuesSrv.js b/public/app/features/templating/templateValuesSrv.js index 73bcfb662bd..e933c16796f 100644 --- a/public/app/features/templating/templateValuesSrv.js +++ b/public/app/features/templating/templateValuesSrv.js @@ -52,7 +52,7 @@ function (angular, _, kbn) { if (!variable.auto) { return; } // add auto option if missing - if (variable.options[0].text !== 'auto') { + if (variable.options.length && variable.options[0].text !== 'auto') { variable.options.unshift({ text: 'auto', value: '$__auto_interval' }); } From bd0bf3747e3684d7ad70203d5dc2cf6de5d799c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 22 Apr 2015 13:23:23 +0200 Subject: [PATCH 16/54] Began work on http api docs, #1822 --- docs/sources/reference/http_api.md | 132 ++++++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 1 deletion(-) diff --git a/docs/sources/reference/http_api.md b/docs/sources/reference/http_api.md index b7ef92e0ba8..5b24cd1a12b 100644 --- a/docs/sources/reference/http_api.md +++ b/docs/sources/reference/http_api.md @@ -6,5 +6,135 @@ page_keywords: grafana, admin, http, api, documentation # HTTP API Reference -This documentation page has yet to be written. +The Grafana backend exposes an HTTP API, the same API is used by the frontend to do everything from saving +dashboards, creating users and updating data sources. + +## Authorization + +Currently you can authenticate via an `API Token` or via a `Session cookie` (acquired using regular login or oauth). + +### Create API Token + +Open the sidemenu and click the organization dropdown and select the `API Keys` option. + +![](/img/v2/orgdropdown_api_keys.png) + +You use the token in all requests in the `Authorization` header, like this: + +**Example**: + + GET http://your.grafana.com/api/dashboards/db/mydash HTTP/1.1 + Accept: application/json + Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + +The `Authorization` header value should be `Bearer `. + +## Dashboards + +### Create or Update dashboard + +`POST /api/dashboards/db` + +Creates a new dashboard or updates an existing dashboard. + +**Example Request for new dashboard**: + + POST /api/dashboards/db HTTP/1.1 + Accept: application/json + Content-Type: application/json + Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + + { + "dashboard": { + "id": null, + "title": "Production Overview", + "tags": [ "templated" ], + "timezone": "browser", + "rows": [ + { + } + ] + "schemaVersion": 6, + "version": 0 + }, + "overwrite": false + } + +JSON Body schema: + +- **dashboard** – The complete dashboard model, id = null to create a new dashboard +- **overwrite** – Set to true if you want to overwrite existing dashboard with new version or with same dashboard title. + +**Example Response**: + + HTTP/1.1 200 OK + Content-Type: application/json; charset=UTF-8 + Date: Wed, 22 Apr 2015 11:12:06 GMT + Content-Length: 78 + + { + "slug": "production-overview", + "status": "success", + "version": 1 + } + +Status Codes: + +- **200** – Created +- **400** – Errors (invalid json, missing or invalid fields, etc) +- **401** – Unauthorized +- **412** – Precondition failed + +The **412** status code is used when a newer dashboard already exists (newer, its version is greater than the verison that was sent). The +same status code is also used if another dashboar exists with the same title. The response body will look like this: + + HTTP/1.1 412 Precondition Failed + Content-Type: application/json; charset=UTF-8 + Content-Length: 97 + + { + "message": "The dashboard has been changed by someone else", + "status": "version-mismatch" + } + +In in case of title already exists the `status` property will be `name-exists`. + +### Get dashboard + +`GET /api/dashboards/db/:slug` + +Will return the dashboard given the dashboard slug. Slug is the url friendly version of the dashboard title. + +**Example Request**: + + GET /api/dashboards/db/production-overview HTTP/1.1 + Accept: application/json + Content-Type: application/json + Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk + + { + "meta": { + "isStarred": false, + "slug": "production-overview" + }, + "dashboard": { + "id": null, + "title": "Production Overview", + "tags": [ "templated" ], + "timezone": "browser", + "rows": [ + { + } + ] + "schemaVersion": 6, + "version": 0 + }, + } + +## Data sources + +## Organizations + +## Users + From 170e8a5d7674a558dc87cf7cd4777d50f5d33194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 22 Apr 2015 13:47:15 +0200 Subject: [PATCH 17/54] Another docs update --- docs/sources/reference/http_api.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/sources/reference/http_api.md b/docs/sources/reference/http_api.md index 5b24cd1a12b..242fd8c89dc 100644 --- a/docs/sources/reference/http_api.md +++ b/docs/sources/reference/http_api.md @@ -31,7 +31,7 @@ The `Authorization` header value should be `Bearer `. ## Dashboards -### Create or Update dashboard +### Create / Update dashboard `POST /api/dashboards/db` @@ -63,13 +63,12 @@ Creates a new dashboard or updates an existing dashboard. JSON Body schema: - **dashboard** – The complete dashboard model, id = null to create a new dashboard -- **overwrite** – Set to true if you want to overwrite existing dashboard with new version or with same dashboard title. +- **overwrite** – Set to true if you want to overwrite existing dashboard with newer version or with same dashboard title. **Example Response**: HTTP/1.1 200 OK Content-Type: application/json; charset=UTF-8 - Date: Wed, 22 Apr 2015 11:12:06 GMT Content-Length: 78 { @@ -112,6 +111,11 @@ Will return the dashboard given the dashboard slug. Slug is the url friendly ver Content-Type: application/json Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk +**Example Response**: + + HTTP/1.1 200 + Content-Type: application/json + { "meta": { "isStarred": false, From 1dfc5762633830055cde66af044d78e0117c6909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 22 Apr 2015 13:54:31 +0200 Subject: [PATCH 18/54] Panel timeshift: You can now use panel timeshift without a relative time override, Fixes #1848 --- CHANGELOG.md | 1 + public/app/features/panel/panelHelper.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01ef2c4505b..6549e2d325f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ **Fixes** - [Issue #1832](https://github.com/grafana/grafana/issues/1832). Graph Panel + Legend Table mode: Many series casued zero height graph, now legend will never reduce the height of the graph below 50% of row height. - [Issue #1846](https://github.com/grafana/grafana/issues/1846). Snapshots: Fixed issue with snapshoting dashboards with an interval template variable +- [Issue #1848](https://github.com/grafana/grafana/issues/1848). Panel timeshift: You can now use panel timeshift without a relative time override # 2.0.1 (2015-04-20) diff --git a/public/app/features/panel/panelHelper.js b/public/app/features/panel/panelHelper.js index 442bcbac8c5..39d8e00a9d6 100644 --- a/public/app/features/panel/panelHelper.js +++ b/public/app/features/panel/panelHelper.js @@ -43,7 +43,7 @@ function (angular, _, kbn, $) { } if (scope.panel.timeShift) { - if (!kbn.isValidTimeSpan(scope.panel.timeFrom)) { + if (!kbn.isValidTimeSpan(scope.panel.timeShift)) { scope.panelMeta.timeInfo = 'invalid timeshift'; return; } From da74fa086216b3d5d80a88e8e0684ac4f260f631 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 22 Apr 2015 17:44:47 +0200 Subject: [PATCH 19/54] Updated configuration and http api docs --- docs/sources/installation/configuration.md | 2 +- docs/sources/reference/http_api.md | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index c9a9bc14ab4..d727f9ced41 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -252,7 +252,7 @@ How long sessions lasts in seconds. Defaults to `86400` (24 hours). When enabled Grafana will send anonymous usage statistics to stats.grafana.org. No ip addresses are being tracked, only simple counters to track running instances, versions, dashboard & error counts. It is very helpful to us, please leave this -enabled. Counters are sent every 24 hours. +enabled. Counters are sent every 24 hours. Default value is `true`. ### google_analytics_ua_id If you want to track Grafana usage via Google analytics specify *your* Univeral Analytics ID diff --git a/docs/sources/reference/http_api.md b/docs/sources/reference/http_api.md index 242fd8c89dc..f02741cb37b 100644 --- a/docs/sources/reference/http_api.md +++ b/docs/sources/reference/http_api.md @@ -135,8 +135,16 @@ Will return the dashboard given the dashboard slug. Slug is the url friendly ver }, } +### Delete dashboard + +`DELETE /api/dashboards/db/:slug` + +The above will delete the dashboard with the specified slug. The slug is the url friendly (unique) version of the dashboard title. + ## Data sources +### Create data source + ## Organizations ## Users From 9cc5e981dd9525f0ec8748bbf3f7dabe27dab1f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 22 Apr 2015 17:51:50 +0200 Subject: [PATCH 20/54] Bumped version to 2.0.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 618a2340950..0ff6bf8b480 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "company": "Coding Instinct AB" }, "name": "grafana", - "version": "2.0.2-pre1", + "version": "2.0.2", "repository": { "type": "git", "url": "http://github.com/torkelo/grafana.git" From aa52f6675c03d27d1ed083c581d552dd8811cf4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 22 Apr 2015 17:56:07 +0200 Subject: [PATCH 21/54] updated changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6549e2d325f..94852d43047 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# 2.0.2 (unreleased) +# 2.0.2 (2015-04-22) **Fixes** - [Issue #1832](https://github.com/grafana/grafana/issues/1832). Graph Panel + Legend Table mode: Many series casued zero height graph, now legend will never reduce the height of the graph below 50% of row height. From 9f6a348851ea084c4a9bd87b3d9ddeb066a945fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 22 Apr 2015 19:23:28 +0200 Subject: [PATCH 22/54] Updated install docs with 2.0.2 version --- docs/sources/installation/debian.md | 4 ++-- docs/sources/installation/rpm.md | 4 ++-- docs/sources/installation/windows.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/sources/installation/debian.md b/docs/sources/installation/debian.md index cf5e4f4f072..4bba51ec530 100644 --- a/docs/sources/installation/debian.md +++ b/docs/sources/installation/debian.md @@ -10,11 +10,11 @@ page_keywords: grafana, installation, debian, ubuntu, guide Description | Download ------------ | ------------- -.deb for Debian-based Linux | [grafana_2.0.1_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_2.0.1_amd64.deb) +.deb for Debian-based Linux | [grafana_2.0.2_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_2.0.2_amd64.deb) ## Install - $ wget https://grafanarel.s3.amazonaws.com/builds/grafana_2.0.1_amd64.deb + $ wget https://grafanarel.s3.amazonaws.com/builds/grafana_2.0.2_amd64.deb $ sudo apt-get install -y adduser libfontconfig $ sudo dpkg -i grafana_2.0.1_amd64.deb diff --git a/docs/sources/installation/rpm.md b/docs/sources/installation/rpm.md index b0f0db098e0..9b7dc0ed9ed 100644 --- a/docs/sources/installation/rpm.md +++ b/docs/sources/installation/rpm.md @@ -10,12 +10,12 @@ page_keywords: grafana, installation, centos, fedora, opensuse, redhat, guide Description | Download ------------ | ------------- -.RPM for Fedora / RHEL / CentOS Linux | [grafana-2.0.1-1.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-2.0.1-1.x86_64.rpm) +.RPM for Fedora / RHEL / CentOS Linux | [grafana-2.0.2-1.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-2.0.2-1.x86_64.rpm) ## Install You can install using yum - $ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-2.0.1-1.x86_64.rpm + $ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-2.0.2-1.x86_64.rpm Or manually using `rpm` diff --git a/docs/sources/installation/windows.md b/docs/sources/installation/windows.md index 1606b5f5dfd..5bce40b3233 100644 --- a/docs/sources/installation/windows.md +++ b/docs/sources/installation/windows.md @@ -10,7 +10,7 @@ page_keywords: grafana, installation, windows guide Description | Download ------------ | ------------- -Zip package for Windows | [grafana.2.0.1.windows-x64.zip](https://grafanarel.s3.amazonaws.com/winbuilds/dist/grafana-2.0.1.windows-x64.zip) +Zip package for Windows | [grafana.2.0.2.windows-x64.zip](https://grafanarel.s3.amazonaws.com/winbuilds/dist/grafana-2.0.2.windows-x64.zip) ## Configure The zip file contains a folder with the current grafana version. Extract this folder to anywhere you want Grafana to run from. From 869cf705e08b954b9d37c3b69e654b7a642aeaa4 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Wed, 22 Apr 2015 22:29:56 +0300 Subject: [PATCH 23/54] Remove exit 0 at the end of init.d script --- packaging/rpm/init.d/grafana-server | 2 -- 1 file changed, 2 deletions(-) diff --git a/packaging/rpm/init.d/grafana-server b/packaging/rpm/init.d/grafana-server index 96e0c18c5e4..a30fffb6e00 100755 --- a/packaging/rpm/init.d/grafana-server +++ b/packaging/rpm/init.d/grafana-server @@ -144,5 +144,3 @@ case "$1" in exit 1 ;; esac - -exit 0 From 2c52224013dbe3b3e9da530d57c0d7175a051b96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 23 Apr 2015 08:24:30 +0200 Subject: [PATCH 24/54] /api/login/ping Fix for issue when behind reverse proxy and subpath, Fixes #1857 --- CHANGELOG.md | 5 +++++ package.json | 2 +- public/app/services/backendSrv.js | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94852d43047..1d656e3685c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 2.0.3 (unreleased) + +**Fixes** +- [Issue #1857](https://github.com/grafana/grafana/issues/1857). /api/login/ping Fix for issue when behind reverse proxy and subpath + # 2.0.2 (2015-04-22) **Fixes** diff --git a/package.json b/package.json index 0ff6bf8b480..64e393616f6 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "company": "Coding Instinct AB" }, "name": "grafana", - "version": "2.0.2", + "version": "2.0.3-pre1", "repository": { "type": "git", "url": "http://github.com/torkelo/grafana.git" diff --git a/public/app/services/backendSrv.js b/public/app/services/backendSrv.js index 30cad361bbe..c208fe3388e 100644 --- a/public/app/services/backendSrv.js +++ b/public/app/services/backendSrv.js @@ -63,8 +63,9 @@ function (angular, _, config) { var requestIsLocal = options.url.indexOf('/') === 0; var firstAttempt = options.retry === 0; - if (requestIsLocal && firstAttempt) { + if (requestIsLocal && !options.hasSubUrl) { options.url = config.appSubUrl + options.url; + options.hasSubUrl = true; } return $http(options).then(function(results) { From 968b1b430827472057195c798282649982392801 Mon Sep 17 00:00:00 2001 From: aibou Date: Thu, 23 Apr 2015 17:42:04 +0900 Subject: [PATCH 25/54] Fix and update documents --- conf/defaults.ini | 5 +++-- conf/sample.ini | 4 ++-- docs/sources/installation/configuration.md | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/conf/defaults.ini b/conf/defaults.ini index 042f1a5574c..6bb3fb80857 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -7,7 +7,7 @@ app_mode = production #################################### Paths #################################### [paths] -# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is useD) +# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used) # data = data # @@ -62,7 +62,7 @@ path = grafana.db #################################### Session #################################### [session] -# Either "memory", "file", "redis", "mysql", default is "memory" +# Either "memory", "file", "redis", "mysql", "postgresql", default is "file" provider = file # Provider config options @@ -70,6 +70,7 @@ provider = file # file: session dir path, is relative to grafana data_path # redis: config like redis server addr, poolSize, password, e.g. `127.0.0.1:6379,100,grafana` # mysql: go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1)/database_name` + provider_config = sessions # Session cookie name diff --git a/conf/sample.ini b/conf/sample.ini index 6aaa69f7314..68bd3eb3a1d 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -7,7 +7,7 @@ #################################### Paths #################################### [paths] -# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is useD) +# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used) # ;data = /var/lib/grafana # @@ -62,7 +62,7 @@ #################################### Session #################################### [session] -# Either "memory", "file", "redis", "mysql", default is "memory" +# Either "memory", "file", "redis", "mysql", "postgresql", default is "file" ;provider = file # Provider config options diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index d727f9ced41..a79a8494d73 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -219,7 +219,7 @@ set to true, any user successfully authenticating via google auth will be automa ## [session] ### provider -Valid values are "memory", "file", "mysql", 'postgres'. Default is "memory". +Valid values are "memory", "file", "mysql", 'postgres'. Default is "file". ### provider_config This option should be configured differently depending on what type of session provider you have configured. From 236c4e65f863d55ae79e4df9a3ff9124d4d4b15a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 23 Apr 2015 15:26:39 +0200 Subject: [PATCH 26/54] Began work on dashboard: editable flag, that actually stops users from changing anything, #1834 --- pkg/api/dtos/models.go | 6 +- public/app/features/dashboard/dashboardSrv.js | 20 +-- .../dashboard/partials/dashboardTopNav.html | 12 +- public/app/partials/dasheditor.html | 155 ++++++++++++------ public/app/routes/dashLoadControllers.js | 41 +++-- public/css/less/bootstrap-tagsinput.less | 30 +--- .../vendor/tagsinput/bootstrap-tagsinput.js | 2 +- 7 files changed, 157 insertions(+), 109 deletions(-) diff --git a/pkg/api/dtos/models.go b/pkg/api/dtos/models.go index 53519631d22..0057f78ff0d 100644 --- a/pkg/api/dtos/models.go +++ b/pkg/api/dtos/models.go @@ -28,9 +28,9 @@ type CurrentUser struct { } type DashboardMeta struct { - IsStarred bool `json:"isStarred"` - IsHome bool `json:"isHome"` - IsSnapshot bool `json:"isSnapshot"` + IsStarred bool `json:"isStarred,omitempty"` + IsHome bool `json:"isHome,omitempty"` + IsSnapshot bool `json:"isSnapshot,omitempty"` Slug string `json:"slug"` Expires time.Time `json:"expires"` Created time.Time `json:"created"` diff --git a/public/app/features/dashboard/dashboardSrv.js b/public/app/features/dashboard/dashboardSrv.js index 1064892745b..73a36ed3da8 100644 --- a/public/app/features/dashboard/dashboardSrv.js +++ b/public/app/features/dashboard/dashboardSrv.js @@ -52,24 +52,20 @@ function (angular, $, kbn, _, moment) { p._initMeta = function(meta) { meta = meta || {}; - meta.canShare = true; - meta.canSave = true; - meta.canEdit = true; - meta.canStar = true; + + meta.canShare = meta.canShare === false ? false : true; + meta.canSave = meta.canSave === false ? false : true; + meta.canEdit = meta.canEdit === false ? false : true; + meta.canStar = meta.canStar === false ? false : true; + meta.canDelete = meta.canDelete === false ? false : true; if (contextSrv.hasRole('Viewer')) { meta.canSave = false; } - if (meta.isSnapshot) { - meta.canSave = false; - } - - if (meta.isHome) { - meta.canShare = false; - meta.canStar = false; - meta.canSave = false; + if (!this.editable) { meta.canEdit = false; + meta.canDelete = false; } this.meta = meta; diff --git a/public/app/features/dashboard/partials/dashboardTopNav.html b/public/app/features/dashboard/partials/dashboardTopNav.html index 784185837e8..711fb1f34ba 100644 --- a/public/app/features/dashboard/partials/dashboardTopNav.html +++ b/public/app/features/dashboard/partials/dashboardTopNav.html @@ -27,19 +27,19 @@
  • -
  • +
  • - diff --git a/public/app/partials/dasheditor.html b/public/app/partials/dasheditor.html index e6ab6070f9f..fefded81efc 100644 --- a/public/app/partials/dasheditor.html +++ b/public/app/partials/dasheditor.html @@ -17,63 +17,118 @@ -
    - -
    -
    -
    -
    - -
    -
    - - -
    - - +
    +
    +
    +
    +
    Dashboard info
    +
    +
      +
    • + Title +
    • +
    • + +
    • +
    • + Tags + Press enter to a add tag +
    • +
    • + + +
    • +
    +
    +
    +
      +
    • + Timezone +
    • +
    • + +
    • +
    +
    +
    +
    -
    -
    -
    - - - - Press enter to a add tag -
    + +
    +
    Toggles
    +
    +
      +
    • + +
    • +
    • +
    • + + +
    • + +
    +
    +
    +
    +
      +
    • + +
    • +
    • + + +
    • +
    +
    +
    +
    +
      +
    • + +
    • +
    • + + +
    • +
    +
    - -
    -
    -
    - - - - - - - -
    - {{row.title}} - - - - -
    -
    -
    -
    - -
    - - -
    -
    -
    +
    +
    +
    + + + + + + + +
    + {{row.title}} + + + + +
    +
    +
    +
    +
    + +
    + + +
    + +
    + +
    - -
    +
    ADD ROW From d84d92f73c9bdb4578a6ce48540fb38bfab8b710 Mon Sep 17 00:00:00 2001 From: Anthony Woods Date: Sat, 25 Apr 2015 18:46:30 +0800 Subject: [PATCH 36/54] fixes #1880 correct mysql statement for modifying column data type --- pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go b/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go index 9cbb5c8c7ab..2e3d2d2a188 100644 --- a/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go +++ b/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go @@ -53,5 +53,5 @@ func addDashboardSnapshotMigrations(mg *Migrator) { mg.AddMigration("alter dashboard_snapshot.data to mediumtext v1", new(RawSqlMigration). Sqlite("SELECT 0 WHERE 0;"). Postgres("SELECT 0;"). - Mysql("ALTER TABLE dashboard_snapshot.data MODIFY data MEDIUMTEXT;")) + Mysql("ALTER TABLE dashboard_snapshot MODIFY data MEDIUMTEXT;")) } From f227002a804c4fcdc360939ce5bb7e0b5194a3aa Mon Sep 17 00:00:00 2001 From: Anthony Woods Date: Sat, 25 Apr 2015 18:51:25 +0800 Subject: [PATCH 37/54] fixes #1880 dashboard_snapshot table does not have a data column --- pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go b/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go index 2e3d2d2a188..352619ee6e9 100644 --- a/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go +++ b/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go @@ -49,9 +49,4 @@ func addDashboardSnapshotMigrations(mg *Migrator) { mg.AddMigration("create dashboard_snapshot table v5 #2", NewAddTableMigration(snapshotV5)) addTableIndicesMigrations(mg, "v5", snapshotV5) - // ncrease data type - mg.AddMigration("alter dashboard_snapshot.data to mediumtext v1", new(RawSqlMigration). - Sqlite("SELECT 0 WHERE 0;"). - Postgres("SELECT 0;"). - Mysql("ALTER TABLE dashboard_snapshot MODIFY data MEDIUMTEXT;")) } From e410fbb558be6ae491523a413872b24002028211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 25 Apr 2015 20:28:50 +0200 Subject: [PATCH 38/54] Corrected SQL migration for snapshot table column type change, #1880 --- pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go b/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go index 352619ee6e9..b08cc451e55 100644 --- a/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go +++ b/pkg/services/sqlstore/migrations/dashboard_snapshot_mig.go @@ -49,4 +49,9 @@ func addDashboardSnapshotMigrations(mg *Migrator) { mg.AddMigration("create dashboard_snapshot table v5 #2", NewAddTableMigration(snapshotV5)) addTableIndicesMigrations(mg, "v5", snapshotV5) + // change column type of dashboard + mg.AddMigration("alter dashboard_snapshot to mediumtext v2", new(RawSqlMigration). + Sqlite("SELECT 0 WHERE 0;"). + Postgres("SELECT 0;"). + Mysql("ALTER TABLE dashboard_snapshot MODIFY dashboard MEDIUMTEXT;")) } From 16fc6e8b4234dbffda88af6091a47f70f3a6bc53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 27 Apr 2015 10:09:32 +0200 Subject: [PATCH 39/54] More work on editable false dashboards, #1834 --- .../features/dashboard/dashboardNavCtrl.js | 2 ++ public/app/features/dashboard/dashboardSrv.js | 2 ++ .../dashboard/partials/dashboardTopNav.html | 4 ++-- public/app/routes/dashLoadControllers.js | 17 ++++++++++---- public/app/services/contextSrv.js | 15 ++++++------- public/test/specs/dashboardSrv-specs.js | 22 ++++++++++++++++--- 6 files changed, 45 insertions(+), 17 deletions(-) diff --git a/public/app/features/dashboard/dashboardNavCtrl.js b/public/app/features/dashboard/dashboardNavCtrl.js index 11595e30479..d2cf8d29c12 100644 --- a/public/app/features/dashboard/dashboardNavCtrl.js +++ b/public/app/features/dashboard/dashboardNavCtrl.js @@ -119,6 +119,8 @@ function (angular, _) { $scope.saveDashboardAs = function() { var newScope = $rootScope.$new(); newScope.clone = $scope.dashboard.getSaveModelClone(); + newScope.clone.editable = true; + newScope.clone.hideControls = false; $scope.appEvent('show-modal', { src: './app/features/dashboard/partials/saveDashboardAs.html', diff --git a/public/app/features/dashboard/dashboardSrv.js b/public/app/features/dashboard/dashboardSrv.js index 73a36ed3da8..9324f18e33b 100644 --- a/public/app/features/dashboard/dashboardSrv.js +++ b/public/app/features/dashboard/dashboardSrv.js @@ -66,6 +66,8 @@ function (angular, $, kbn, _, moment) { if (!this.editable) { meta.canEdit = false; meta.canDelete = false; + meta.canSave = false; + this.hideControls = true; } this.meta = meta; diff --git a/public/app/features/dashboard/partials/dashboardTopNav.html b/public/app/features/dashboard/partials/dashboardTopNav.html index 711fb1f34ba..6f85d6b4e02 100644 --- a/public/app/features/dashboard/partials/dashboardTopNav.html +++ b/public/app/features/dashboard/partials/dashboardTopNav.html @@ -27,7 +27,7 @@
  • -
  • +
  • Templating
  • Export
  • View JSON
  • -
  • Save As...
  • +
  • Save As...
  • Delete dashboard
  • diff --git a/public/app/routes/dashLoadControllers.js b/public/app/routes/dashLoadControllers.js index ba33dc7e73a..ee36ef72117 100644 --- a/public/app/routes/dashLoadControllers.js +++ b/public/app/routes/dashLoadControllers.js @@ -59,12 +59,15 @@ function (angular, _, kbn, moment, $) { $location.path(''); return; } - $scope.initDashboard({meta: {}, model: window.grafanaImportDashboard }, $scope); + $scope.initDashboard({ + meta: { canShare: false, canStar: false }, + model: window.grafanaImportDashboard + }, $scope); }); module.controller('NewDashboardCtrl', function($scope) { $scope.initDashboard({ - meta: {}, + meta: { canStar: false, canShare: false }, model: { title: "New dashboard", rows: [{ height: '250px', panels:[] }] @@ -93,7 +96,10 @@ function (angular, _, kbn, moment, $) { }; file_load($routeParams.jsonFile).then(function(result) { - $scope.initDashboard({meta: {fromFile: true}, model: result}, $scope); + $scope.initDashboard({ + meta: { canSave: false, canDelete: false }, + model: result + }, $scope); }); }); @@ -138,7 +144,10 @@ function (angular, _, kbn, moment, $) { }; script_load($routeParams.jsFile).then(function(result) { - $scope.initDashboard({meta: {fromScript: true, canDelete: false}, model: result.data}, $scope); + $scope.initDashboard({ + meta: {fromScript: true, canDelete: false, canSave: false}, + model: result.data + }, $scope); }); }); diff --git a/public/app/services/contextSrv.js b/public/app/services/contextSrv.js index c615e0baf8c..99bbcccf156 100644 --- a/public/app/services/contextSrv.js +++ b/public/app/services/contextSrv.js @@ -18,13 +18,6 @@ function (angular, _, store, config) { } } - this.version = config.buildInfo.version; - this.lightTheme = false; - this.user = new User(); - this.isSignedIn = this.user.isSignedIn; - this.isGrafanaAdmin = this.user.isGrafanaAdmin; - this.sidemenu = store.getBool('grafana.sidemenu'); - // events $rootScope.$on('toggle-sidemenu', function() { self.toggleSideMenu(); @@ -47,6 +40,12 @@ function (angular, _, store, config) { }, 50); }; + this.version = config.buildInfo.version; + this.lightTheme = false; + this.user = new User(); + this.isSignedIn = this.user.isSignedIn; + this.isGrafanaAdmin = this.user.isGrafanaAdmin; + this.sidemenu = store.getBool('grafana.sidemenu'); + this.isEditor = this.hasRole('Editor') || this.hasRole('Admin'); }); - }); diff --git a/public/test/specs/dashboardSrv-specs.js b/public/test/specs/dashboardSrv-specs.js index 19f81f1cc01..35d248888c7 100644 --- a/public/test/specs/dashboardSrv-specs.js +++ b/public/test/specs/dashboardSrv-specs.js @@ -185,10 +185,26 @@ define([ expect(model.annotations.list.length).to.be(0); expect(model.templating.list.length).to.be(0); }); - }); + describe('Given editable false dashboard', function() { + var model; + + beforeEach(function() { + model = _dashboardSrv.create({ + editable: false, + }); + }); + + it('Should set meta canEdit and canSave to false', function() { + expect(model.meta.canSave).to.be(false); + expect(model.meta.canEdit).to.be(false); + }); + + it('getSaveModelClone should remove meta', function() { + var clone = model.getSaveModelClone(); + expect(clone.meta).to.be(undefined); + }); + }); }); - - }); From 29a7490af294887ec03db1aff2fd5d78ded49ec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 27 Apr 2015 10:29:04 +0200 Subject: [PATCH 40/54] Small fix for unsaved changes when using save as feature --- public/app/features/dashboard/unsavedChangesSrv.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/dashboard/unsavedChangesSrv.js b/public/app/features/dashboard/unsavedChangesSrv.js index d17276dc374..eec884551ec 100644 --- a/public/app/features/dashboard/unsavedChangesSrv.js +++ b/public/app/features/dashboard/unsavedChangesSrv.js @@ -37,7 +37,7 @@ function(angular, _, config) { }); this.ignoreChanges = function() { - if (!self.current) { return true; } + if (!self.current || !self.current.meta) { return true; } var meta = self.current.meta; return !meta.canSave || meta.fromScript || meta.fromFile; From b0ef659add252ae47dea6a5730ffca2a9051401c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 27 Apr 2015 10:56:36 +0200 Subject: [PATCH 41/54] Stop users from entering panel edit mode when dashboard editable is false, #1834 --- public/app/features/panel/panelSrv.js | 8 ++++++++ public/app/panels/graph/module.js | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/public/app/features/panel/panelSrv.js b/public/app/features/panel/panelSrv.js index d8e2272436a..33f70ca25da 100644 --- a/public/app/features/panel/panelSrv.js +++ b/public/app/features/panel/panelSrv.js @@ -70,6 +70,14 @@ function (angular, _, config) { }; $scope.toggleFullscreen = function(edit) { + if (edit && $scope.dashboardMeta.canEdit === false) { + $scope.appEvent('alert-warning', [ + 'Dashboard not editable', + 'Use Save As.. feature to create an editable copy of this dashboard.' + ]); + return; + } + $scope.dashboardViewState.update({ fullscreen: true, edit: edit, panelId: $scope.panel.id }); }; diff --git a/public/app/panels/graph/module.js b/public/app/panels/graph/module.js index b9fff58f670..dfcd5901594 100644 --- a/public/app/panels/graph/module.js +++ b/public/app/panels/graph/module.js @@ -29,7 +29,7 @@ function (angular, app, $, _, kbn, moment, TimeSeries, PanelMeta) { panelName: 'Graph', editIcon: "fa fa-bar-chart", fullscreen: true, - metricsEditor: true + metricsEditor: true, }); $scope.panelMeta.addEditorTab('Axes & Grid', 'app/panels/graph/axisEditor.html'); From 8a986ec340948ba3ce0b9954ffba29e112822b20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 27 Apr 2015 10:59:14 +0200 Subject: [PATCH 42/54] Using CTRL+S should not work when dashboardMeta.canSave is false, #1834 --- public/app/features/dashboard/dashboardNavCtrl.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/app/features/dashboard/dashboardNavCtrl.js b/public/app/features/dashboard/dashboardNavCtrl.js index d2cf8d29c12..27ce528f69e 100644 --- a/public/app/features/dashboard/dashboardNavCtrl.js +++ b/public/app/features/dashboard/dashboardNavCtrl.js @@ -52,6 +52,10 @@ function (angular, _) { }; $scope.saveDashboard = function(options) { + if ($scope.dashboardMeta.canSave === false) { + return; + } + var clone = $scope.dashboard.getSaveModelClone(); backendSrv.saveDashboard(clone, options).then(function(data) { From a0dad3897479533eb8b8b181404876306f4e278a Mon Sep 17 00:00:00 2001 From: Ian Danforth Date: Tue, 28 Apr 2015 15:09:22 -0700 Subject: [PATCH 43/54] Correct deb version number in install guide. --- docs/sources/installation/debian.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/installation/debian.md b/docs/sources/installation/debian.md index 4bba51ec530..c2594e38445 100644 --- a/docs/sources/installation/debian.md +++ b/docs/sources/installation/debian.md @@ -16,7 +16,7 @@ Description | Download $ wget https://grafanarel.s3.amazonaws.com/builds/grafana_2.0.2_amd64.deb $ sudo apt-get install -y adduser libfontconfig - $ sudo dpkg -i grafana_2.0.1_amd64.deb + $ sudo dpkg -i grafana_2.0.2_amd64.deb ## APT Repository Add the following line to your `/etc/apt/sources.list` From 7ea579bb71cf1d505c815d5907b4d8910772a488 Mon Sep 17 00:00:00 2001 From: Garrett Bjerkhoel Date: Tue, 28 Apr 2015 20:19:48 -0700 Subject: [PATCH 44/54] Add team_ids configuration option --- conf/defaults.ini | 1 + pkg/social/social.go | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/conf/defaults.ini b/conf/defaults.ini index 6bb3fb80857..7345f18520e 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -140,6 +140,7 @@ enabled = false client_id = some_id client_secret = some_secret scopes = user:email +team_ids = auth_url = https://github.com/login/oauth/authorize token_url = https://github.com/login/oauth/access_token api_url = https://api.github.com/user diff --git a/pkg/social/social.go b/pkg/social/social.go index 47c7ea5dc38..c19784e34e1 100644 --- a/pkg/social/social.go +++ b/pkg/social/social.go @@ -75,7 +75,8 @@ func NewOAuthService() { // GitHub. if name == "github" { setting.OAuthService.GitHub = true - SocialMap["github"] = &SocialGithub{Config: &config, allowedDomains: info.AllowedDomains, ApiUrl: info.ApiUrl, allowSignup: info.AllowSignup} + teamIds := sec.Key("team_ids").Ints(",") + SocialMap["github"] = &SocialGithub{Config: &config, allowedDomains: info.AllowedDomains, ApiUrl: info.ApiUrl, allowSignup: info.AllowSignup, teamIds: teamIds} } // Google. @@ -105,6 +106,7 @@ type SocialGithub struct { allowedDomains []string ApiUrl string allowSignup bool + teamIds []int } func (s *SocialGithub) Type() int { From 979d0ca70f5aec638ce6e6bb8c8f69f47973f221 Mon Sep 17 00:00:00 2001 From: Garrett Bjerkhoel Date: Tue, 28 Apr 2015 20:21:44 -0700 Subject: [PATCH 45/54] Add new error type for team membership permissions --- pkg/social/social.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/social/social.go b/pkg/social/social.go index c19784e34e1..752ed7114c2 100644 --- a/pkg/social/social.go +++ b/pkg/social/social.go @@ -5,6 +5,7 @@ import ( "fmt" "strconv" "strings" + "errors" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" @@ -109,6 +110,10 @@ type SocialGithub struct { teamIds []int } +var ( + ErrMissingTeamMembership = errors.New("User not a member of one of the required teams") +) + func (s *SocialGithub) Type() int { return int(models.GITHUB) } From eb37fc089b01aba3d046635e60596e8d82dc1601 Mon Sep 17 00:00:00 2001 From: Garrett Bjerkhoel Date: Tue, 28 Apr 2015 20:22:21 -0700 Subject: [PATCH 46/54] Check for active team membership when fetching s.UserInfo --- pkg/social/social.go | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/pkg/social/social.go b/pkg/social/social.go index 752ed7114c2..2b716495d53 100644 --- a/pkg/social/social.go +++ b/pkg/social/social.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" "errors" + "net/http" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" @@ -126,6 +127,28 @@ func (s *SocialGithub) IsSignupAllowed() bool { return s.allowSignup } +func (s *SocialGithub) IsTeamMember(client *http.Client, username string, teamId int) bool { + var data struct { + Url string `json:"url"` + State string `json:"state"` + } + + membershipUrl := fmt.Sprintf("https://api.github.com/teams/%d/memberships/%s", teamId, username) + r, err := client.Get(membershipUrl) + if err != nil { + return false + } + + defer r.Body.Close() + + if err = json.NewDecoder(r.Body).Decode(&data); err != nil { + return false + } + + active := data.State == "active" + return active +} + func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) { var data struct { Id int `json:"id"` @@ -146,11 +169,23 @@ func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) { return nil, err } - return &BasicUserInfo{ + userInfo := &BasicUserInfo{ Identity: strconv.Itoa(data.Id), Name: data.Name, Email: data.Email, - }, nil + } + + if len(s.teamIds) > 0 { + for _, teamId := range s.teamIds { + if s.IsTeamMember(client, data.Name, teamId) { + return userInfo, nil + } + } + + return nil, ErrMissingTeamMembership + } else { + return userInfo, nil + } } // ________ .__ From 1d7f9452685f5f2d41224afbf659bb922636a8bc Mon Sep 17 00:00:00 2001 From: Garrett Bjerkhoel Date: Tue, 28 Apr 2015 20:22:45 -0700 Subject: [PATCH 47/54] Handle special error case if connect.UserInfo returns an error --- pkg/api/login_oauth.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go index 11d62754a18..d89a7237d35 100644 --- a/pkg/api/login_oauth.go +++ b/pkg/api/login_oauth.go @@ -45,7 +45,11 @@ func OAuthLogin(ctx *middleware.Context) { userInfo, err := connect.UserInfo(token) if err != nil { - ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err) + if err == social.ErrMissingTeamMembership { + ctx.Redirect(setting.AppSubUrl + "/login?missing_team_membership=1") + } else { + ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err) + } return } From 1fdc5277ae875b50ee680dcc7f162ef716cdc9c4 Mon Sep 17 00:00:00 2001 From: Garrett Bjerkhoel Date: Tue, 28 Apr 2015 20:38:05 -0700 Subject: [PATCH 48/54] Update documentation for team_ids option --- docs/sources/installation/configuration.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index a79a8494d73..a1dfb6ac035 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -179,6 +179,7 @@ Client ID and a Client Secret. Specify these in the grafana config file. Example client_id = YOUR_GITHUB_APP_CLIENT_ID client_secret = YOUR_GITHUB_APP_CLIENT_SECRET scopes = user:email + team_ids = auth_url = https://github.com/login/oauth/authorize token_url = https://github.com/login/oauth/access_token allow_sign_up = false @@ -189,6 +190,21 @@ now login or signup with your github accounts. You may allow users to sign-up via github auth by setting allow_sign_up to true. When this option is set to true, any user successfully authenticating via github auth will be automatically signed up. +### team_ids +Require an active team membership for at least one of the given teams on GitHub. +If the authenticated user isn't a member of at least one the teams they will not +be able to register or authenticate with your Grafana instance. Example: + + [auth.github] + enabled = true + client_id = YOUR_GITHUB_APP_CLIENT_ID + client_secret = YOUR_GITHUB_APP_CLIENT_SECRET + scopes = user:email + team_ids = 150,300 + auth_url = https://github.com/login/oauth/authorize + token_url = https://github.com/login/oauth/access_token + allow_sign_up = false + ## [auth.google] You need to create a google project. You can do this in the [Google Developer Console](https://console.developers.google.com/project). When you create the project you will need to specify a callback URL. Specify this as callback: @@ -257,5 +273,3 @@ enabled. Counters are sent every 24 hours. Default value is `true`. ### google_analytics_ua_id If you want to track Grafana usage via Google analytics specify *your* Univeral Analytics ID here. By defualt this feature is disabled. - - From b72eba1ef223e2476ab4a04663ad74da1b58d1a6 Mon Sep 17 00:00:00 2001 From: Anthony Woods Date: Wed, 29 Apr 2015 14:55:39 +0800 Subject: [PATCH 49/54] refactor handling of refresh when urlValues being used for templates. fixes #1862 --- .../features/templating/templateValuesSrv.js | 33 +++++++++++++------ 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/public/app/features/templating/templateValuesSrv.js b/public/app/features/templating/templateValuesSrv.js index 3df2c831b6f..10ff556bf84 100644 --- a/public/app/features/templating/templateValuesSrv.js +++ b/public/app/features/templating/templateValuesSrv.js @@ -28,17 +28,11 @@ function (angular, _, kbn) { for (var i = 0; i < this.variables.length; i++) { var variable = this.variables[i]; var urlValue = queryParams['var-' + variable.name]; - if (variable.refresh) { - promises.push(this.updateOptions(variable)); - } if (urlValue !== void 0) { - var option = _.findWhere(variable.options, { text: urlValue }); - option = option || { text: urlValue, value: urlValue }; - - var promise = this.setVariableValue(variable, option, true); - this.updateAutoInterval(variable); - - promises.push(promise); + promises.push(this.setVariableFromUrl(variable, urlValue)); + } + else if (variable.refresh) { + promises.push(this.updateOptions(variable)); } else if (variable.type === 'interval') { this.updateAutoInterval(variable); @@ -48,6 +42,25 @@ function (angular, _, kbn) { return $q.all(promises); }; + this.setVariableFromUrl = function(variable, urlValue) { + if (variable.refresh) { + var self = this; + //refresh the list of options before setting the value + return this.updateOptions(variable).then(function() { + var option = _.findWhere(variable.options, { text: urlValue }); + option = option || { text: urlValue, value: urlValue }; + + self.updateAutoInterval(variable); + return self.setVariableValue(variable, option); + }); + } + var option = _.findWhere(variable.options, { text: urlValue }); + option = option || { text: urlValue, value: urlValue }; + + this.updateAutoInterval(variable); + return this.setVariableValue(variable, option); + }; + this.updateAutoInterval = function(variable) { if (!variable.auto) { return; } From 81636d8634fa21f60a867ca4a11a270df883d473 Mon Sep 17 00:00:00 2001 From: Anthony Woods Date: Wed, 29 Apr 2015 15:14:49 +0800 Subject: [PATCH 50/54] expose orgId via currentUser object. fixes #1907 --- pkg/api/dtos/models.go | 1 + pkg/api/index.go | 1 + 2 files changed, 2 insertions(+) diff --git a/pkg/api/dtos/models.go b/pkg/api/dtos/models.go index 0057f78ff0d..a14ff55c079 100644 --- a/pkg/api/dtos/models.go +++ b/pkg/api/dtos/models.go @@ -23,6 +23,7 @@ type CurrentUser struct { LightTheme bool `json:"lightTheme"` OrgRole m.RoleType `json:"orgRole"` OrgName string `json:"orgName"` + OrgId int64 `json:"orgId"` IsGrafanaAdmin bool `json:"isGrafanaAdmin"` GravatarUrl string `json:"gravatarUrl"` } diff --git a/pkg/api/index.go b/pkg/api/index.go index d9ecf65b699..6e880b1d066 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -20,6 +20,7 @@ func setIndexViewData(c *middleware.Context) error { LightTheme: c.Theme == "light", OrgName: c.OrgName, OrgRole: c.OrgRole, + OrgId: c.OrgId, GravatarUrl: dtos.GetGravatarUrl(c.Email), IsGrafanaAdmin: c.IsGrafanaAdmin, } From e7c43bf614ae380c99f9cf09b4bdbb100088efad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 29 Apr 2015 09:26:12 +0200 Subject: [PATCH 51/54] expose org id to frontend, Closes #1907 --- pkg/api/dtos/models.go | 3 ++- pkg/api/index.go | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/api/dtos/models.go b/pkg/api/dtos/models.go index 0057f78ff0d..fea88f07550 100644 --- a/pkg/api/dtos/models.go +++ b/pkg/api/dtos/models.go @@ -21,8 +21,9 @@ type CurrentUser struct { Email string `json:"email"` Name string `json:"name"` LightTheme bool `json:"lightTheme"` - OrgRole m.RoleType `json:"orgRole"` + OrgId int64 `json:"orgId"` OrgName string `json:"orgName"` + OrgRole m.RoleType `json:"orgRole"` IsGrafanaAdmin bool `json:"isGrafanaAdmin"` GravatarUrl string `json:"gravatarUrl"` } diff --git a/pkg/api/index.go b/pkg/api/index.go index d9ecf65b699..86a5e3f1882 100644 --- a/pkg/api/index.go +++ b/pkg/api/index.go @@ -18,6 +18,7 @@ func setIndexViewData(c *middleware.Context) error { Email: c.Email, Name: c.Name, LightTheme: c.Theme == "light", + OrgId: c.OrgId, OrgName: c.OrgName, OrgRole: c.OrgRole, GravatarUrl: dtos.GetGravatarUrl(c.Email), From 884dc53f8a7bf963e802eb551fc845749516d6ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 29 Apr 2015 09:49:22 +0200 Subject: [PATCH 52/54] =?UTF-8?q?smal=C4=BA=20refactorings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pkg/social/social.go | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/pkg/social/social.go b/pkg/social/social.go index 2b716495d53..355f85b54b6 100644 --- a/pkg/social/social.go +++ b/pkg/social/social.go @@ -2,11 +2,11 @@ package social import ( "encoding/json" + "errors" "fmt" + "net/http" "strconv" "strings" - "errors" - "net/http" "github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/setting" @@ -78,13 +78,23 @@ func NewOAuthService() { if name == "github" { setting.OAuthService.GitHub = true teamIds := sec.Key("team_ids").Ints(",") - SocialMap["github"] = &SocialGithub{Config: &config, allowedDomains: info.AllowedDomains, ApiUrl: info.ApiUrl, allowSignup: info.AllowSignup, teamIds: teamIds} + SocialMap["github"] = &SocialGithub{ + Config: &config, + allowedDomains: info.AllowedDomains, + apiUrl: info.ApiUrl, + allowSignup: info.AllowSignup, + teamIds: teamIds, + } } // Google. if name == "google" { setting.OAuthService.Google = true - SocialMap["google"] = &SocialGoogle{Config: &config, allowedDomains: info.AllowedDomains, ApiUrl: info.ApiUrl, allowSignup: info.AllowSignup} + SocialMap["google"] = &SocialGoogle{ + Config: &config, allowedDomains: info.AllowedDomains, + apiUrl: info.ApiUrl, + allowSignup: info.AllowSignup, + } } } } @@ -106,7 +116,7 @@ func isEmailAllowed(email string, allowedDomains []string) bool { type SocialGithub struct { *oauth2.Config allowedDomains []string - ApiUrl string + apiUrl string allowSignup bool teamIds []int } @@ -129,8 +139,8 @@ func (s *SocialGithub) IsSignupAllowed() bool { func (s *SocialGithub) IsTeamMember(client *http.Client, username string, teamId int) bool { var data struct { - Url string `json:"url"` - State string `json:"state"` + Url string `json:"url"` + State string `json:"state"` } membershipUrl := fmt.Sprintf("https://api.github.com/teams/%d/memberships/%s", teamId, username) @@ -158,7 +168,7 @@ func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) { var err error client := s.Client(oauth2.NoContext, token) - r, err := client.Get(s.ApiUrl) + r, err := client.Get(s.apiUrl) if err != nil { return nil, err } @@ -198,7 +208,7 @@ func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) { type SocialGoogle struct { *oauth2.Config allowedDomains []string - ApiUrl string + apiUrl string allowSignup bool } @@ -223,7 +233,7 @@ func (s *SocialGoogle) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) { var err error client := s.Client(oauth2.NoContext, token) - r, err := client.Get(s.ApiUrl) + r, err := client.Get(s.apiUrl) if err != nil { return nil, err } From 32fa8180fa2bc3c57192a6dce93e34cc4761ad35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 29 Apr 2015 09:52:52 +0200 Subject: [PATCH 53/54] Github OAuth: You can now configure a Github team membership requirement, Closes #1731 --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b9133bf8601..70aaa67ab22 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ -# 2.0.3 (unreleased) +# 2.1.0 (unreleased - master branch) + +**Backend** +- [Issue #1905](https://github.com/grafana/grafana/issues/1905). Github OAuth: You can now configure a Github team membership requirement, thx @dewski + + +# 2.0.3 (unreleased - 2.0.x branch) **Fixes** - [Issue #1872](https://github.com/grafana/grafana/issues/1872). Firefox/IE issue, invisible text in dashboard search fixed From 0d3fbb865929becce7ff5cc72ab0a15d4f1b7da3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 29 Apr 2015 10:08:01 +0200 Subject: [PATCH 54/54] Added message alerts when login failed due to github team membership or email domain requirement, #1731, #1660 --- conf/sample.ini | 7 +++---- pkg/api/login_oauth.go | 5 +++-- public/app/controllers/loginCtrl.js | 9 ++++++++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/conf/sample.ini b/conf/sample.ini index 68bd3eb3a1d..4ebab72d1af 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -142,8 +142,8 @@ ;auth_url = https://github.com/login/oauth/authorize ;token_url = https://github.com/login/oauth/access_token ;api_url = https://api.github.com/user -# Uncomment bellow to only allow specific email domains -; allowed_domains = mycompany.com othercompany.com +;team_ids = +;allowed_domains = #################################### Google Auth ########################## [auth.google] @@ -154,8 +154,7 @@ ;auth_url = https://accounts.google.com/o/oauth2/auth ;token_url = https://accounts.google.com/o/oauth2/token ;api_url = https://www.googleapis.com/oauth2/v1/userinfo -# Uncomment bellow to only allow specific email domains -; allowed_domains = mycompany.com othercompany.com +;allowed_domains = #################################### Logging ########################## [log] diff --git a/pkg/api/login_oauth.go b/pkg/api/login_oauth.go index d89a7237d35..505c17ddde8 100644 --- a/pkg/api/login_oauth.go +++ b/pkg/api/login_oauth.go @@ -3,6 +3,7 @@ package api import ( "errors" "fmt" + "net/url" "golang.org/x/oauth2" @@ -46,7 +47,7 @@ func OAuthLogin(ctx *middleware.Context) { userInfo, err := connect.UserInfo(token) if err != nil { if err == social.ErrMissingTeamMembership { - ctx.Redirect(setting.AppSubUrl + "/login?missing_team_membership=1") + ctx.Redirect(setting.AppSubUrl + "/login?failedMsg=" + url.QueryEscape("Required Github team membership not fulfilled")) } else { ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err) } @@ -58,7 +59,7 @@ func OAuthLogin(ctx *middleware.Context) { // validate that the email is allowed to login to grafana if !connect.IsEmailAllowed(userInfo.Email) { log.Info("OAuth login attempt with unallowed email, %s", userInfo.Email) - ctx.Redirect(setting.AppSubUrl + "/login?email_not_allowed=1") + ctx.Redirect(setting.AppSubUrl + "/login?failedMsg=" + url.QueryEscape("Required email domain not fulfilled")) return } diff --git a/public/app/controllers/loginCtrl.js b/public/app/controllers/loginCtrl.js index 5de773842f8..c8856df0690 100644 --- a/public/app/controllers/loginCtrl.js +++ b/public/app/controllers/loginCtrl.js @@ -7,7 +7,7 @@ function (angular, config) { var module = angular.module('grafana.controllers'); - module.controller('LoginCtrl', function($scope, backendSrv, contextSrv) { + module.controller('LoginCtrl', function($scope, backendSrv, contextSrv, $location) { $scope.formModel = { user: '', email: '', @@ -28,6 +28,13 @@ function (angular, config) { $scope.init = function() { $scope.$watch("loginMode", $scope.loginModeChanged); $scope.passwordChanged(); + + var params = $location.search(); + if (params.failedMsg) { + $scope.appEvent('alert-warning', ['Login Failed', params.failedMsg]); + delete params.failedMsg; + $location.search(params); + } }; // build info view model