Parcourir la source

Merge branch 'master' into panel_repeat

Conflicts:
	public/app/features/templating/templateValuesSrv.js
Torkel Ödegaard il y a 10 ans
Parent
commit
b762f56aee

+ 7 - 1
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**
 **Fixes**
 - [Issue #1872](https://github.com/grafana/grafana/issues/1872). Firefox/IE issue, invisible text in dashboard search fixed
 - [Issue #1872](https://github.com/grafana/grafana/issues/1872). Firefox/IE issue, invisible text in dashboard search fixed

+ 3 - 2
conf/defaults.ini

@@ -137,18 +137,20 @@ org_role = Viewer
 #################################### Github Auth ##########################
 #################################### Github Auth ##########################
 [auth.github]
 [auth.github]
 enabled = false
 enabled = false
+allow_sign_up = false
 client_id = some_id
 client_id = some_id
 client_secret = some_secret
 client_secret = some_secret
 scopes = user:email
 scopes = user:email
 auth_url = https://github.com/login/oauth/authorize
 auth_url = https://github.com/login/oauth/authorize
 token_url = https://github.com/login/oauth/access_token
 token_url = https://github.com/login/oauth/access_token
 api_url = https://api.github.com/user
 api_url = https://api.github.com/user
+team_ids =
 allowed_domains =
 allowed_domains =
-allow_sign_up = false
 
 
 #################################### Google Auth ##########################
 #################################### Google Auth ##########################
 [auth.google]
 [auth.google]
 enabled = false
 enabled = false
+allow_sign_up = false
 client_id = some_client_id
 client_id = some_client_id
 client_secret = some_client_secret
 client_secret = some_client_secret
 scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email
 scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email
@@ -156,7 +158,6 @@ auth_url = https://accounts.google.com/o/oauth2/auth
 token_url = https://accounts.google.com/o/oauth2/token
 token_url = https://accounts.google.com/o/oauth2/token
 api_url = https://www.googleapis.com/oauth2/v1/userinfo
 api_url = https://www.googleapis.com/oauth2/v1/userinfo
 allowed_domains =
 allowed_domains =
-allow_sign_up = false
 
 
 #################################### Logging ##########################
 #################################### Logging ##########################
 [log]
 [log]

+ 5 - 4
conf/sample.ini

@@ -136,26 +136,27 @@
 #################################### Github Auth ##########################
 #################################### Github Auth ##########################
 [auth.github]
 [auth.github]
 ;enabled = false
 ;enabled = false
+;allow_sign_up = false
 ;client_id = some_id
 ;client_id = some_id
 ;client_secret = some_secret
 ;client_secret = some_secret
 ;scopes = user:email
 ;scopes = user:email
 ;auth_url = https://github.com/login/oauth/authorize
 ;auth_url = https://github.com/login/oauth/authorize
 ;token_url = https://github.com/login/oauth/access_token
 ;token_url = https://github.com/login/oauth/access_token
 ;api_url = https://api.github.com/user
 ;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 ##########################
 #################################### Google Auth ##########################
 [auth.google]
 [auth.google]
 ;enabled = false
 ;enabled = false
+;allow_sign_up = false
 ;client_id = some_client_id
 ;client_id = some_client_id
 ;client_secret = some_client_secret
 ;client_secret = some_client_secret
 ;scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email
 ;scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email
 ;auth_url = https://accounts.google.com/o/oauth2/auth
 ;auth_url = https://accounts.google.com/o/oauth2/auth
 ;token_url = https://accounts.google.com/o/oauth2/token
 ;token_url = https://accounts.google.com/o/oauth2/token
 ;api_url = https://www.googleapis.com/oauth2/v1/userinfo
 ;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 ##########################
 #################################### Logging ##########################
 [log]
 [log]

+ 1 - 1
docs/Makefile

@@ -44,7 +44,7 @@ docs-test: docs-build
 	$(DOCKER_RUN_DOCS) "$(DOCKER_DOCS_IMAGE)" ./test.sh
 	$(DOCKER_RUN_DOCS) "$(DOCKER_DOCS_IMAGE)" ./test.sh
 
 
 docs-build:
 docs-build:
-	git fetch https://github.com/grafana/grafana.git docs-2.0 && git diff --name-status FETCH_HEAD...HEAD -- . > changed-files
+	git fetch https://github.com/grafana/grafana.git docs-1.x && git diff --name-status FETCH_HEAD...HEAD -- . > changed-files
 	echo "$(GIT_BRANCH)" > GIT_BRANCH
 	echo "$(GIT_BRANCH)" > GIT_BRANCH
 	echo "$(GITCOMMIT)" > GITCOMMIT
 	echo "$(GITCOMMIT)" > GITCOMMIT
 	docker build -t "$(DOCKER_DOCS_IMAGE)" .
 	docker build -t "$(DOCKER_DOCS_IMAGE)" .

+ 1 - 4
docs/sources/guides/screencasts.md

@@ -15,10 +15,9 @@ no_toc: true
   <div class="columns medium-6">
   <div class="columns medium-6">
     <h3>Episode 2 - Templated Graphite Queries</h3>
     <h3>Episode 2 - Templated Graphite Queries</h3>
     <div class="video-container">
     <div class="video-container">
-    <iframe height="315" src="//www.youtube.com/embed/FhNUrueWwOk?list=PLDGkOdUX1Ujo3wHw9-z5Vo12YLqXRjzg2" frameborder="0" allowfullscreen></iframe>
+    <iframe height="215" src="//www.youtube.com/embed/FhNUrueWwOk?list=PLDGkOdUX1Ujo3wHw9-z5Vo12YLqXRjzg2" frameborder="0" allowfullscreen></iframe>
     </div>
     </div>
   </div>
   </div>
-  </div>
 </div>
 </div>
 
 
 <div class="row">
 <div class="row">
@@ -34,7 +33,6 @@ no_toc: true
     <iframe height="215" src="https://www.youtube.com/embed/JY22EBOR9hQ?list=PLDGkOdUX1Ujo3wHw9-z5Vo12YLqXRjzg2" frameborder="0" allowfullscreen></iframe>
     <iframe height="215" src="https://www.youtube.com/embed/JY22EBOR9hQ?list=PLDGkOdUX1Ujo3wHw9-z5Vo12YLqXRjzg2" frameborder="0" allowfullscreen></iframe>
     </div>
     </div>
   </div>
   </div>
-  </div>
 </div>
 </div>
 
 
 <div class="row">
 <div class="row">
@@ -50,7 +48,6 @@ no_toc: true
     <iframe height="215" src="https://www.youtube.com/embed/9ZCMVNxUf6s?list=PLDGkOdUX1Ujo3wHw9-z5Vo12YLqXRjzg2" frameborder="0" allowfullscreen></iframe>
     <iframe height="215" src="https://www.youtube.com/embed/9ZCMVNxUf6s?list=PLDGkOdUX1Ujo3wHw9-z5Vo12YLqXRjzg2" frameborder="0" allowfullscreen></iframe>
     </div>
     </div>
   </div>
   </div>
-  </div>
 </div>
 </div>
 
 
 <div class="row">
 <div class="row">

+ 16 - 2
docs/sources/installation/configuration.md

@@ -182,6 +182,7 @@ Client ID and a Client Secret. Specify these in the grafana config file. Example
     auth_url = https://github.com/login/oauth/authorize
     auth_url = https://github.com/login/oauth/authorize
     token_url = https://github.com/login/oauth/access_token
     token_url = https://github.com/login/oauth/access_token
     allow_sign_up = false
     allow_sign_up = false
+    team_ids =
 
 
 Restart the grafana backend. You should now see a github login button on the login page. You can
 Restart the grafana backend. You should now see a github login button on the login page. You can
 now login or signup with your github accounts.
 now login or signup with your github accounts.
@@ -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
 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.
 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]
 ## [auth.google]
 You need to create a google project. You can do this in the [Google Developer Console](https://console.developers.google.com/project).
 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:
 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
 ### google_analytics_ua_id
 If you want to track Grafana usage via Google analytics specify *your* Univeral Analytics ID
 If you want to track Grafana usage via Google analytics specify *your* Univeral Analytics ID
 here. By defualt this feature is disabled.
 here. By defualt this feature is disabled.
-
-

+ 1 - 1
docs/sources/installation/debian.md

@@ -16,7 +16,7 @@ Description | Download
 
 
     $ wget https://grafanarel.s3.amazonaws.com/builds/grafana_2.0.2_amd64.deb
     $ wget https://grafanarel.s3.amazonaws.com/builds/grafana_2.0.2_amd64.deb
     $ sudo apt-get install -y adduser libfontconfig
     $ 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
 ## APT Repository
 Add the following line to your `/etc/apt/sources.list`
 Add the following line to your `/etc/apt/sources.list`

+ 2 - 1
pkg/api/dtos/models.go

@@ -21,8 +21,9 @@ type CurrentUser struct {
 	Email          string     `json:"email"`
 	Email          string     `json:"email"`
 	Name           string     `json:"name"`
 	Name           string     `json:"name"`
 	LightTheme     bool       `json:"lightTheme"`
 	LightTheme     bool       `json:"lightTheme"`
-	OrgRole        m.RoleType `json:"orgRole"`
+	OrgId          int64      `json:"orgId"`
 	OrgName        string     `json:"orgName"`
 	OrgName        string     `json:"orgName"`
+	OrgRole        m.RoleType `json:"orgRole"`
 	IsGrafanaAdmin bool       `json:"isGrafanaAdmin"`
 	IsGrafanaAdmin bool       `json:"isGrafanaAdmin"`
 	GravatarUrl    string     `json:"gravatarUrl"`
 	GravatarUrl    string     `json:"gravatarUrl"`
 }
 }

+ 1 - 0
pkg/api/index.go

@@ -18,6 +18,7 @@ func setIndexViewData(c *middleware.Context) error {
 		Email:          c.Email,
 		Email:          c.Email,
 		Name:           c.Name,
 		Name:           c.Name,
 		LightTheme:     c.Theme == "light",
 		LightTheme:     c.Theme == "light",
+		OrgId:          c.OrgId,
 		OrgName:        c.OrgName,
 		OrgName:        c.OrgName,
 		OrgRole:        c.OrgRole,
 		OrgRole:        c.OrgRole,
 		GravatarUrl:    dtos.GetGravatarUrl(c.Email),
 		GravatarUrl:    dtos.GetGravatarUrl(c.Email),

+ 7 - 2
pkg/api/login_oauth.go

@@ -3,6 +3,7 @@ package api
 import (
 import (
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"net/url"
 
 
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2"
 
 
@@ -45,7 +46,11 @@ func OAuthLogin(ctx *middleware.Context) {
 
 
 	userInfo, err := connect.UserInfo(token)
 	userInfo, err := connect.UserInfo(token)
 	if err != nil {
 	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?failedMsg=" + url.QueryEscape("Required Github team membership not fulfilled"))
+		} else {
+			ctx.Handle(500, fmt.Sprintf("login.OAuthLogin(get info from %s)", name), err)
+		}
 		return
 		return
 	}
 	}
 
 
@@ -54,7 +59,7 @@ func OAuthLogin(ctx *middleware.Context) {
 	// validate that the email is allowed to login to grafana
 	// validate that the email is allowed to login to grafana
 	if !connect.IsEmailAllowed(userInfo.Email) {
 	if !connect.IsEmailAllowed(userInfo.Email) {
 		log.Info("OAuth login attempt with unallowed email, %s", 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
 		return
 	}
 	}
 
 

+ 60 - 8
pkg/social/social.go

@@ -2,7 +2,9 @@ package social
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
+	"errors"
 	"fmt"
 	"fmt"
+	"net/http"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 
 
@@ -75,13 +77,24 @@ func NewOAuthService() {
 		// GitHub.
 		// GitHub.
 		if name == "github" {
 		if name == "github" {
 			setting.OAuthService.GitHub = true
 			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.
 		// Google.
 		if name == "google" {
 		if name == "google" {
 			setting.OAuthService.Google = true
 			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,
+			}
 		}
 		}
 	}
 	}
 }
 }
@@ -103,10 +116,15 @@ func isEmailAllowed(email string, allowedDomains []string) bool {
 type SocialGithub struct {
 type SocialGithub struct {
 	*oauth2.Config
 	*oauth2.Config
 	allowedDomains []string
 	allowedDomains []string
-	ApiUrl         string
+	apiUrl         string
 	allowSignup    bool
 	allowSignup    bool
+	teamIds        []int
 }
 }
 
 
+var (
+	ErrMissingTeamMembership = errors.New("User not a member of one of the required teams")
+)
+
 func (s *SocialGithub) Type() int {
 func (s *SocialGithub) Type() int {
 	return int(models.GITHUB)
 	return int(models.GITHUB)
 }
 }
@@ -119,6 +137,28 @@ func (s *SocialGithub) IsSignupAllowed() bool {
 	return s.allowSignup
 	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) {
 func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) {
 	var data struct {
 	var data struct {
 		Id    int    `json:"id"`
 		Id    int    `json:"id"`
@@ -128,7 +168,7 @@ func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) {
 
 
 	var err error
 	var err error
 	client := s.Client(oauth2.NoContext, token)
 	client := s.Client(oauth2.NoContext, token)
-	r, err := client.Get(s.ApiUrl)
+	r, err := client.Get(s.apiUrl)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
@@ -139,11 +179,23 @@ func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	return &BasicUserInfo{
+	userInfo := &BasicUserInfo{
 		Identity: strconv.Itoa(data.Id),
 		Identity: strconv.Itoa(data.Id),
 		Name:     data.Name,
 		Name:     data.Name,
 		Email:    data.Email,
 		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
+	}
 }
 }
 
 
 //   ________                     .__
 //   ________                     .__
@@ -156,7 +208,7 @@ func (s *SocialGithub) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) {
 type SocialGoogle struct {
 type SocialGoogle struct {
 	*oauth2.Config
 	*oauth2.Config
 	allowedDomains []string
 	allowedDomains []string
-	ApiUrl         string
+	apiUrl         string
 	allowSignup    bool
 	allowSignup    bool
 }
 }
 
 
@@ -181,7 +233,7 @@ func (s *SocialGoogle) UserInfo(token *oauth2.Token) (*BasicUserInfo, error) {
 	var err error
 	var err error
 
 
 	client := s.Client(oauth2.NoContext, token)
 	client := s.Client(oauth2.NoContext, token)
-	r, err := client.Get(s.ApiUrl)
+	r, err := client.Get(s.apiUrl)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}

+ 2 - 0
public/app/components/kbn.js

@@ -376,6 +376,7 @@ function($, _, moment) {
   kbn.valueFormats.bytes = kbn.formatFuncCreator(1024, [' B', ' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']);
   kbn.valueFormats.bytes = kbn.formatFuncCreator(1024, [' B', ' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']);
   kbn.valueFormats.kbytes = kbn.formatFuncCreator(1024, [' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']);
   kbn.valueFormats.kbytes = kbn.formatFuncCreator(1024, [' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']);
   kbn.valueFormats.mbytes = kbn.formatFuncCreator(1024, [' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']);
   kbn.valueFormats.mbytes = kbn.formatFuncCreator(1024, [' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']);
+  kbn.valueFormats.gbytes = kbn.formatFuncCreator(1024, [' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB']);
   kbn.valueFormats.bps = kbn.formatFuncCreator(1000, [' bps', ' Kbps', ' Mbps', ' Gbps', ' Tbps', ' Pbps', ' Ebps', ' Zbps', ' Ybps']);
   kbn.valueFormats.bps = kbn.formatFuncCreator(1000, [' bps', ' Kbps', ' Mbps', ' Gbps', ' Tbps', ' Pbps', ' Ebps', ' Zbps', ' Ybps']);
   kbn.valueFormats.Bps = kbn.formatFuncCreator(1000, [' Bps', ' KBps', ' MBps', ' GBps', ' TBps', ' PBps', ' EBps', ' ZBps', ' YBps']);
   kbn.valueFormats.Bps = kbn.formatFuncCreator(1000, [' Bps', ' KBps', ' MBps', ' GBps', ' TBps', ' PBps', ' EBps', ' ZBps', ' YBps']);
   kbn.valueFormats.short = kbn.formatFuncCreator(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Qaudr', ' Quint', ' Sext', ' Sept']);
   kbn.valueFormats.short = kbn.formatFuncCreator(1000, ['', ' K', ' Mil', ' Bil', ' Tri', ' Qaudr', ' Quint', ' Sext', ' Sept']);
@@ -547,6 +548,7 @@ function($, _, moment) {
           {text: 'bytes', value: 'bytes'},
           {text: 'bytes', value: 'bytes'},
           {text: 'kilobytes', value: 'kbytes'},
           {text: 'kilobytes', value: 'kbytes'},
           {text: 'megabytes', value: 'mbytes'},
           {text: 'megabytes', value: 'mbytes'},
+          {text: 'gigabytes', value: 'gbytes'},
         ]
         ]
       },
       },
       {
       {

+ 8 - 1
public/app/controllers/loginCtrl.js

@@ -7,7 +7,7 @@ function (angular, config) {
 
 
   var module = angular.module('grafana.controllers');
   var module = angular.module('grafana.controllers');
 
 
-  module.controller('LoginCtrl', function($scope, backendSrv, contextSrv) {
+  module.controller('LoginCtrl', function($scope, backendSrv, contextSrv, $location) {
     $scope.formModel = {
     $scope.formModel = {
       user: '',
       user: '',
       email: '',
       email: '',
@@ -28,6 +28,13 @@ function (angular, config) {
     $scope.init = function() {
     $scope.init = function() {
       $scope.$watch("loginMode", $scope.loginModeChanged);
       $scope.$watch("loginMode", $scope.loginModeChanged);
       $scope.passwordChanged();
       $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
     // build info view model

+ 20 - 7
public/app/features/templating/templateValuesSrv.js

@@ -29,13 +29,7 @@ function (angular, _, kbn) {
         var variable = this.variables[i];
         var variable = this.variables[i];
         var urlValue = queryParams['var-' + variable.name];
         var urlValue = queryParams['var-' + variable.name];
         if (urlValue !== void 0) {
         if (urlValue !== void 0) {
-          var option = _.findWhere(variable.options, { text: urlValue });
-          option = option || { text: urlValue, value: urlValue };
-
-          var promise = this.setVariableValue(variable, option);
-          this.updateAutoInterval(variable);
-
-          promises.push(promise);
+          promises.push(this.setVariableFromUrl(variable, urlValue));
         }
         }
         else if (variable.refresh) {
         else if (variable.refresh) {
           promises.push(this.updateOptions(variable));
           promises.push(this.updateOptions(variable));
@@ -48,6 +42,25 @@ function (angular, _, kbn) {
       return $q.all(promises);
       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) {
     this.updateAutoInterval = function(variable) {
       if (!variable.auto) { return; }
       if (!variable.auto) { return; }
 
 

+ 8 - 13
public/app/plugins/datasource/influxdb/influxSeries.js

@@ -5,7 +5,8 @@ function (_) {
   'use strict';
   'use strict';
 
 
   function InfluxSeries(options) {
   function InfluxSeries(options) {
-    this.seriesList = options.seriesList;
+    this.seriesList = options.seriesList && options.seriesList.results && options.seriesList.results.length > 0
+      ? options.seriesList.results[0].series || [] : [];
     this.alias = options.alias;
     this.alias = options.alias;
     this.annotation = options.annotation;
     this.annotation = options.annotation;
   }
   }
@@ -17,12 +18,10 @@ function (_) {
     var self = this;
     var self = this;
 
 
     console.log(self.seriesList);
     console.log(self.seriesList);
-    if (!self.seriesList || !self.seriesList.results || !self.seriesList.results[0]) {
+    if (self.seriesList.length === 0) {
       return output;
       return output;
     }
     }
 
 
-    this.seriesList = self.seriesList.results[0].series;
-
     _.each(self.seriesList, function(series) {
     _.each(self.seriesList, function(series) {
       var datapoints = [];
       var datapoints = [];
       for (var i = 0; i < series.values.length; i++) {
       for (var i = 0; i < series.values.length; i++) {
@@ -63,19 +62,15 @@ function (_) {
         if (column === self.annotation.textColumn) { textCol = index; return; }
         if (column === self.annotation.textColumn) { textCol = index; return; }
       });
       });
 
 
-      _.each(series.points, function (point) {
+      _.each(series.values, function (value) {
         var data = {
         var data = {
           annotation: self.annotation,
           annotation: self.annotation,
-          time: point[timeCol],
-          title: point[titleCol],
-          tags: point[tagsCol],
-          text: point[textCol]
+          time: + new Date(value[timeCol]),
+          title: value[titleCol],
+          tags: value[tagsCol],
+          text: value[textCol]
         };
         };
 
 
-        if (tagsCol) {
-          data.tags = point[tagsCol];
-        }
-
         list.push(data);
         list.push(data);
       });
       });
     });
     });

+ 2 - 1
public/app/plugins/datasource/influxdb/plugin.json

@@ -13,5 +13,6 @@
     "annotations": "app/plugins/datasource/influxdb/partials/annotations.editor.html"
     "annotations": "app/plugins/datasource/influxdb/partials/annotations.editor.html"
   },
   },
 
 
-  "metrics": true
+  "metrics": true,
+  "annotations": true
 }
 }