Procházet zdrojové kódy

Merge branch 'master' into query-part-refactor

Torkel Ödegaard před 9 roky
rodič
revize
a3ee388b66
78 změnil soubory, kde provedl 2228 přidání a 270 odebrání
  1. 4 0
      .floo
  2. 13 0
      .flooignore
  3. 22 1
      CHANGELOG.md
  4. 5 0
      Godeps/Godeps.json
  5. 1127 0
      Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/api.go
  6. 12 0
      Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/customizations.go
  7. 39 0
      Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/customizations_test.go
  8. 149 0
      Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/examples_test.go
  9. 130 0
      Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/service.go
  10. 38 0
      Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/stsiface/interface.go
  11. 3 2
      README.md
  12. 3 5
      build.go
  13. 3 0
      conf/defaults.ini
  14. 3 0
      conf/sample.ini
  15. 7 0
      docker/blocks/graphite/fig
  16. 8 0
      docker/blocks/influxdb/fig
  17. 7 1
      docker/blocks/opentsdb/fig
  18. 10 0
      docker/blocks/prometheus/fig
  19. 2 0
      docs/sources/datasources/cloudwatch.md
  20. 3 3
      docs/sources/datasources/opentsdb.md
  21. 33 6
      docs/sources/guides/whats-new-in-v3.md
  22. 1 0
      docs/sources/http_api/overview.md
  23. 100 0
      docs/sources/http_api/preferences.md
  24. 3 10
      docs/sources/installation/debian.md
  25. 28 3
      docs/sources/installation/mac.md
  26. 4 23
      docs/sources/installation/rpm.md
  27. 1 1
      docs/sources/installation/windows.md
  28. 1 1
      karma.conf.js
  29. 2 2
      latest.json
  30. 2 2
      package.json
  31. 5 5
      packaging/publish/publish.sh
  32. 81 32
      pkg/api/cloudwatch/cloudwatch.go
  33. 10 8
      pkg/api/cloudwatch/metrics.go
  34. 6 4
      pkg/api/cloudwatch/metrics_test.go
  35. 1 0
      pkg/api/frontendsettings.go
  36. 7 8
      pkg/cmd/grafana-cli/commands/upgrade_command.go
  37. 15 7
      pkg/cmd/grafana-cli/services/services.go
  38. 10 1
      pkg/plugins/queries.go
  39. 2 2
      pkg/plugins/update_checker.go
  40. 3 1
      pkg/services/sqlstore/preferences.go
  41. 18 6
      pkg/setting/setting.go
  42. 3 1
      public/app/app.ts
  43. 1 1
      public/app/core/utils/datemath.ts
  44. 2 0
      public/app/core/utils/kbn.js
  45. 5 4
      public/app/features/annotations/annotations_srv.js
  46. 1 1
      public/app/features/dashboard/dashboardSrv.js
  47. 2 1
      public/app/features/dashboard/dynamicDashboardSrv.js
  48. 1 1
      public/app/features/dashboard/timeSrv.js
  49. 1 1
      public/app/features/panel/metrics_ds_selector.ts
  50. 2 1
      public/app/features/templating/templateSrv.js
  51. 1 1
      public/app/features/templating/templateValuesSrv.js
  52. 7 0
      public/app/plugins/datasource/cloudwatch/partials/config.html
  53. 7 3
      public/app/plugins/datasource/influxdb/datasource.ts
  54. 1 1
      public/app/plugins/datasource/influxdb/partials/query.options.html
  55. 2 1
      public/app/plugins/datasource/opentsdb/config_ctrl.ts
  56. 23 17
      public/app/plugins/datasource/opentsdb/datasource.js
  57. 3 3
      public/app/plugins/datasource/opentsdb/partials/query.editor.html
  58. 7 7
      public/app/plugins/datasource/prometheus/datasource.ts
  59. 11 7
      public/app/plugins/datasource/prometheus/metric_find_query.js
  60. 1 1
      public/app/plugins/datasource/prometheus/query_ctrl.ts
  61. 16 7
      public/app/plugins/datasource/prometheus/specs/metric_find_query_specs.ts
  62. 16 7
      public/app/plugins/panel/graph/graph.js
  63. 15 3
      public/app/plugins/panel/graph/graph_tooltip.js
  64. 1 0
      public/app/plugins/panel/graph/module.ts
  65. 9 3
      public/app/plugins/panel/graph/tab_display.html
  66. 0 32
      public/app/plugins/panel/singlestat/editor.html
  67. 58 0
      public/app/plugins/panel/singlestat/mappings.html
  68. 53 12
      public/app/plugins/panel/singlestat/module.ts
  69. 25 0
      public/app/plugins/panel/singlestat/specs/singlestat-specs.ts
  70. binární
      public/fonts/grafana-icons.eot
  71. 3 3
      public/fonts/grafana-icons.svg
  72. binární
      public/fonts/grafana-icons.ttf
  73. binární
      public/fonts/grafana-icons.woff
  74. 19 17
      public/sass/base/_grafana_icons.scss
  75. 1 0
      public/test/specs/dynamicDashboardSrv-specs.js
  76. 4 0
      public/test/specs/helpers.js
  77. 5 0
      public/test/specs/templateSrv-specs.js
  78. 1 0
      public/test/specs/unsavedChangesSrv-specs.js

+ 4 - 0
.floo

@@ -0,0 +1,4 @@
+{
+  "url": "https://floobits.com/raintank/grafana"
+}
+

+ 13 - 0
.flooignore

@@ -0,0 +1,13 @@
+#*
+*.o
+*.pyc
+*.pyo
+*~
+extern/
+node_modules/
+tmp/
+data/
+vendor/
+public_gen/
+dist/
+

+ 22 - 1
CHANGELOG.md

@@ -1,5 +1,26 @@
-# 3.0.0 stable (unreleased)
+# 3.1.0
 
+### Enhancements
+* **Singlestat**: Add support for range to text mappings, closes [#1319](https://github.com/grafana/grafana/issues/1319)
+* **Graph**: Adds sort order options for graph tooltip, closes  [#1189](https://github.com/grafana/grafana/issues/1189)
+* **Theme**: Add default theme to config file [#5011](https://github.com/grafana/grafana/pull/5011)
+
+# 3.0.3 Patch release (unreleased)
+* **Time picker**: Fixed issue timepicker and UTC when reading time from URL, fixes [#5078](https://github.com/grafana/grafana/issues/5078)
+* **CloudWatch**: Support for Multiple Account by AssumeRole, closes [#3522](https://github.com/grafana/grafana/issues/3522)
+
+# 3.0.2 Patch release (2016-05-16)
+
+* **Templating**: Fixed issue mixing row repeat and panel repeats, fixes [#4988](https://github.com/grafana/grafana/issues/4988)
+* **Templating**: Fixed issue detecting dependencies in nested variables, fixes [#4987](https://github.com/grafana/grafana/issues/4987), fixes [#4986](https://github.com/grafana/grafana/issues/4986)
+* **Graph**: Fixed broken PNG rendering in graph panel, fixes [#5025](https://github.com/grafana/grafana/issues/5025)
+* **Graph**: Fixed broken xaxis on graph panel, fixes [#5024](https://github.com/grafana/grafana/issues/5024)
+
+* **Influxdb**: Fixes crash when hiding middle serie, fixes [#5005](https://github.com/grafana/grafana/issues/5005)
+
+# 3.0.1 Stable (2016-05-11)
+
+### Bug fixes
 * **Templating**: Fixed issue with new data source variable not persisting current selected value, fixes [#4934](https://github.com/grafana/grafana/issues/4934)
 
 # 3.0.0-beta7 (2016-05-02)

+ 5 - 0
Godeps/Godeps.json

@@ -124,6 +124,11 @@
 			"Comment": "v1.0.0",
 			"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
 		},
+		{
+			"ImportPath": "github.com/aws/aws-sdk-go/service/sts",
+			"Comment": "v1.0.0",
+			"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
+		},
 		{
 			"ImportPath": "github.com/bmizerany/assert",
 			"Comment": "release.r60-6-ge17e998",

+ 1127 - 0
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/api.go

@@ -0,0 +1,1127 @@
+// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
+
+// Package sts provides a client for AWS Security Token Service.
+package sts
+
+import (
+	"time"
+
+	"github.com/aws/aws-sdk-go/aws/awsutil"
+	"github.com/aws/aws-sdk-go/aws/request"
+)
+
+const opAssumeRole = "AssumeRole"
+
+// AssumeRoleRequest generates a request for the AssumeRole operation.
+func (c *STS) AssumeRoleRequest(input *AssumeRoleInput) (req *request.Request, output *AssumeRoleOutput) {
+	op := &request.Operation{
+		Name:       opAssumeRole,
+		HTTPMethod: "POST",
+		HTTPPath:   "/",
+	}
+
+	if input == nil {
+		input = &AssumeRoleInput{}
+	}
+
+	req = c.newRequest(op, input, output)
+	output = &AssumeRoleOutput{}
+	req.Data = output
+	return
+}
+
+// Returns a set of temporary security credentials (consisting of an access
+// key ID, a secret access key, and a security token) that you can use to access
+// AWS resources that you might not normally have access to. Typically, you
+// use AssumeRole for cross-account access or federation.
+//
+// Important: You cannot call AssumeRole by using AWS account credentials;
+// access will be denied. You must use IAM user credentials or temporary security
+// credentials to call AssumeRole.
+//
+// For cross-account access, imagine that you own multiple accounts and need
+// to access resources in each account. You could create long-term credentials
+// in each account to access those resources. However, managing all those credentials
+// and remembering which one can access which account can be time consuming.
+// Instead, you can create one set of long-term credentials in one account and
+// then use temporary security credentials to access all the other accounts
+// by assuming roles in those accounts. For more information about roles, see
+// IAM Roles (Delegation and Federation) (http://docs.aws.amazon.com/IAM/latest/UserGuide/roles-toplevel.html)
+// in the Using IAM.
+//
+// For federation, you can, for example, grant single sign-on access to the
+// AWS Management Console. If you already have an identity and authentication
+// system in your corporate network, you don't have to recreate user identities
+// in AWS in order to grant those user identities access to AWS. Instead, after
+// a user has been authenticated, you call AssumeRole (and specify the role
+// with the appropriate permissions) to get temporary security credentials for
+// that user. With those temporary security credentials, you construct a sign-in
+// URL that users can use to access the console. For more information, see Common
+// Scenarios for Temporary Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html#sts-introduction)
+// in the Using IAM.
+//
+// The temporary security credentials are valid for the duration that you specified
+// when calling AssumeRole, which can be from 900 seconds (15 minutes) to 3600
+// seconds (1 hour). The default is 1 hour.
+//
+// Optionally, you can pass an IAM access policy to this operation. If you
+// choose not to pass a policy, the temporary security credentials that are
+// returned by the operation have the permissions that are defined in the access
+// policy of the role that is being assumed. If you pass a policy to this operation,
+// the temporary security credentials that are returned by the operation have
+// the permissions that are allowed by both the access policy of the role that
+// is being assumed, and the policy that you pass. This gives you a way to further
+// restrict the permissions for the resulting temporary security credentials.
+// You cannot use the passed policy to grant permissions that are in excess
+// of those allowed by the access policy of the role that is being assumed.
+// For more information, see Permissions for AssumeRole, AssumeRoleWithSAML,
+// and AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html)
+// in the Using IAM.
+//
+// To assume a role, your AWS account must be trusted by the role. The trust
+// relationship is defined in the role's trust policy when the role is created.
+// You must also have a policy that allows you to call sts:AssumeRole.
+//
+//  Using MFA with AssumeRole
+//
+// You can optionally include multi-factor authentication (MFA) information
+// when you call AssumeRole. This is useful for cross-account scenarios in which
+// you want to make sure that the user who is assuming the role has been authenticated
+// using an AWS MFA device. In that scenario, the trust policy of the role being
+// assumed includes a condition that tests for MFA authentication; if the caller
+// does not include valid MFA information, the request to assume the role is
+// denied. The condition in a trust policy that tests for MFA authentication
+// might look like the following example.
+//
+//  "Condition": {"Bool": {"aws:MultiFactorAuthPresent": true}}
+//
+// For more information, see Configuring MFA-Protected API Access (http://docs.aws.amazon.com/IAM/latest/UserGuide/MFAProtectedAPI.html)
+// in the Using IAM guide.
+//
+// To use MFA with AssumeRole, you pass values for the SerialNumber and TokenCode
+// parameters. The SerialNumber value identifies the user's hardware or virtual
+// MFA device. The TokenCode is the time-based one-time password (TOTP) that
+// the MFA devices produces.
+func (c *STS) AssumeRole(input *AssumeRoleInput) (*AssumeRoleOutput, error) {
+	req, out := c.AssumeRoleRequest(input)
+	err := req.Send()
+	return out, err
+}
+
+const opAssumeRoleWithSAML = "AssumeRoleWithSAML"
+
+// AssumeRoleWithSAMLRequest generates a request for the AssumeRoleWithSAML operation.
+func (c *STS) AssumeRoleWithSAMLRequest(input *AssumeRoleWithSAMLInput) (req *request.Request, output *AssumeRoleWithSAMLOutput) {
+	op := &request.Operation{
+		Name:       opAssumeRoleWithSAML,
+		HTTPMethod: "POST",
+		HTTPPath:   "/",
+	}
+
+	if input == nil {
+		input = &AssumeRoleWithSAMLInput{}
+	}
+
+	req = c.newRequest(op, input, output)
+	output = &AssumeRoleWithSAMLOutput{}
+	req.Data = output
+	return
+}
+
+// Returns a set of temporary security credentials for users who have been authenticated
+// via a SAML authentication response. This operation provides a mechanism for
+// tying an enterprise identity store or directory to role-based AWS access
+// without user-specific credentials or configuration.
+//
+// The temporary security credentials returned by this operation consist of
+// an access key ID, a secret access key, and a security token. Applications
+// can use these temporary security credentials to sign calls to AWS services.
+// The credentials are valid for the duration that you specified when calling
+// AssumeRoleWithSAML, which can be up to 3600 seconds (1 hour) or until the
+// time specified in the SAML authentication response's SessionNotOnOrAfter
+// value, whichever is shorter.
+//
+// The maximum duration for a session is 1 hour, and the minimum duration is
+// 15 minutes, even if values outside this range are specified.  Optionally,
+// you can pass an IAM access policy to this operation. If you choose not to
+// pass a policy, the temporary security credentials that are returned by the
+// operation have the permissions that are defined in the access policy of the
+// role that is being assumed. If you pass a policy to this operation, the temporary
+// security credentials that are returned by the operation have the permissions
+// that are allowed by both the access policy of the role that is being assumed,
+// and the policy that you pass. This gives you a way to further restrict the
+// permissions for the resulting temporary security credentials. You cannot
+// use the passed policy to grant permissions that are in excess of those allowed
+// by the access policy of the role that is being assumed. For more information,
+// see Permissions for AssumeRole, AssumeRoleWithSAML, and AssumeRoleWithWebIdentity
+// (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html)
+// in the Using IAM.
+//
+// Before your application can call AssumeRoleWithSAML, you must configure
+// your SAML identity provider (IdP) to issue the claims required by AWS. Additionally,
+// you must use AWS Identity and Access Management (IAM) to create a SAML provider
+// entity in your AWS account that represents your identity provider, and create
+// an IAM role that specifies this SAML provider in its trust policy.
+//
+// Calling AssumeRoleWithSAML does not require the use of AWS security credentials.
+// The identity of the caller is validated by using keys in the metadata document
+// that is uploaded for the SAML provider entity for your identity provider.
+//
+// For more information, see the following resources:
+//
+//   About SAML 2.0-based Federation (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_saml.html)
+// in the Using IAM.   Creating SAML Identity Providers (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_saml.html)
+// in the Using IAM.   Configuring a Relying Party and Claims (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_saml_relying-party.html)
+// in the Using IAM.   Creating a Role for SAML 2.0 Federation (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-idp_saml.html)
+// in the Using IAM.
+func (c *STS) AssumeRoleWithSAML(input *AssumeRoleWithSAMLInput) (*AssumeRoleWithSAMLOutput, error) {
+	req, out := c.AssumeRoleWithSAMLRequest(input)
+	err := req.Send()
+	return out, err
+}
+
+const opAssumeRoleWithWebIdentity = "AssumeRoleWithWebIdentity"
+
+// AssumeRoleWithWebIdentityRequest generates a request for the AssumeRoleWithWebIdentity operation.
+func (c *STS) AssumeRoleWithWebIdentityRequest(input *AssumeRoleWithWebIdentityInput) (req *request.Request, output *AssumeRoleWithWebIdentityOutput) {
+	op := &request.Operation{
+		Name:       opAssumeRoleWithWebIdentity,
+		HTTPMethod: "POST",
+		HTTPPath:   "/",
+	}
+
+	if input == nil {
+		input = &AssumeRoleWithWebIdentityInput{}
+	}
+
+	req = c.newRequest(op, input, output)
+	output = &AssumeRoleWithWebIdentityOutput{}
+	req.Data = output
+	return
+}
+
+// Returns a set of temporary security credentials for users who have been authenticated
+// in a mobile or web application with a web identity provider, such as Amazon
+// Cognito, Login with Amazon, Facebook, Google, or any OpenID Connect-compatible
+// identity provider.
+//
+//  For mobile applications, we recommend that you use Amazon Cognito. You
+// can use Amazon Cognito with the AWS SDK for iOS (http://aws.amazon.com/sdkforios/)
+// and the AWS SDK for Android (http://aws.amazon.com/sdkforandroid/) to uniquely
+// identify a user and supply the user with a consistent identity throughout
+// the lifetime of an application.
+//
+// To learn more about Amazon Cognito, see Amazon Cognito Overview (http://docs.aws.amazon.com/mobile/sdkforandroid/developerguide/cognito-auth.html#d0e840)
+// in the AWS SDK for Android Developer Guide guide and Amazon Cognito Overview
+// (http://docs.aws.amazon.com/mobile/sdkforios/developerguide/cognito-auth.html#d0e664)
+// in the AWS SDK for iOS Developer Guide.
+//
+//  Calling AssumeRoleWithWebIdentity does not require the use of AWS security
+// credentials. Therefore, you can distribute an application (for example, on
+// mobile devices) that requests temporary security credentials without including
+// long-term AWS credentials in the application, and without deploying server-based
+// proxy services that use long-term AWS credentials. Instead, the identity
+// of the caller is validated by using a token from the web identity provider.
+//
+// The temporary security credentials returned by this API consist of an access
+// key ID, a secret access key, and a security token. Applications can use these
+// temporary security credentials to sign calls to AWS service APIs. The credentials
+// are valid for the duration that you specified when calling AssumeRoleWithWebIdentity,
+// which can be from 900 seconds (15 minutes) to 3600 seconds (1 hour). By default,
+// the temporary security credentials are valid for 1 hour.
+//
+// Optionally, you can pass an IAM access policy to this operation. If you
+// choose not to pass a policy, the temporary security credentials that are
+// returned by the operation have the permissions that are defined in the access
+// policy of the role that is being assumed. If you pass a policy to this operation,
+// the temporary security credentials that are returned by the operation have
+// the permissions that are allowed by both the access policy of the role that
+// is being assumed, and the policy that you pass. This gives you a way to further
+// restrict the permissions for the resulting temporary security credentials.
+// You cannot use the passed policy to grant permissions that are in excess
+// of those allowed by the access policy of the role that is being assumed.
+// For more information, see Permissions for AssumeRole, AssumeRoleWithSAML,
+// and AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html)
+// in the Using IAM.
+//
+// Before your application can call AssumeRoleWithWebIdentity, you must have
+// an identity token from a supported identity provider and create a role that
+// the application can assume. The role that your application assumes must trust
+// the identity provider that is associated with the identity token. In other
+// words, the identity provider must be specified in the role's trust policy.
+//
+// For more information about how to use web identity federation and the AssumeRoleWithWebIdentity
+// API, see the following resources:
+//
+//   Using Web Identity Federation APIs for Mobile Apps (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_oidc_manual)
+// and Federation Through a Web-based Identity Provider (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity).
+//    Web Identity Federation Playground (https://web-identity-federation-playground.s3.amazonaws.com/index.html).
+// This interactive website lets you walk through the process of authenticating
+// via Login with Amazon, Facebook, or Google, getting temporary security credentials,
+// and then using those credentials to make a request to AWS.   AWS SDK for
+// iOS (http://aws.amazon.com/sdkforios/) and AWS SDK for Android (http://aws.amazon.com/sdkforandroid/).
+// These toolkits contain sample apps that show how to invoke the identity providers,
+// and then how to use the information from these providers to get and use temporary
+// security credentials.   Web Identity Federation with Mobile Applications
+// (http://aws.amazon.com/articles/4617974389850313). This article discusses
+// web identity federation and shows an example of how to use web identity federation
+// to get access to content in Amazon S3.
+func (c *STS) AssumeRoleWithWebIdentity(input *AssumeRoleWithWebIdentityInput) (*AssumeRoleWithWebIdentityOutput, error) {
+	req, out := c.AssumeRoleWithWebIdentityRequest(input)
+	err := req.Send()
+	return out, err
+}
+
+const opDecodeAuthorizationMessage = "DecodeAuthorizationMessage"
+
+// DecodeAuthorizationMessageRequest generates a request for the DecodeAuthorizationMessage operation.
+func (c *STS) DecodeAuthorizationMessageRequest(input *DecodeAuthorizationMessageInput) (req *request.Request, output *DecodeAuthorizationMessageOutput) {
+	op := &request.Operation{
+		Name:       opDecodeAuthorizationMessage,
+		HTTPMethod: "POST",
+		HTTPPath:   "/",
+	}
+
+	if input == nil {
+		input = &DecodeAuthorizationMessageInput{}
+	}
+
+	req = c.newRequest(op, input, output)
+	output = &DecodeAuthorizationMessageOutput{}
+	req.Data = output
+	return
+}
+
+// Decodes additional information about the authorization status of a request
+// from an encoded message returned in response to an AWS request.
+//
+// For example, if a user is not authorized to perform an action that he or
+// she has requested, the request returns a Client.UnauthorizedOperation response
+// (an HTTP 403 response). Some AWS actions additionally return an encoded message
+// that can provide details about this authorization failure.
+//
+//  Only certain AWS actions return an encoded authorization message. The documentation
+// for an individual action indicates whether that action returns an encoded
+// message in addition to returning an HTTP code.  The message is encoded because
+// the details of the authorization status can constitute privileged information
+// that the user who requested the action should not see. To decode an authorization
+// status message, a user must be granted permissions via an IAM policy to request
+// the DecodeAuthorizationMessage (sts:DecodeAuthorizationMessage) action.
+//
+// The decoded message includes the following type of information:
+//
+//  Whether the request was denied due to an explicit deny or due to the absence
+// of an explicit allow. For more information, see Determining Whether a Request
+// is Allowed or Denied (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic.html#policy-eval-denyallow)
+// in the Using IAM.  The principal who made the request. The requested action.
+// The requested resource. The values of condition keys in the context of the
+// user's request.
+func (c *STS) DecodeAuthorizationMessage(input *DecodeAuthorizationMessageInput) (*DecodeAuthorizationMessageOutput, error) {
+	req, out := c.DecodeAuthorizationMessageRequest(input)
+	err := req.Send()
+	return out, err
+}
+
+const opGetFederationToken = "GetFederationToken"
+
+// GetFederationTokenRequest generates a request for the GetFederationToken operation.
+func (c *STS) GetFederationTokenRequest(input *GetFederationTokenInput) (req *request.Request, output *GetFederationTokenOutput) {
+	op := &request.Operation{
+		Name:       opGetFederationToken,
+		HTTPMethod: "POST",
+		HTTPPath:   "/",
+	}
+
+	if input == nil {
+		input = &GetFederationTokenInput{}
+	}
+
+	req = c.newRequest(op, input, output)
+	output = &GetFederationTokenOutput{}
+	req.Data = output
+	return
+}
+
+// Returns a set of temporary security credentials (consisting of an access
+// key ID, a secret access key, and a security token) for a federated user.
+// A typical use is in a proxy application that gets temporary security credentials
+// on behalf of distributed applications inside a corporate network. Because
+// you must call the GetFederationToken action using the long-term security
+// credentials of an IAM user, this call is appropriate in contexts where those
+// credentials can be safely stored, usually in a server-based application.
+//
+//   If you are creating a mobile-based or browser-based app that can authenticate
+// users using a web identity provider like Login with Amazon, Facebook, Google,
+// or an OpenID Connect-compatible identity provider, we recommend that you
+// use Amazon Cognito (http://aws.amazon.com/cognito/) or AssumeRoleWithWebIdentity.
+// For more information, see Federation Through a Web-based Identity Provider
+// (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_assumerolewithwebidentity).
+//
+//  The GetFederationToken action must be called by using the long-term AWS
+// security credentials of an IAM user. You can also call GetFederationToken
+// using the security credentials of an AWS account (root), but this is not
+// recommended. Instead, we recommend that you create an IAM user for the purpose
+// of the proxy application and then attach a policy to the IAM user that limits
+// federated users to only the actions and resources they need access to. For
+// more information, see IAM Best Practices (http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html)
+// in the Using IAM.
+//
+// The temporary security credentials that are obtained by using the long-term
+// credentials of an IAM user are valid for the specified duration, between
+// 900 seconds (15 minutes) and 129600 seconds (36 hours). Temporary credentials
+// that are obtained by using AWS account (root) credentials have a maximum
+// duration of 3600 seconds (1 hour)
+//
+//  Permissions
+//
+// The permissions for the temporary security credentials returned by GetFederationToken
+// are determined by a combination of the following:
+//
+//  The policy or policies that are attached to the IAM user whose credentials
+// are used to call GetFederationToken. The policy that is passed as a parameter
+// in the call.  The passed policy is attached to the temporary security credentials
+// that result from the GetFederationToken API call--that is, to the federated
+// user. When the federated user makes an AWS request, AWS evaluates the policy
+// attached to the federated user in combination with the policy or policies
+// attached to the IAM user whose credentials were used to call GetFederationToken.
+// AWS allows the federated user's request only when both the federated user
+// and the IAM user are explicitly allowed to perform the requested action.
+// The passed policy cannot grant more permissions than those that are defined
+// in the IAM user policy.
+//
+// A typical use case is that the permissions of the IAM user whose credentials
+// are used to call GetFederationToken are designed to allow access to all the
+// actions and resources that any federated user will need. Then, for individual
+// users, you pass a policy to the operation that scopes down the permissions
+// to a level that's appropriate to that individual user, using a policy that
+// allows only a subset of permissions that are granted to the IAM user.
+//
+// If you do not pass a policy, the resulting temporary security credentials
+// have no effective permissions. The only exception is when the temporary security
+// credentials are used to access a resource that has a resource-based policy
+// that specifically allows the federated user to access the resource.
+//
+// For more information about how permissions work, see Permissions for GetFederationToken
+// (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_getfederationtoken.html).
+// For information about using GetFederationToken to create temporary security
+// credentials, see GetFederationToken—Federation Through a Custom Identity
+// Broker (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getfederationtoken).
+func (c *STS) GetFederationToken(input *GetFederationTokenInput) (*GetFederationTokenOutput, error) {
+	req, out := c.GetFederationTokenRequest(input)
+	err := req.Send()
+	return out, err
+}
+
+const opGetSessionToken = "GetSessionToken"
+
+// GetSessionTokenRequest generates a request for the GetSessionToken operation.
+func (c *STS) GetSessionTokenRequest(input *GetSessionTokenInput) (req *request.Request, output *GetSessionTokenOutput) {
+	op := &request.Operation{
+		Name:       opGetSessionToken,
+		HTTPMethod: "POST",
+		HTTPPath:   "/",
+	}
+
+	if input == nil {
+		input = &GetSessionTokenInput{}
+	}
+
+	req = c.newRequest(op, input, output)
+	output = &GetSessionTokenOutput{}
+	req.Data = output
+	return
+}
+
+// Returns a set of temporary credentials for an AWS account or IAM user. The
+// credentials consist of an access key ID, a secret access key, and a security
+// token. Typically, you use GetSessionToken if you want to use MFA to protect
+// programmatic calls to specific AWS APIs like Amazon EC2 StopInstances. MFA-enabled
+// IAM users would need to call GetSessionToken and submit an MFA code that
+// is associated with their MFA device. Using the temporary security credentials
+// that are returned from the call, IAM users can then make programmatic calls
+// to APIs that require MFA authentication. If you do not supply a correct MFA
+// code, then the API returns an access denied error.
+//
+// The GetSessionToken action must be called by using the long-term AWS security
+// credentials of the AWS account or an IAM user. Credentials that are created
+// by IAM users are valid for the duration that you specify, between 900 seconds
+// (15 minutes) and 129600 seconds (36 hours); credentials that are created
+// by using account credentials have a maximum duration of 3600 seconds (1 hour).
+//
+//  We recommend that you do not call GetSessionToken with root account credentials.
+// Instead, follow our best practices (http://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#create-iam-users)
+// by creating one or more IAM users, giving them the necessary permissions,
+// and using IAM users for everyday interaction with AWS.
+//
+//  The permissions associated with the temporary security credentials returned
+// by GetSessionToken are based on the permissions associated with account or
+// IAM user whose credentials are used to call the action. If GetSessionToken
+// is called using root account credentials, the temporary credentials have
+// root account permissions. Similarly, if GetSessionToken is called using the
+// credentials of an IAM user, the temporary credentials have the same permissions
+// as the IAM user.
+//
+// For more information about using GetSessionToken to create temporary credentials,
+// go to Temporary Credentials for Users in Untrusted Environments (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_request.html#api_getsessiontoken)
+// in the Using IAM.
+func (c *STS) GetSessionToken(input *GetSessionTokenInput) (*GetSessionTokenOutput, error) {
+	req, out := c.GetSessionTokenRequest(input)
+	err := req.Send()
+	return out, err
+}
+
+type AssumeRoleInput struct {
+	// The duration, in seconds, of the role session. The value can range from 900
+	// seconds (15 minutes) to 3600 seconds (1 hour). By default, the value is set
+	// to 3600 seconds.
+	DurationSeconds *int64 `min:"900" type:"integer"`
+
+	// A unique identifier that is used by third parties when assuming roles in
+	// their customers' accounts. For each role that the third party can assume,
+	// they should instruct their customers to ensure the role's trust policy checks
+	// for the external ID that the third party generated. Each time the third party
+	// assumes the role, they should pass the customer's external ID. The external
+	// ID is useful in order to help third parties bind a role to the customer who
+	// created it. For more information about the external ID, see How to Use an
+	// External ID When Granting Access to Your AWS Resources to a Third Party (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_create_for-user_externalid.html)
+	// in the Using IAM.
+	ExternalId *string `min:"2" type:"string"`
+
+	// An IAM policy in JSON format.
+	//
+	// This parameter is optional. If you pass a policy, the temporary security
+	// credentials that are returned by the operation have the permissions that
+	// are allowed by both (the intersection of) the access policy of the role that
+	// is being assumed, and the policy that you pass. This gives you a way to further
+	// restrict the permissions for the resulting temporary security credentials.
+	// You cannot use the passed policy to grant permissions that are in excess
+	// of those allowed by the access policy of the role that is being assumed.
+	// For more information, see Permissions for AssumeRole, AssumeRoleWithSAML,
+	// and AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html)
+	// in the Using IAM.
+	//
+	// The policy plain text must be 2048 bytes or shorter. However, an internal
+	// conversion compresses it into a packed binary format with a separate limit.
+	// The PackedPolicySize response element indicates by percentage how close to
+	// the upper size limit the policy is, with 100% equaling the maximum allowed
+	// size.
+	Policy *string `min:"1" type:"string"`
+
+	// The Amazon Resource Name (ARN) of the role to assume.
+	RoleArn *string `min:"20" type:"string" required:"true"`
+
+	// An identifier for the assumed role session.
+	//
+	// Use the role session name to uniquely identity a session when the same role
+	// is assumed by different principals or for different reasons. In cross-account
+	// scenarios, the role session name is visible to, and can be logged by the
+	// account that owns the role. The role session name is also used in the ARN
+	// of the assumed role principal. This means that subsequent cross-account API
+	// requests using the temporary security credentials will expose the role session
+	// name to the external account in their CloudTrail logs.
+	RoleSessionName *string `min:"2" type:"string" required:"true"`
+
+	// The identification number of the MFA device that is associated with the user
+	// who is making the AssumeRole call. Specify this value if the trust policy
+	// of the role being assumed includes a condition that requires MFA authentication.
+	// The value is either the serial number for a hardware device (such as GAHT12345678)
+	// or an Amazon Resource Name (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user).
+	SerialNumber *string `min:"9" type:"string"`
+
+	// The value provided by the MFA device, if the trust policy of the role being
+	// assumed requires MFA (that is, if the policy includes a condition that tests
+	// for MFA). If the role being assumed requires MFA and if the TokenCode value
+	// is missing or expired, the AssumeRole call returns an "access denied" error.
+	TokenCode *string `min:"6" type:"string"`
+
+	metadataAssumeRoleInput `json:"-" xml:"-"`
+}
+
+type metadataAssumeRoleInput struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s AssumeRoleInput) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s AssumeRoleInput) GoString() string {
+	return s.String()
+}
+
+// Contains the response to a successful AssumeRole request, including temporary
+// AWS credentials that can be used to make AWS requests.
+type AssumeRoleOutput struct {
+	// The Amazon Resource Name (ARN) and the assumed role ID, which are identifiers
+	// that you can use to refer to the resulting temporary security credentials.
+	// For example, you can reference these credentials as a principal in a resource-based
+	// policy by using the ARN or assumed role ID. The ARN and ID include the RoleSessionName
+	// that you specified when you called AssumeRole.
+	AssumedRoleUser *AssumedRoleUser `type:"structure"`
+
+	// The temporary security credentials, which include an access key ID, a secret
+	// access key, and a security (or session) token.
+	Credentials *Credentials `type:"structure"`
+
+	// A percentage value that indicates the size of the policy in packed form.
+	// The service rejects any policy with a packed size greater than 100 percent,
+	// which means the policy exceeded the allowed space.
+	PackedPolicySize *int64 `type:"integer"`
+
+	metadataAssumeRoleOutput `json:"-" xml:"-"`
+}
+
+type metadataAssumeRoleOutput struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s AssumeRoleOutput) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s AssumeRoleOutput) GoString() string {
+	return s.String()
+}
+
+type AssumeRoleWithSAMLInput struct {
+	// The duration, in seconds, of the role session. The value can range from 900
+	// seconds (15 minutes) to 3600 seconds (1 hour). By default, the value is set
+	// to 3600 seconds. An expiration can also be specified in the SAML authentication
+	// response's SessionNotOnOrAfter value. The actual expiration time is whichever
+	// value is shorter.
+	//
+	// The maximum duration for a session is 1 hour, and the minimum duration is
+	// 15 minutes, even if values outside this range are specified.
+	DurationSeconds *int64 `min:"900" type:"integer"`
+
+	// An IAM policy in JSON format.
+	//
+	// The policy parameter is optional. If you pass a policy, the temporary security
+	// credentials that are returned by the operation have the permissions that
+	// are allowed by both the access policy of the role that is being assumed,
+	// and the policy that you pass. This gives you a way to further restrict the
+	// permissions for the resulting temporary security credentials. You cannot
+	// use the passed policy to grant permissions that are in excess of those allowed
+	// by the access policy of the role that is being assumed. For more information,
+	// Permissions for AssumeRole, AssumeRoleWithSAML, and AssumeRoleWithWebIdentity
+	// (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html)
+	// in the Using IAM.
+	//
+	// The policy plain text must be 2048 bytes or shorter. However, an internal
+	// conversion compresses it into a packed binary format with a separate limit.
+	// The PackedPolicySize response element indicates by percentage how close to
+	// the upper size limit the policy is, with 100% equaling the maximum allowed
+	// size.
+	Policy *string `min:"1" type:"string"`
+
+	// The Amazon Resource Name (ARN) of the SAML provider in IAM that describes
+	// the IdP.
+	PrincipalArn *string `min:"20" type:"string" required:"true"`
+
+	// The Amazon Resource Name (ARN) of the role that the caller is assuming.
+	RoleArn *string `min:"20" type:"string" required:"true"`
+
+	// The base-64 encoded SAML authentication response provided by the IdP.
+	//
+	// For more information, see Configuring a Relying Party and Adding Claims
+	// (http://docs.aws.amazon.com/IAM/latest/UserGuide/create-role-saml-IdP-tasks.html)
+	// in the Using IAM guide.
+	SAMLAssertion *string `min:"4" type:"string" required:"true"`
+
+	metadataAssumeRoleWithSAMLInput `json:"-" xml:"-"`
+}
+
+type metadataAssumeRoleWithSAMLInput struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s AssumeRoleWithSAMLInput) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s AssumeRoleWithSAMLInput) GoString() string {
+	return s.String()
+}
+
+// Contains the response to a successful AssumeRoleWithSAML request, including
+// temporary AWS credentials that can be used to make AWS requests.
+type AssumeRoleWithSAMLOutput struct {
+	// The identifiers for the temporary security credentials that the operation
+	// returns.
+	AssumedRoleUser *AssumedRoleUser `type:"structure"`
+
+	// The value of the Recipient attribute of the SubjectConfirmationData element
+	// of the SAML assertion.
+	Audience *string `type:"string"`
+
+	// AWS credentials for API authentication.
+	Credentials *Credentials `type:"structure"`
+
+	// The value of the Issuer element of the SAML assertion.
+	Issuer *string `type:"string"`
+
+	// A hash value based on the concatenation of the Issuer response value, the
+	// AWS account ID, and the friendly name (the last part of the ARN) of the SAML
+	// provider in IAM. The combination of NameQualifier and Subject can be used
+	// to uniquely identify a federated user.
+	//
+	// The following pseudocode shows how the hash value is calculated:
+	//
+	//  BASE64 ( SHA1 ( "https://example.com/saml" + "123456789012" + "/MySAMLIdP"
+	// ) )
+	NameQualifier *string `type:"string"`
+
+	// A percentage value that indicates the size of the policy in packed form.
+	// The service rejects any policy with a packed size greater than 100 percent,
+	// which means the policy exceeded the allowed space.
+	PackedPolicySize *int64 `type:"integer"`
+
+	// The value of the NameID element in the Subject element of the SAML assertion.
+	Subject *string `type:"string"`
+
+	// The format of the name ID, as defined by the Format attribute in the NameID
+	// element of the SAML assertion. Typical examples of the format are transient
+	// or persistent.
+	//
+	//  If the format includes the prefix urn:oasis:names:tc:SAML:2.0:nameid-format,
+	// that prefix is removed. For example, urn:oasis:names:tc:SAML:2.0:nameid-format:transient
+	// is returned as transient. If the format includes any other prefix, the format
+	// is returned with no modifications.
+	SubjectType *string `type:"string"`
+
+	metadataAssumeRoleWithSAMLOutput `json:"-" xml:"-"`
+}
+
+type metadataAssumeRoleWithSAMLOutput struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s AssumeRoleWithSAMLOutput) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s AssumeRoleWithSAMLOutput) GoString() string {
+	return s.String()
+}
+
+type AssumeRoleWithWebIdentityInput struct {
+	// The duration, in seconds, of the role session. The value can range from 900
+	// seconds (15 minutes) to 3600 seconds (1 hour). By default, the value is set
+	// to 3600 seconds.
+	DurationSeconds *int64 `min:"900" type:"integer"`
+
+	// An IAM policy in JSON format.
+	//
+	// The policy parameter is optional. If you pass a policy, the temporary security
+	// credentials that are returned by the operation have the permissions that
+	// are allowed by both the access policy of the role that is being assumed,
+	// and the policy that you pass. This gives you a way to further restrict the
+	// permissions for the resulting temporary security credentials. You cannot
+	// use the passed policy to grant permissions that are in excess of those allowed
+	// by the access policy of the role that is being assumed. For more information,
+	// see Permissions for AssumeRoleWithWebIdentity (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_assumerole.html)
+	// in the Using IAM.
+	//
+	// The policy plain text must be 2048 bytes or shorter. However, an internal
+	// conversion compresses it into a packed binary format with a separate limit.
+	// The PackedPolicySize response element indicates by percentage how close to
+	// the upper size limit the policy is, with 100% equaling the maximum allowed
+	// size.
+	Policy *string `min:"1" type:"string"`
+
+	// The fully qualified host component of the domain name of the identity provider.
+	//
+	// Specify this value only for OAuth 2.0 access tokens. Currently www.amazon.com
+	// and graph.facebook.com are the only supported identity providers for OAuth
+	// 2.0 access tokens. Do not include URL schemes and port numbers.
+	//
+	// Do not specify this value for OpenID Connect ID tokens.
+	ProviderId *string `min:"4" type:"string"`
+
+	// The Amazon Resource Name (ARN) of the role that the caller is assuming.
+	RoleArn *string `min:"20" type:"string" required:"true"`
+
+	// An identifier for the assumed role session. Typically, you pass the name
+	// or identifier that is associated with the user who is using your application.
+	// That way, the temporary security credentials that your application will use
+	// are associated with that user. This session name is included as part of the
+	// ARN and assumed role ID in the AssumedRoleUser response element.
+	RoleSessionName *string `min:"2" type:"string" required:"true"`
+
+	// The OAuth 2.0 access token or OpenID Connect ID token that is provided by
+	// the identity provider. Your application must get this token by authenticating
+	// the user who is using your application with a web identity provider before
+	// the application makes an AssumeRoleWithWebIdentity call.
+	WebIdentityToken *string `min:"4" type:"string" required:"true"`
+
+	metadataAssumeRoleWithWebIdentityInput `json:"-" xml:"-"`
+}
+
+type metadataAssumeRoleWithWebIdentityInput struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s AssumeRoleWithWebIdentityInput) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s AssumeRoleWithWebIdentityInput) GoString() string {
+	return s.String()
+}
+
+// Contains the response to a successful AssumeRoleWithWebIdentity request,
+// including temporary AWS credentials that can be used to make AWS requests.
+type AssumeRoleWithWebIdentityOutput struct {
+	// The Amazon Resource Name (ARN) and the assumed role ID, which are identifiers
+	// that you can use to refer to the resulting temporary security credentials.
+	// For example, you can reference these credentials as a principal in a resource-based
+	// policy by using the ARN or assumed role ID. The ARN and ID include the RoleSessionName
+	// that you specified when you called AssumeRole.
+	AssumedRoleUser *AssumedRoleUser `type:"structure"`
+
+	// The intended audience (also known as client ID) of the web identity token.
+	// This is traditionally the client identifier issued to the application that
+	// requested the web identity token.
+	Audience *string `type:"string"`
+
+	// The temporary security credentials, which include an access key ID, a secret
+	// access key, and a security token.
+	Credentials *Credentials `type:"structure"`
+
+	// A percentage value that indicates the size of the policy in packed form.
+	// The service rejects any policy with a packed size greater than 100 percent,
+	// which means the policy exceeded the allowed space.
+	PackedPolicySize *int64 `type:"integer"`
+
+	// The issuing authority of the web identity token presented. For OpenID Connect
+	// ID Tokens this contains the value of the iss field. For OAuth 2.0 access
+	// tokens, this contains the value of the ProviderId parameter that was passed
+	// in the AssumeRoleWithWebIdentity request.
+	Provider *string `type:"string"`
+
+	// The unique user identifier that is returned by the identity provider. This
+	// identifier is associated with the WebIdentityToken that was submitted with
+	// the AssumeRoleWithWebIdentity call. The identifier is typically unique to
+	// the user and the application that acquired the WebIdentityToken (pairwise
+	// identifier). For OpenID Connect ID tokens, this field contains the value
+	// returned by the identity provider as the token's sub (Subject) claim.
+	SubjectFromWebIdentityToken *string `min:"6" type:"string"`
+
+	metadataAssumeRoleWithWebIdentityOutput `json:"-" xml:"-"`
+}
+
+type metadataAssumeRoleWithWebIdentityOutput struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s AssumeRoleWithWebIdentityOutput) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s AssumeRoleWithWebIdentityOutput) GoString() string {
+	return s.String()
+}
+
+// The identifiers for the temporary security credentials that the operation
+// returns.
+type AssumedRoleUser struct {
+	// The ARN of the temporary security credentials that are returned from the
+	// AssumeRole action. For more information about ARNs and how to use them in
+	// policies, see IAM Identifiers (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html)
+	// in Using IAM.
+	Arn *string `min:"20" type:"string" required:"true"`
+
+	// A unique identifier that contains the role ID and the role session name of
+	// the role that is being assumed. The role ID is generated by AWS when the
+	// role is created.
+	AssumedRoleId *string `min:"2" type:"string" required:"true"`
+
+	metadataAssumedRoleUser `json:"-" xml:"-"`
+}
+
+type metadataAssumedRoleUser struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s AssumedRoleUser) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s AssumedRoleUser) GoString() string {
+	return s.String()
+}
+
+// AWS credentials for API authentication.
+type Credentials struct {
+	// The access key ID that identifies the temporary security credentials.
+	AccessKeyId *string `min:"16" type:"string" required:"true"`
+
+	// The date on which the current credentials expire.
+	Expiration *time.Time `type:"timestamp" timestampFormat:"iso8601" required:"true"`
+
+	// The secret access key that can be used to sign requests.
+	SecretAccessKey *string `type:"string" required:"true"`
+
+	// The token that users must pass to the service API to use the temporary credentials.
+	SessionToken *string `type:"string" required:"true"`
+
+	metadataCredentials `json:"-" xml:"-"`
+}
+
+type metadataCredentials struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s Credentials) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s Credentials) GoString() string {
+	return s.String()
+}
+
+type DecodeAuthorizationMessageInput struct {
+	// The encoded message that was returned with the response.
+	EncodedMessage *string `min:"1" type:"string" required:"true"`
+
+	metadataDecodeAuthorizationMessageInput `json:"-" xml:"-"`
+}
+
+type metadataDecodeAuthorizationMessageInput struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s DecodeAuthorizationMessageInput) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s DecodeAuthorizationMessageInput) GoString() string {
+	return s.String()
+}
+
+// A document that contains additional information about the authorization status
+// of a request from an encoded message that is returned in response to an AWS
+// request.
+type DecodeAuthorizationMessageOutput struct {
+	// An XML document that contains the decoded message. For more information,
+	// see DecodeAuthorizationMessage.
+	DecodedMessage *string `type:"string"`
+
+	metadataDecodeAuthorizationMessageOutput `json:"-" xml:"-"`
+}
+
+type metadataDecodeAuthorizationMessageOutput struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s DecodeAuthorizationMessageOutput) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s DecodeAuthorizationMessageOutput) GoString() string {
+	return s.String()
+}
+
+// Identifiers for the federated user that is associated with the credentials.
+type FederatedUser struct {
+	// The ARN that specifies the federated user that is associated with the credentials.
+	// For more information about ARNs and how to use them in policies, see IAM
+	// Identifiers (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html)
+	// in Using IAM.
+	Arn *string `min:"20" type:"string" required:"true"`
+
+	// The string that identifies the federated user associated with the credentials,
+	// similar to the unique ID of an IAM user.
+	FederatedUserId *string `min:"2" type:"string" required:"true"`
+
+	metadataFederatedUser `json:"-" xml:"-"`
+}
+
+type metadataFederatedUser struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s FederatedUser) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s FederatedUser) GoString() string {
+	return s.String()
+}
+
+type GetFederationTokenInput struct {
+	// The duration, in seconds, that the session should last. Acceptable durations
+	// for federation sessions range from 900 seconds (15 minutes) to 129600 seconds
+	// (36 hours), with 43200 seconds (12 hours) as the default. Sessions obtained
+	// using AWS account (root) credentials are restricted to a maximum of 3600
+	// seconds (one hour). If the specified duration is longer than one hour, the
+	// session obtained by using AWS account (root) credentials defaults to one
+	// hour.
+	DurationSeconds *int64 `min:"900" type:"integer"`
+
+	// The name of the federated user. The name is used as an identifier for the
+	// temporary security credentials (such as Bob). For example, you can reference
+	// the federated user name in a resource-based policy, such as in an Amazon
+	// S3 bucket policy.
+	Name *string `min:"2" type:"string" required:"true"`
+
+	// An IAM policy in JSON format that is passed with the GetFederationToken call
+	// and evaluated along with the policy or policies that are attached to the
+	// IAM user whose credentials are used to call GetFederationToken. The passed
+	// policy is used to scope down the permissions that are available to the IAM
+	// user, by allowing only a subset of the permissions that are granted to the
+	// IAM user. The passed policy cannot grant more permissions than those granted
+	// to the IAM user. The final permissions for the federated user are the most
+	// restrictive set based on the intersection of the passed policy and the IAM
+	// user policy.
+	//
+	// If you do not pass a policy, the resulting temporary security credentials
+	// have no effective permissions. The only exception is when the temporary security
+	// credentials are used to access a resource that has a resource-based policy
+	// that specifically allows the federated user to access the resource.
+	//
+	// The policy plain text must be 2048 bytes or shorter. However, an internal
+	// conversion compresses it into a packed binary format with a separate limit.
+	// The PackedPolicySize response element indicates by percentage how close to
+	// the upper size limit the policy is, with 100% equaling the maximum allowed
+	// size.  For more information about how permissions work, see Permissions for
+	// GetFederationToken (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_control-access_getfederationtoken.html).
+	Policy *string `min:"1" type:"string"`
+
+	metadataGetFederationTokenInput `json:"-" xml:"-"`
+}
+
+type metadataGetFederationTokenInput struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s GetFederationTokenInput) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s GetFederationTokenInput) GoString() string {
+	return s.String()
+}
+
+// Contains the response to a successful GetFederationToken request, including
+// temporary AWS credentials that can be used to make AWS requests.
+type GetFederationTokenOutput struct {
+	// Credentials for the service API authentication.
+	Credentials *Credentials `type:"structure"`
+
+	// Identifiers for the federated user associated with the credentials (such
+	// as arn:aws:sts::123456789012:federated-user/Bob or 123456789012:Bob). You
+	// can use the federated user's ARN in your resource-based policies, such as
+	// an Amazon S3 bucket policy.
+	FederatedUser *FederatedUser `type:"structure"`
+
+	// A percentage value indicating the size of the policy in packed form. The
+	// service rejects policies for which the packed size is greater than 100 percent
+	// of the allowed value.
+	PackedPolicySize *int64 `type:"integer"`
+
+	metadataGetFederationTokenOutput `json:"-" xml:"-"`
+}
+
+type metadataGetFederationTokenOutput struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s GetFederationTokenOutput) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s GetFederationTokenOutput) GoString() string {
+	return s.String()
+}
+
+type GetSessionTokenInput struct {
+	// The duration, in seconds, that the credentials should remain valid. Acceptable
+	// durations for IAM user sessions range from 900 seconds (15 minutes) to 129600
+	// seconds (36 hours), with 43200 seconds (12 hours) as the default. Sessions
+	// for AWS account owners are restricted to a maximum of 3600 seconds (one hour).
+	// If the duration is longer than one hour, the session for AWS account owners
+	// defaults to one hour.
+	DurationSeconds *int64 `min:"900" type:"integer"`
+
+	// The identification number of the MFA device that is associated with the IAM
+	// user who is making the GetSessionToken call. Specify this value if the IAM
+	// user has a policy that requires MFA authentication. The value is either the
+	// serial number for a hardware device (such as GAHT12345678) or an Amazon Resource
+	// Name (ARN) for a virtual device (such as arn:aws:iam::123456789012:mfa/user).
+	// You can find the device for an IAM user by going to the AWS Management Console
+	// and viewing the user's security credentials.
+	SerialNumber *string `min:"9" type:"string"`
+
+	// The value provided by the MFA device, if MFA is required. If any policy requires
+	// the IAM user to submit an MFA code, specify this value. If MFA authentication
+	// is required, and the user does not provide a code when requesting a set of
+	// temporary security credentials, the user will receive an "access denied"
+	// response when requesting resources that require MFA authentication.
+	TokenCode *string `min:"6" type:"string"`
+
+	metadataGetSessionTokenInput `json:"-" xml:"-"`
+}
+
+type metadataGetSessionTokenInput struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s GetSessionTokenInput) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s GetSessionTokenInput) GoString() string {
+	return s.String()
+}
+
+// Contains the response to a successful GetSessionToken request, including
+// temporary AWS credentials that can be used to make AWS requests.
+type GetSessionTokenOutput struct {
+	// The session credentials for API authentication.
+	Credentials *Credentials `type:"structure"`
+
+	metadataGetSessionTokenOutput `json:"-" xml:"-"`
+}
+
+type metadataGetSessionTokenOutput struct {
+	SDKShapeTraits bool `type:"structure"`
+}
+
+// String returns the string representation
+func (s GetSessionTokenOutput) String() string {
+	return awsutil.Prettify(s)
+}
+
+// GoString returns the string representation
+func (s GetSessionTokenOutput) GoString() string {
+	return s.String()
+}

+ 12 - 0
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/customizations.go

@@ -0,0 +1,12 @@
+package sts
+
+import "github.com/aws/aws-sdk-go/aws/request"
+
+func init() {
+	initRequest = func(r *request.Request) {
+		switch r.Operation.Name {
+		case opAssumeRoleWithSAML, opAssumeRoleWithWebIdentity:
+			r.Handlers.Sign.Clear() // these operations are unsigned
+		}
+	}
+}

+ 39 - 0
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/customizations_test.go

@@ -0,0 +1,39 @@
+package sts_test
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/awstesting/unit"
+	"github.com/aws/aws-sdk-go/service/sts"
+)
+
+var svc = sts.New(unit.Session, &aws.Config{
+	Region: aws.String("mock-region"),
+})
+
+func TestUnsignedRequest_AssumeRoleWithSAML(t *testing.T) {
+	req, _ := svc.AssumeRoleWithSAMLRequest(&sts.AssumeRoleWithSAMLInput{
+		PrincipalArn:  aws.String("ARN01234567890123456789"),
+		RoleArn:       aws.String("ARN01234567890123456789"),
+		SAMLAssertion: aws.String("ASSERT"),
+	})
+
+	err := req.Sign()
+	assert.NoError(t, err)
+	assert.Equal(t, "", req.HTTPRequest.Header.Get("Authorization"))
+}
+
+func TestUnsignedRequest_AssumeRoleWithWebIdentity(t *testing.T) {
+	req, _ := svc.AssumeRoleWithWebIdentityRequest(&sts.AssumeRoleWithWebIdentityInput{
+		RoleArn:          aws.String("ARN01234567890123456789"),
+		RoleSessionName:  aws.String("SESSION"),
+		WebIdentityToken: aws.String("TOKEN"),
+	})
+
+	err := req.Sign()
+	assert.NoError(t, err)
+	assert.Equal(t, "", req.HTTPRequest.Header.Get("Authorization"))
+}

+ 149 - 0
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/examples_test.go

@@ -0,0 +1,149 @@
+// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
+
+package sts_test
+
+import (
+	"bytes"
+	"fmt"
+	"time"
+
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/session"
+	"github.com/aws/aws-sdk-go/service/sts"
+)
+
+var _ time.Duration
+var _ bytes.Buffer
+
+func ExampleSTS_AssumeRole() {
+	svc := sts.New(session.New())
+
+	params := &sts.AssumeRoleInput{
+		RoleArn:         aws.String("arnType"),             // Required
+		RoleSessionName: aws.String("roleSessionNameType"), // Required
+		DurationSeconds: aws.Int64(1),
+		ExternalId:      aws.String("externalIdType"),
+		Policy:          aws.String("sessionPolicyDocumentType"),
+		SerialNumber:    aws.String("serialNumberType"),
+		TokenCode:       aws.String("tokenCodeType"),
+	}
+	resp, err := svc.AssumeRole(params)
+
+	if err != nil {
+		// Print the error, cast err to awserr.Error to get the Code and
+		// Message from an error.
+		fmt.Println(err.Error())
+		return
+	}
+
+	// Pretty-print the response data.
+	fmt.Println(resp)
+}
+
+func ExampleSTS_AssumeRoleWithSAML() {
+	svc := sts.New(session.New())
+
+	params := &sts.AssumeRoleWithSAMLInput{
+		PrincipalArn:    aws.String("arnType"),           // Required
+		RoleArn:         aws.String("arnType"),           // Required
+		SAMLAssertion:   aws.String("SAMLAssertionType"), // Required
+		DurationSeconds: aws.Int64(1),
+		Policy:          aws.String("sessionPolicyDocumentType"),
+	}
+	resp, err := svc.AssumeRoleWithSAML(params)
+
+	if err != nil {
+		// Print the error, cast err to awserr.Error to get the Code and
+		// Message from an error.
+		fmt.Println(err.Error())
+		return
+	}
+
+	// Pretty-print the response data.
+	fmt.Println(resp)
+}
+
+func ExampleSTS_AssumeRoleWithWebIdentity() {
+	svc := sts.New(session.New())
+
+	params := &sts.AssumeRoleWithWebIdentityInput{
+		RoleArn:          aws.String("arnType"),             // Required
+		RoleSessionName:  aws.String("roleSessionNameType"), // Required
+		WebIdentityToken: aws.String("clientTokenType"),     // Required
+		DurationSeconds:  aws.Int64(1),
+		Policy:           aws.String("sessionPolicyDocumentType"),
+		ProviderId:       aws.String("urlType"),
+	}
+	resp, err := svc.AssumeRoleWithWebIdentity(params)
+
+	if err != nil {
+		// Print the error, cast err to awserr.Error to get the Code and
+		// Message from an error.
+		fmt.Println(err.Error())
+		return
+	}
+
+	// Pretty-print the response data.
+	fmt.Println(resp)
+}
+
+func ExampleSTS_DecodeAuthorizationMessage() {
+	svc := sts.New(session.New())
+
+	params := &sts.DecodeAuthorizationMessageInput{
+		EncodedMessage: aws.String("encodedMessageType"), // Required
+	}
+	resp, err := svc.DecodeAuthorizationMessage(params)
+
+	if err != nil {
+		// Print the error, cast err to awserr.Error to get the Code and
+		// Message from an error.
+		fmt.Println(err.Error())
+		return
+	}
+
+	// Pretty-print the response data.
+	fmt.Println(resp)
+}
+
+func ExampleSTS_GetFederationToken() {
+	svc := sts.New(session.New())
+
+	params := &sts.GetFederationTokenInput{
+		Name:            aws.String("userNameType"), // Required
+		DurationSeconds: aws.Int64(1),
+		Policy:          aws.String("sessionPolicyDocumentType"),
+	}
+	resp, err := svc.GetFederationToken(params)
+
+	if err != nil {
+		// Print the error, cast err to awserr.Error to get the Code and
+		// Message from an error.
+		fmt.Println(err.Error())
+		return
+	}
+
+	// Pretty-print the response data.
+	fmt.Println(resp)
+}
+
+func ExampleSTS_GetSessionToken() {
+	svc := sts.New(session.New())
+
+	params := &sts.GetSessionTokenInput{
+		DurationSeconds: aws.Int64(1),
+		SerialNumber:    aws.String("serialNumberType"),
+		TokenCode:       aws.String("tokenCodeType"),
+	}
+	resp, err := svc.GetSessionToken(params)
+
+	if err != nil {
+		// Print the error, cast err to awserr.Error to get the Code and
+		// Message from an error.
+		fmt.Println(err.Error())
+		return
+	}
+
+	// Pretty-print the response data.
+	fmt.Println(resp)
+}

+ 130 - 0
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/service.go

@@ -0,0 +1,130 @@
+// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
+
+package sts
+
+import (
+	"github.com/aws/aws-sdk-go/aws"
+	"github.com/aws/aws-sdk-go/aws/client"
+	"github.com/aws/aws-sdk-go/aws/client/metadata"
+	"github.com/aws/aws-sdk-go/aws/request"
+	"github.com/aws/aws-sdk-go/private/protocol/query"
+	"github.com/aws/aws-sdk-go/private/signer/v4"
+)
+
+// The AWS Security Token Service (STS) is a web service that enables you to
+// request temporary, limited-privilege credentials for AWS Identity and Access
+// Management (IAM) users or for users that you authenticate (federated users).
+// This guide provides descriptions of the STS API. For more detailed information
+// about using this service, go to Temporary Security Credentials (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html).
+//
+//  As an alternative to using the API, you can use one of the AWS SDKs, which
+// consist of libraries and sample code for various programming languages and
+// platforms (Java, Ruby, .NET, iOS, Android, etc.). The SDKs provide a convenient
+// way to create programmatic access to STS. For example, the SDKs take care
+// of cryptographically signing requests, managing errors, and retrying requests
+// automatically. For information about the AWS SDKs, including how to download
+// and install them, see the Tools for Amazon Web Services page (http://aws.amazon.com/tools/).
+//  For information about setting up signatures and authorization through the
+// API, go to Signing AWS API Requests (http://docs.aws.amazon.com/general/latest/gr/signing_aws_api_requests.html"
+// target="_blank) in the AWS General Reference. For general information about
+// the Query API, go to Making Query Requests (http://docs.aws.amazon.com/IAM/latest/UserGuide/IAM_UsingQueryAPI.html"
+// target="_blank) in Using IAM. For information about using security tokens
+// with other AWS products, go to AWS Services That Work with IAM (http://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html)
+// in the Using IAM.
+//
+// If you're new to AWS and need additional technical information about a specific
+// AWS product, you can find the product's technical documentation at http://aws.amazon.com/documentation/
+// (http://aws.amazon.com/documentation/" target="_blank).
+//
+//  Endpoints
+//
+// The AWS Security Token Service (STS) has a default endpoint of https://sts.amazonaws.com
+// that maps to the US East (N. Virginia) region. Additional regions are available,
+// but must first be activated in the AWS Management Console before you can
+// use a different region's endpoint. For more information about activating
+// a region for STS see Activating STS in a New Region (http://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp_enable-regions.html)
+// in the Using IAM.
+//
+// For information about STS endpoints, see Regions and Endpoints (http://docs.aws.amazon.com/general/latest/gr/rande.html#sts_region)
+// in the AWS General Reference.
+//
+//  Recording API requests
+//
+// STS supports AWS CloudTrail, which is a service that records AWS calls for
+// your AWS account and delivers log files to an Amazon S3 bucket. By using
+// information collected by CloudTrail, you can determine what requests were
+// successfully made to STS, who made the request, when it was made, and so
+// on. To learn more about CloudTrail, including how to turn it on and find
+// your log files, see the AWS CloudTrail User Guide (http://docs.aws.amazon.com/awscloudtrail/latest/userguide/what_is_cloud_trail_top_level.html).
+//The service client's operations are safe to be used concurrently.
+// It is not safe to mutate any of the client's properties though.
+type STS struct {
+	*client.Client
+}
+
+// Used for custom client initialization logic
+var initClient func(*client.Client)
+
+// Used for custom request initialization logic
+var initRequest func(*request.Request)
+
+// A ServiceName is the name of the service the client will make API calls to.
+const ServiceName = "sts"
+
+// New creates a new instance of the STS client with a session.
+// If additional configuration is needed for the client instance use the optional
+// aws.Config parameter to add your extra config.
+//
+// Example:
+//     // Create a STS client from just a session.
+//     svc := sts.New(mySession)
+//
+//     // Create a STS client with additional configuration
+//     svc := sts.New(mySession, aws.NewConfig().WithRegion("us-west-2"))
+func New(p client.ConfigProvider, cfgs ...*aws.Config) *STS {
+	c := p.ClientConfig(ServiceName, cfgs...)
+	return newClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
+}
+
+// newClient creates, initializes and returns a new service client instance.
+func newClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string) *STS {
+	svc := &STS{
+		Client: client.New(
+			cfg,
+			metadata.ClientInfo{
+				ServiceName:   ServiceName,
+				SigningRegion: signingRegion,
+				Endpoint:      endpoint,
+				APIVersion:    "2011-06-15",
+			},
+			handlers,
+		),
+	}
+
+	// Handlers
+	svc.Handlers.Sign.PushBack(v4.Sign)
+	svc.Handlers.Build.PushBack(query.Build)
+	svc.Handlers.Unmarshal.PushBack(query.Unmarshal)
+	svc.Handlers.UnmarshalMeta.PushBack(query.UnmarshalMeta)
+	svc.Handlers.UnmarshalError.PushBack(query.UnmarshalError)
+
+	// Run custom client initialization if present
+	if initClient != nil {
+		initClient(svc.Client)
+	}
+
+	return svc
+}
+
+// newRequest creates a new request for a STS operation and runs any
+// custom request initialization.
+func (c *STS) newRequest(op *request.Operation, params, data interface{}) *request.Request {
+	req := c.NewRequest(op, params, data)
+
+	// Run custom request initialization if present
+	if initRequest != nil {
+		initRequest(req)
+	}
+
+	return req
+}

+ 38 - 0
Godeps/_workspace/src/github.com/aws/aws-sdk-go/service/sts/stsiface/interface.go

@@ -0,0 +1,38 @@
+// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
+
+// Package stsiface provides an interface for the AWS Security Token Service.
+package stsiface
+
+import (
+	"github.com/aws/aws-sdk-go/aws/request"
+	"github.com/aws/aws-sdk-go/service/sts"
+)
+
+// STSAPI is the interface type for sts.STS.
+type STSAPI interface {
+	AssumeRoleRequest(*sts.AssumeRoleInput) (*request.Request, *sts.AssumeRoleOutput)
+
+	AssumeRole(*sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
+
+	AssumeRoleWithSAMLRequest(*sts.AssumeRoleWithSAMLInput) (*request.Request, *sts.AssumeRoleWithSAMLOutput)
+
+	AssumeRoleWithSAML(*sts.AssumeRoleWithSAMLInput) (*sts.AssumeRoleWithSAMLOutput, error)
+
+	AssumeRoleWithWebIdentityRequest(*sts.AssumeRoleWithWebIdentityInput) (*request.Request, *sts.AssumeRoleWithWebIdentityOutput)
+
+	AssumeRoleWithWebIdentity(*sts.AssumeRoleWithWebIdentityInput) (*sts.AssumeRoleWithWebIdentityOutput, error)
+
+	DecodeAuthorizationMessageRequest(*sts.DecodeAuthorizationMessageInput) (*request.Request, *sts.DecodeAuthorizationMessageOutput)
+
+	DecodeAuthorizationMessage(*sts.DecodeAuthorizationMessageInput) (*sts.DecodeAuthorizationMessageOutput, error)
+
+	GetFederationTokenRequest(*sts.GetFederationTokenInput) (*request.Request, *sts.GetFederationTokenOutput)
+
+	GetFederationToken(*sts.GetFederationTokenInput) (*sts.GetFederationTokenOutput, error)
+
+	GetSessionTokenRequest(*sts.GetSessionTokenInput) (*request.Request, *sts.GetSessionTokenOutput)
+
+	GetSessionToken(*sts.GetSessionTokenInput) (*sts.GetSessionTokenOutput, error)
+}
+
+var _ STSAPI = (*sts.STS)(nil)

+ 3 - 2
README.md

@@ -16,6 +16,7 @@ Graphite, Elasticsearch, OpenTSDB, Prometheus and InfluxDB.
 - [What's New in Grafana 2.0](http://docs.grafana.org/guides/whats-new-in-v2/)
 - [What's New in Grafana 2.1](http://docs.grafana.org/guides/whats-new-in-v2-1/)
 - [What's New in Grafana 2.5](http://docs.grafana.org/guides/whats-new-in-v2-5/)
+- [What's New in Grafana 3.0](http://docs.grafana.org/guides/whats-new-in-v3/)
 
 ## Features
 ### Graphite Target Editor
@@ -78,7 +79,7 @@ the latest master builds [here](http://grafana.org/download/builds)
 ### Dependencies
 
 - Go 1.5
-- NodeJS v0.12.0
+- NodeJS v4+
 - [Godep](https://github.com/tools/godep)
 
 ### Get Code
@@ -109,7 +110,7 @@ go run build.go build
 
 ### Building frontend assets
 
-To build less to css for the frontend you will need a recent version of of **node (v0.12.0)**,
+To build less to css for the frontend you will need a recent version of of **node (v4+)**,
 npm (v2.5.0) and grunt (v0.4.5). Run the following:
 
 ```bash

+ 3 - 5
build.go

@@ -132,12 +132,10 @@ func readVersionFromPackageJson() {
 	if len(parts) > 1 {
 		linuxPackageVersion = parts[0]
 		linuxPackageIteration = parts[1]
-		if linuxPackageIteration != "" {
-			// add timestamp to iteration
-			linuxPackageIteration = fmt.Sprintf("%s%v", linuxPackageIteration, time.Now().Unix())
-		}
-		log.Println(fmt.Sprintf("Iteration %v", linuxPackageIteration))
 	}
+
+	// add timestamp to iteration
+	linuxPackageIteration = fmt.Sprintf("%d%s", time.Now().Unix(), linuxPackageIteration)
 }
 
 type linuxPackageOptions struct {

+ 3 - 0
conf/defaults.ini

@@ -172,6 +172,9 @@ verify_email_enabled = false
 # Background text for the user field on the login page
 login_hint = email or username
 
+# Default UI theme ("dark" or "light")
+default_theme = dark
+
 #################################### Anonymous Auth ##########################
 [auth.anonymous]
 # enable anonymous access

+ 3 - 0
conf/sample.ini

@@ -155,6 +155,9 @@ check_for_updates = true
 # Background text for the user field on the login page
 ;login_hint = email or username
 
+# Default UI theme ("dark" or "light")
+;default_theme = dark
+
 #################################### Anonymous Auth ##########################
 [auth.anonymous]
 # enable anonymous access

+ 7 - 0
docker/blocks/graphite/fig

@@ -8,3 +8,10 @@ graphite:
     - /etc/localtime:/etc/localtime:ro
     - /etc/timezone:/etc/timezone:ro
 
+fake-graphite-data:
+  image: grafana/fake-data-gen
+  net: bridge
+  environment:
+    FD_DATASOURCE: graphite
+    FD_PORT: 2003
+

+ 8 - 0
docker/blocks/influxdb/fig

@@ -4,3 +4,11 @@ influxdb:
     - "2004:2004"
     - "8083:8083"
     - "8086:8086"
+
+fake-influxdb-data:
+  image: grafana/fake-data-gen
+  net: bridge
+  environment:
+    FD_DATASOURCE: influxdb
+    FD_PORT: 8086
+

+ 7 - 1
docker/blocks/opentsdb/fig

@@ -2,4 +2,10 @@ opentsdb:
   image: opower/opentsdb:latest
   ports:
     - "4242:4242"
-    
+
+fake-opentsdb-data:
+  image: grafana/fake-data-gen
+  net: bridge
+  environment:
+    FD_DATASOURCE: opentsdb
+

+ 10 - 0
docker/blocks/prometheus/fig

@@ -1,6 +1,16 @@
 prometheus:
   build: blocks/prometheus
+  net: bridge
   ports:
     - "9090:9090"
   volumes:
     - /var/docker/prometheus:/prometheus-data
+
+fake-prometheus-data:
+  image: grafana/fake-data-gen
+  net: bridge
+  ports:
+    - "9091:9091"
+  environment:
+    FD_DATASOURCE: prom
+

+ 2 - 0
docs/sources/datasources/cloudwatch.md

@@ -26,6 +26,8 @@ Name | The data source name, important that this is the same as in Grafana v1.x
 Default | Default data source means that it will be pre-selected for new panels.
 Credentials profile name | Specify the name of the profile to use (if you use `~/aws/credentials` file), leave blank for default. This option was introduced in Grafana 2.5.1
 Default Region | Used in query editor to set region (can be changed on per query basis)
+Custom Metrics namespace | Specify the CloudWatch namespace of Custom metrics
+Assume Role Arn | Specify the ARN of the role to assume
 
 ## Authentication
 

+ 3 - 3
docs/sources/datasources/opentsdb.md

@@ -7,10 +7,10 @@ page_keywords: grafana, opentsdb, documentation
 # OpenTSDB Guide
 The newest release of Grafana adds additional functionality when using an OpenTSDB Data source.
 
-![](/img/v2/add_OpenTSDB.jpg)
+![](/img/v2/add_OpenTSDB.png)
 
-1. Open the side menu by clicking the the Grafana icon in the top header. 
-2. In the side menu under the `Dashboards` link you should find a link named `Data Sources`.    
+1. Open the side menu by clicking the the Grafana icon in the top header.
+2. In the side menu under the `Dashboards` link you should find a link named `Data Sources`.
 
     > NOTE: If this link is missing in the side menu it means that your current user does not have the `Admin` role for the current organization.
 

+ 33 - 6
docs/sources/guides/whats-new-in-v3.md

@@ -39,12 +39,13 @@ entire experience right within Grafana.
 
 <img src="/img/v3/grafana_net_tour.png">
 
-A preview of [Grafana.net](http://grafana.net) is launching along with this release. We
-think it’s the perfect compliment to Grafana.
+[Grafana.net](https://grafana.net) offers a central repository where the community can come together to discover, create and
+share plugins (data sources, panels, apps) and dashboards.
 
-Grafana.net currently offers a central repository where the community
-can come together to discover and share plugins (Data Sources, Panels,
-Apps) and Dashboards for Grafana 3.0 and above.
+We are also working on a hosted Graphite-compatible data source that will be optimized for use with Grafana.
+It’ll be easy to combine your existing data source(s) with this OpenSaaS option. Finally, Grafana.net can
+also be a hub to manage all your Grafana instances. You’ll be able to monitor their health and availability,
+perform dashboard backups, and more.
 
 We are also working on a hosted Graphite-compatible Data Source that
 will be optimized for use with Grafana. It’ll be easy to combine your
@@ -65,7 +66,6 @@ Grafana 3.0 comes with a new command line tool called grafana-cli. You
 can easily install plugins from Grafana.net with it. For
 example:
 
-
 ```
 grafana-cli install grafana-pie-chart-panel
 ```
@@ -188,6 +188,33 @@ you can still install manually from [Grafana.net](http://grafana.net)
 * KairosDB: This data source has also no longer shipped with Grafana,
 you can install it manually from [Grafana.net](http://grafana.net)
 
+## Plugin showcase
+
+Discovering and installing plugins is very quick and easy with Grafana 3.0 and [Grafana.net](https://grafana.net). Here
+are a couple that I incurage you try!
+
+#### [Clock Panel](https://grafana.net/plugins/grafana-clock-panel)
+Support's both current time and count down mode.
+<img src="/img/v3/clock_panel.png">
+
+#### [Pie Chart Panel](https://grafana.net/plugins/grafana-piechart-panel)
+A simple pie chart panel is now available as an external plugin.
+<img src="/img/v3/pie_chart_panel.png">
+
+#### [WorldPing App](https://grafana.net/plugins/raintank-worldping-app)
+This is full blown Grafana App that adds new panels, data sources and pages to give
+feature rich global performance monitoring directly from your on-prem Grafana.
+
+<img src="/img/v3/wP-Screenshot-dash-web.png">
+
+#### [Zabbix App](https://grafana.net/plugins/alexanderzobnin-zabbix-app)
+This app contains the already very pouplar Zabbix data source plugin, 2 dashboards and a triggers panel. It is
+created and maintained by [Alexander Zobnin](https://github.com/alexanderzobnin/grafana-zabbix).
+
+<img src="/img/v3/zabbix_app.png">
+
+Checkout the full list of plugins on [Grafana.net](https://grafana.net/plugins)
+
 ## CHANGELOG
 
 For a detailed list and link to github issues for everything included

+ 1 - 0
docs/sources/http_api/overview.md

@@ -18,4 +18,5 @@ dashboards, creating users and updating data sources.
 * [User API](/http_api/user/)
 * [Admin API](/http_api/admin/)
 * [Snapshot API](/http_api/snapshot/)
+* [Preferences API](/http_api/preferences/)
 * [Other API](/http_api/other/)

+ 100 - 0
docs/sources/http_api/preferences.md

@@ -0,0 +1,100 @@
+----
+page_title: Preferences API
+page_description: Grafana Preferences API Reference
+page_keywords: grafana, preferences, http, api, documentation
+---
+
+# User and Org Preferences API
+
+Keys:
+
+- **theme** - One of: ``light``, ``dark``, or an empty string for the default theme
+- **homeDashboardId** - The numerical ``:id`` of a favorited dashboard, default: ``0``
+- **timezone** - One of: ``utc``, ``browser``, or an empty string for the default
+
+Omitting a key will cause the current value to be replaced with the
+system default value.
+
+## Get Current User Prefs
+
+`GET /api/user/preferences`
+
+**Example Request**:
+
+    GET /api/user/preferences HTTP/1.1
+    Accept: application/json
+    Content-Type: application/json
+    Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
+
+**Example Response**:
+
+    HTTP/1.1 200
+    Content-Type: application/json
+
+    {"theme":"","homeDashboardId":0,"timezone":""}
+
+## Update Current User Prefs
+
+`PUT /api/user/preferences`
+
+**Example Request**:
+
+    PUT /api/user/preferences HTTP/1.1
+    Accept: application/json
+    Content-Type: application/json
+    Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
+
+    {
+      "theme": "",
+      "homeDashboardId":0,
+      "timezone":"utc"
+    }
+
+**Example Response**:
+
+    HTTP/1.1 200
+    Content-Type: text/plain; charset=utf-8
+
+    {"message":"Preferences updated"}
+
+## Get Current Org Prefs
+
+`GET /api/org/preferences`
+
+**Example Request**:
+
+    GET /api/org/preferences HTTP/1.1
+    Accept: application/json
+    Content-Type: application/json
+    Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
+
+**Example Response**:
+
+    HTTP/1.1 200
+    Content-Type: application/json
+
+    {"theme":"","homeDashboardId":0,"timezone":""}
+
+## Update Current Org Prefs
+
+`PUT /api/org/preferences`
+
+**Example Request**:
+
+    PUT /api/org/preferences HTTP/1.1
+    Accept: application/json
+    Content-Type: application/json
+    Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
+
+    {
+      "theme": "",
+      "homeDashboardId":0,
+      "timezone":"utc"
+    }
+
+**Example Response**:
+
+    HTTP/1.1 200
+    Content-Type: text/plain; charset=utf-8
+
+    {"message":"Preferences updated"}

+ 3 - 10
docs/sources/installation/debian.md

@@ -10,20 +10,13 @@ page_keywords: grafana, installation, debian, ubuntu, guide
 
 Description | Download
 ------------ | -------------
-Stable .deb for Debian-based Linux | [grafana_2.6.0_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_2.6.0_amd64.deb)
-Beta .deb for Debian-based Linux |   [grafana_3.0.0-beta71462173753_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.0-beta71462173753_amd64.deb)
+Stable .deb for Debian-based Linux | [grafana_3.0.2-1463383025_amd64.deb](https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.2-1463383025_amd64.deb)
 
 ## Install Stable
 
-    $ wget https://grafanarel.s3.amazonaws.com/builds/grafana_2.6.0_amd64.deb
+    $ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.2-1463383025_amd64.deb
     $ sudo apt-get install -y adduser libfontconfig
-    $ sudo dpkg -i grafana_2.6.0_amd64.deb
-
-## Install 3.0 Beta
-
-    $ wget https://grafanarel.s3.amazonaws.com/builds/grafana_3.0.0-beta71462173753_amd64.deb
-    $ sudo apt-get install -y adduser libfontconfig
-    $ sudo dpkg -i grafana_3.0.0-beta71462173753_amd64.deb
+    $ sudo dpkg -i grafana_3.0.2-1463383025_amd64.deb
 
 ## APT Repository
 

+ 28 - 3
docs/sources/installation/mac.md

@@ -6,8 +6,33 @@ page_keywords: grafana, installation, mac, osx, guide
 
 # Installing on Mac
 
-There is currently no binary build for Mac, but Grafana will happily build on Mac. Read the [build from
-source](/project/building_from_source) page for instructions on how to
-build it yourself.
+Installation can be done using [homebrew](http://brew.sh/)
+
+Install latest stable:
+
+```
+brew install grafana/grafana/grafana
+```
+
+To start grafana look at the command printed after the homebrew install completes.
+
+You can also add the grafana as tap.
+
+```
+brew tap grafana/grafana
+brew install grafana
+```
+
+Install latest unstable from master:
+
+```
+brew install --HEAD grafana/grafana/grafana
+```
+
+To upgrade use the reinstall command
+
+```
+brew reinstall --HEAD grafana/grafana/grafana
+```
 
 

+ 4 - 23
docs/sources/installation/rpm.md

@@ -10,43 +10,24 @@ page_keywords: grafana, installation, centos, fedora, opensuse, redhat, guide
 
 Description | Download
 ------------ | -------------
-Stable .RPM for CentOS / Fedora / OpenSuse / Redhat Linux | [grafana-2.6.0-1.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-2.6.0-1.x86_64.rpm)
-Beta .RPM for CentOS / Fedor / OpenSuse / Redhat Linux | [grafana-3.0.0-beta71462173753.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta71462173753.x86_64.rpm)
+Stable .RPM for CentOS / Fedora / OpenSuse / Redhat Linux | [grafana-3.0.2-1463383025.x86_64.rpm](https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.2-1463383025.x86_64.rpm)
 
 ## Install Stable Release from package file
 
 You can install Grafana using Yum directly.
 
-    $ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-2.6.0-1.x86_64.rpm
+    $ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.2-1463383025.x86_64.rpm
 
 Or install manually using `rpm`.
 
 #### On CentOS / Fedora / Redhat:
 
     $ sudo yum install initscripts fontconfig
-    $ sudo rpm -Uvh grafana-2.6.0-1.x86_64.rpm
+    $ sudo rpm -Uvh grafana-3.0.2-1463383025.x86_64.rpm
 
 #### On OpenSuse:
 
-    $ sudo rpm -i --nodeps grafana-2.6.0-1.x86_64.rpm
-
-## Install Beta Release from package file
-
-You can install Grafana using Yum directly.
-
-    $ sudo yum install https://grafanarel.s3.amazonaws.com/builds/grafana-3.0.0-beta71462173753.x86_64.rpm
-
-Or install manually using `rpm`.
-
-#### On CentOS / Fedora / Redhat:
-
-    $ sudo yum install initscripts fontconfig
-    $ sudo rpm -Uvh grafana-3.0.0-beta71462173753.x86_64.rpm
-
-#### On OpenSuse:
-
-    $ sudo rpm -i --nodeps grafana-3.0.0-beta71462173753.x86_64.rpm
-
+    $ sudo rpm -i --nodeps grafana-3.0.2-1463383025.x86_64.rpm
 
 ## Install via YUM Repository
 

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

@@ -10,7 +10,7 @@ page_keywords: grafana, installation, windows guide
 
 Description | Download
 ------------ | -------------
-Stable Zip package for Windows | [grafana.2.6.0.windows-x64.zip](https://grafanarel.s3.amazonaws.com/winbuilds/dist/grafana-2.5.0.windows-x64.zip)
+Stable Zip package for Windows | [grafana.3.0.2.windows-x64.zip](https://grafanarel.s3.amazonaws.com/winbuilds/dist/grafana-3.0.2.windows-x64.zip)
 
 ## Configure
 

+ 1 - 1
karma.conf.js

@@ -26,7 +26,7 @@ module.exports = function(config) {
     browsers: ['PhantomJS'],
     captureTimeout: 20000,
     singleRun: true,
-    autoWatchBatchDelay: 10000,
+    autoWatchBatchDelay: 1000,
     browserNoActivityTimeout: 60000,
 
   });

+ 2 - 2
latest.json

@@ -1,4 +1,4 @@
 {
-  "stable": "2.6.0",
-	"testing": "3.0.0-beta7"
+  "stable": "3.0.2",
+	"testing": "3.0.2"
 }

+ 2 - 2
package.json

@@ -4,7 +4,7 @@
     "company": "Coding Instinct AB"
   },
   "name": "grafana",
-  "version": "3.0.0-beta7",
+  "version": "3.1.0",
   "repository": {
     "type": "git",
     "url": "http://github.com/grafana/grafana.git"
@@ -13,7 +13,7 @@
     "zone.js": "^0.6.6",
     "autoprefixer": "^6.3.3",
     "es6-promise": "^3.0.2",
-    "es6-shim": "^0.35.0",
+    "es6-shim": "^0.35.1",
     "expect.js": "~0.2.0",
     "glob": "~3.2.7",
     "grunt": "~0.4.0",

+ 5 - 5
packaging/publish/publish.sh

@@ -1,7 +1,7 @@
 #! /usr/bin/env bash
 
-deb_ver=3.0.0-beta51460725904
-rpm_ver=3.0.0-beta51460725904
+deb_ver=3.0.1
+rpm_ver=3.0.1-1
 
 #rpm_ver=3.0.0-1
 
@@ -16,7 +16,7 @@ rpm_ver=3.0.0-beta51460725904
 #wget https://grafanarel.s3.amazonaws.com/builds/grafana-${rpm_ver}.x86_64.rpm
 
 #package_cloud push grafana/testing/el/6 grafana-${rpm_ver}.x86_64.rpm
-package_cloud push grafana/testing/el/7 grafana-${rpm_ver}.x86_64.rpm
+#package_cloud push grafana/testing/el/7 grafana-${rpm_ver}.x86_64.rpm
 
-# package_cloud push grafana/stable/el/7 grafana-${version}-1.x86_64.rpm
-# package_cloud push grafana/stable/el/6 grafana-${version}-1.x86_64.rpm
+package_cloud push grafana/stable/el/7 grafana-${rpm_ver}.x86_64.rpm
+package_cloud push grafana/stable/el/6 grafana-${rpm_ver}.x86_64.rpm

+ 81 - 32
pkg/api/cloudwatch/cloudwatch.go

@@ -4,6 +4,8 @@ import (
 	"encoding/json"
 	"errors"
 	"io/ioutil"
+	"strings"
+	"sync"
 	"time"
 
 	"github.com/aws/aws-sdk-go/aws"
@@ -14,6 +16,8 @@ import (
 	"github.com/aws/aws-sdk-go/aws/session"
 	"github.com/aws/aws-sdk-go/service/cloudwatch"
 	"github.com/aws/aws-sdk-go/service/ec2"
+	"github.com/aws/aws-sdk-go/service/sts"
+	"github.com/grafana/grafana/pkg/log"
 	"github.com/grafana/grafana/pkg/middleware"
 	m "github.com/grafana/grafana/pkg/models"
 )
@@ -44,31 +48,96 @@ func init() {
 	}
 }
 
-var awsCredentials map[string]*credentials.Credentials = make(map[string]*credentials.Credentials)
+type cache struct {
+	credential *credentials.Credentials
+	expiration *time.Time
+}
 
-func getCredentials(profile string) *credentials.Credentials {
-	if _, ok := awsCredentials[profile]; ok {
-		return awsCredentials[profile]
+var awsCredentialCache map[string]cache = make(map[string]cache)
+var credentialCacheLock sync.RWMutex
+
+func getCredentials(profile string, region string, assumeRoleArn string) *credentials.Credentials {
+	credentialCacheLock.RLock()
+	if _, ok := awsCredentialCache[profile]; ok {
+		if awsCredentialCache[profile].expiration != nil &&
+			(*awsCredentialCache[profile].expiration).After(time.Now().UTC()) {
+			result := awsCredentialCache[profile].credential
+			credentialCacheLock.RUnlock()
+			return result
+		}
+	}
+	credentialCacheLock.RUnlock()
+
+	accessKeyId := ""
+	secretAccessKey := ""
+	sessionToken := ""
+	var expiration *time.Time
+	expiration = nil
+	if strings.Index(assumeRoleArn, "arn:aws:iam:") == 0 {
+		params := &sts.AssumeRoleInput{
+			RoleArn:         aws.String(assumeRoleArn),
+			RoleSessionName: aws.String("GrafanaSession"),
+			DurationSeconds: aws.Int64(900),
+		}
+
+		stsSess := session.New()
+		stsCreds := credentials.NewChainCredentials(
+			[]credentials.Provider{
+				&credentials.EnvProvider{},
+				&credentials.SharedCredentialsProvider{Filename: "", Profile: profile},
+				&ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(stsSess), ExpiryWindow: 5 * time.Minute},
+			})
+		stsConfig := &aws.Config{
+			Region:      aws.String(region),
+			Credentials: stsCreds,
+		}
+		svc := sts.New(session.New(stsConfig), stsConfig)
+		resp, err := svc.AssumeRole(params)
+		if err != nil {
+			// ignore
+			log.Error(3, "CloudWatch: Failed to assume role", err)
+		}
+		if resp.Credentials != nil {
+			accessKeyId = *resp.Credentials.AccessKeyId
+			secretAccessKey = *resp.Credentials.SecretAccessKey
+			sessionToken = *resp.Credentials.SessionToken
+			expiration = resp.Credentials.Expiration
+		}
 	}
 
 	sess := session.New()
 	creds := credentials.NewChainCredentials(
 		[]credentials.Provider{
+			&credentials.StaticProvider{Value: credentials.Value{
+				AccessKeyID:     accessKeyId,
+				SecretAccessKey: secretAccessKey,
+				SessionToken:    sessionToken,
+			}},
 			&credentials.EnvProvider{},
 			&credentials.SharedCredentialsProvider{Filename: "", Profile: profile},
 			&ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(sess), ExpiryWindow: 5 * time.Minute},
 		})
-	awsCredentials[profile] = creds
+	credentialCacheLock.Lock()
+	awsCredentialCache[profile] = cache{
+		credential: creds,
+		expiration: expiration,
+	}
+	credentialCacheLock.Unlock()
 
 	return creds
 }
 
-func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) {
+func getAwsConfig(req *cwRequest) *aws.Config {
+	assumeRoleArn := req.DataSource.JsonData.Get("assumeRoleArn").MustString()
 	cfg := &aws.Config{
 		Region:      aws.String(req.Region),
-		Credentials: getCredentials(req.DataSource.Database),
+		Credentials: getCredentials(req.DataSource.Database, req.Region, assumeRoleArn),
 	}
+	return cfg
+}
 
+func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) {
+	cfg := getAwsConfig(req)
 	svc := cloudwatch.New(session.New(cfg), cfg)
 
 	reqParam := &struct {
@@ -104,11 +173,7 @@ func handleGetMetricStatistics(req *cwRequest, c *middleware.Context) {
 }
 
 func handleListMetrics(req *cwRequest, c *middleware.Context) {
-	cfg := &aws.Config{
-		Region:      aws.String(req.Region),
-		Credentials: getCredentials(req.DataSource.Database),
-	}
-
+	cfg := getAwsConfig(req)
 	svc := cloudwatch.New(session.New(cfg), cfg)
 
 	reqParam := &struct {
@@ -144,11 +209,7 @@ func handleListMetrics(req *cwRequest, c *middleware.Context) {
 }
 
 func handleDescribeAlarms(req *cwRequest, c *middleware.Context) {
-	cfg := &aws.Config{
-		Region:      aws.String(req.Region),
-		Credentials: getCredentials(req.DataSource.Database),
-	}
-
+	cfg := getAwsConfig(req)
 	svc := cloudwatch.New(session.New(cfg), cfg)
 
 	reqParam := &struct {
@@ -187,11 +248,7 @@ func handleDescribeAlarms(req *cwRequest, c *middleware.Context) {
 }
 
 func handleDescribeAlarmsForMetric(req *cwRequest, c *middleware.Context) {
-	cfg := &aws.Config{
-		Region:      aws.String(req.Region),
-		Credentials: getCredentials(req.DataSource.Database),
-	}
-
+	cfg := getAwsConfig(req)
 	svc := cloudwatch.New(session.New(cfg), cfg)
 
 	reqParam := &struct {
@@ -227,11 +284,7 @@ func handleDescribeAlarmsForMetric(req *cwRequest, c *middleware.Context) {
 }
 
 func handleDescribeAlarmHistory(req *cwRequest, c *middleware.Context) {
-	cfg := &aws.Config{
-		Region:      aws.String(req.Region),
-		Credentials: getCredentials(req.DataSource.Database),
-	}
-
+	cfg := getAwsConfig(req)
 	svc := cloudwatch.New(session.New(cfg), cfg)
 
 	reqParam := &struct {
@@ -263,11 +316,7 @@ func handleDescribeAlarmHistory(req *cwRequest, c *middleware.Context) {
 }
 
 func handleDescribeInstances(req *cwRequest, c *middleware.Context) {
-	cfg := &aws.Config{
-		Region:      aws.String(req.Region),
-		Credentials: getCredentials(req.DataSource.Database),
-	}
-
+	cfg := getAwsConfig(req)
 	svc := ec2.New(session.New(cfg), cfg)
 
 	reqParam := &struct {

+ 10 - 8
pkg/api/cloudwatch/metrics.go

@@ -166,7 +166,8 @@ func handleGetMetrics(req *cwRequest, c *middleware.Context) {
 		}
 	} else {
 		var err error
-		if namespaceMetrics, err = getMetricsForCustomMetrics(req.Region, reqParam.Parameters.Namespace, req.DataSource.Database, getAllMetrics); err != nil {
+		assumeRoleArn := req.DataSource.JsonData.Get("assumeRoleArn").MustString()
+		if namespaceMetrics, err = getMetricsForCustomMetrics(req.Region, reqParam.Parameters.Namespace, req.DataSource.Database, assumeRoleArn, getAllMetrics); err != nil {
 			c.JsonApiErr(500, "Unable to call AWS API", err)
 			return
 		}
@@ -199,7 +200,8 @@ func handleGetDimensions(req *cwRequest, c *middleware.Context) {
 		}
 	} else {
 		var err error
-		if dimensionValues, err = getDimensionsForCustomMetrics(req.Region, reqParam.Parameters.Namespace, req.DataSource.Database, getAllMetrics); err != nil {
+		assumeRoleArn := req.DataSource.JsonData.Get("assumeRoleArn").MustString()
+		if dimensionValues, err = getDimensionsForCustomMetrics(req.Region, reqParam.Parameters.Namespace, req.DataSource.Database, assumeRoleArn, getAllMetrics); err != nil {
 			c.JsonApiErr(500, "Unable to call AWS API", err)
 			return
 		}
@@ -214,10 +216,10 @@ func handleGetDimensions(req *cwRequest, c *middleware.Context) {
 	c.JSON(200, result)
 }
 
-func getAllMetrics(region string, namespace string, database string) (cloudwatch.ListMetricsOutput, error) {
+func getAllMetrics(region string, namespace string, database string, assumeRoleArn string) (cloudwatch.ListMetricsOutput, error) {
 	cfg := &aws.Config{
 		Region:      aws.String(region),
-		Credentials: getCredentials(database),
+		Credentials: getCredentials(database, region, assumeRoleArn),
 	}
 
 	svc := cloudwatch.New(session.New(cfg), cfg)
@@ -244,8 +246,8 @@ func getAllMetrics(region string, namespace string, database string) (cloudwatch
 
 var metricsCacheLock sync.Mutex
 
-func getMetricsForCustomMetrics(region string, namespace string, database string, getAllMetrics func(string, string, string) (cloudwatch.ListMetricsOutput, error)) ([]string, error) {
-	result, err := getAllMetrics(region, namespace, database)
+func getMetricsForCustomMetrics(region string, namespace string, database string, assumeRoleArn string, getAllMetrics func(string, string, string, string) (cloudwatch.ListMetricsOutput, error)) ([]string, error) {
+	result, err := getAllMetrics(region, namespace, database, assumeRoleArn)
 	if err != nil {
 		return []string{}, err
 	}
@@ -282,8 +284,8 @@ func getMetricsForCustomMetrics(region string, namespace string, database string
 
 var dimensionsCacheLock sync.Mutex
 
-func getDimensionsForCustomMetrics(region string, namespace string, database string, getAllMetrics func(string, string, string) (cloudwatch.ListMetricsOutput, error)) ([]string, error) {
-	result, err := getAllMetrics(region, namespace, database)
+func getDimensionsForCustomMetrics(region string, namespace string, database string, assumeRoleArn string, getAllMetrics func(string, string, string, string) (cloudwatch.ListMetricsOutput, error)) ([]string, error) {
+	result, err := getAllMetrics(region, namespace, database, assumeRoleArn)
 	if err != nil {
 		return []string{}, err
 	}

+ 6 - 4
pkg/api/cloudwatch/metrics_test.go

@@ -14,7 +14,8 @@ func TestCloudWatchMetrics(t *testing.T) {
 		region := "us-east-1"
 		namespace := "Foo"
 		database := "default"
-		f := func(region string, namespace string, database string) (cloudwatch.ListMetricsOutput, error) {
+		assumeRoleArn := ""
+		f := func(region string, namespace string, database string, assumeRoleArn string) (cloudwatch.ListMetricsOutput, error) {
 			return cloudwatch.ListMetricsOutput{
 				Metrics: []*cloudwatch.Metric{
 					{
@@ -28,7 +29,7 @@ func TestCloudWatchMetrics(t *testing.T) {
 				},
 			}, nil
 		}
-		metrics, _ := getMetricsForCustomMetrics(region, namespace, database, f)
+		metrics, _ := getMetricsForCustomMetrics(region, namespace, database, assumeRoleArn, f)
 
 		Convey("Should contain Test_MetricName", func() {
 			So(metrics, ShouldContain, "Test_MetricName")
@@ -39,7 +40,8 @@ func TestCloudWatchMetrics(t *testing.T) {
 		region := "us-east-1"
 		namespace := "Foo"
 		database := "default"
-		f := func(region string, namespace string, database string) (cloudwatch.ListMetricsOutput, error) {
+		assumeRoleArn := ""
+		f := func(region string, namespace string, database string, assumeRoleArn string) (cloudwatch.ListMetricsOutput, error) {
 			return cloudwatch.ListMetricsOutput{
 				Metrics: []*cloudwatch.Metric{
 					{
@@ -53,7 +55,7 @@ func TestCloudWatchMetrics(t *testing.T) {
 				},
 			}, nil
 		}
-		dimensionKeys, _ := getDimensionsForCustomMetrics(region, namespace, database, f)
+		dimensionKeys, _ := getDimensionsForCustomMetrics(region, namespace, database, assumeRoleArn, f)
 
 		Convey("Should contain Test_DimensionName", func() {
 			So(dimensionKeys, ShouldContain, "Test_DimensionName")

+ 1 - 0
pkg/api/frontendsettings.go

@@ -142,6 +142,7 @@ func getFrontendSettingsMap(c *middleware.Context) (map[string]interface{}, erro
 			"buildstamp":    setting.BuildStamp,
 			"latestVersion": plugins.GrafanaLatestVersion,
 			"hasUpdate":     plugins.GrafanaHasUpdate,
+			"env":           setting.Env,
 		},
 	}
 

+ 7 - 8
pkg/cmd/grafana-cli/commands/upgrade_command.go

@@ -1,6 +1,8 @@
 package commands
 
 import (
+	"github.com/fatih/color"
+	"github.com/grafana/grafana/pkg/cmd/grafana-cli/log"
 	s "github.com/grafana/grafana/pkg/cmd/grafana-cli/services"
 )
 
@@ -14,20 +16,17 @@ func upgradeCommand(c CommandLine) error {
 		return err
 	}
 
-	remotePlugins, err2 := s.ListAllPlugins(c.GlobalString("repo"))
+	v, err2 := s.GetPlugin(localPlugin.Id, c.GlobalString("repo"))
 
 	if err2 != nil {
 		return err2
 	}
 
-	for _, v := range remotePlugins.Plugins {
-		if localPlugin.Id == v.Id {
-			if ShouldUpgrade(localPlugin.Info.Version, v) {
-				s.RemoveInstalledPlugin(pluginsDir, pluginName)
-				return InstallPlugin(localPlugin.Id, "", c)
-			}
-		}
+	if ShouldUpgrade(localPlugin.Info.Version, v) {
+		s.RemoveInstalledPlugin(pluginsDir, pluginName)
+		return InstallPlugin(localPlugin.Id, "", c)
 	}
 
+	log.Infof("%s %s is up to date \n", color.GreenString("✔"), localPlugin.Id)
 	return nil
 }

+ 15 - 7
pkg/cmd/grafana-cli/services/services.go

@@ -44,7 +44,7 @@ func ReadPlugin(pluginDir, pluginName string) (m.InstalledPlugin, error) {
 	}
 
 	if res.Id == "" {
-		return m.InstalledPlugin{}, errors.New("could not read find plugin " + pluginName)
+		return m.InstalledPlugin{}, errors.New("could not find plugin " + pluginName + " in " + pluginDir)
 	}
 
 	return res, nil
@@ -69,13 +69,21 @@ func RemoveInstalledPlugin(pluginPath, id string) error {
 }
 
 func GetPlugin(pluginId, repoUrl string) (m.Plugin, error) {
-	resp, _ := ListAllPlugins(repoUrl)
+	fullUrl := repoUrl + "/repo/" + pluginId
 
-	for _, i := range resp.Plugins {
-		if i.Id == pluginId {
-			return i, nil
-		}
+	res, err := goreq.Request{Uri: fullUrl, MaxRedirects: 3}.Do()
+	if err != nil {
+		return m.Plugin{}, err
+	}
+	if res.StatusCode != 200 {
+		return m.Plugin{}, fmt.Errorf("Could not access %s statuscode %v", fullUrl, res.StatusCode)
 	}
 
-	return m.Plugin{}, errors.New("could not find plugin named \"" + pluginId + "\"")
+	var resp m.Plugin
+	err = res.Body.FromJsonTo(&resp)
+	if err != nil {
+		return m.Plugin{}, errors.New("Could not load plugin data")
+	}
+
+	return resp, nil
 }

+ 10 - 1
pkg/plugins/queries.go

@@ -24,7 +24,16 @@ func GetPluginSettings(orgId int64) (map[string]*m.PluginSettingInfoDTO, error)
 		}
 
 		// default to enabled true
-		opt := &m.PluginSettingInfoDTO{Enabled: true}
+		opt := &m.PluginSettingInfoDTO{
+			PluginId: pluginDef.Id,
+			OrgId:    orgId,
+			Enabled:  true,
+		}
+
+		// apps are disabled by default
+		if pluginDef.Type == PluginTypeApp {
+			opt.Enabled = false
+		}
 
 		// if it's included in app check app settings
 		if pluginDef.IncludedInAppId != "" {

+ 2 - 2
pkg/plugins/update_checker.go

@@ -91,14 +91,14 @@ func checkForUpdates() {
 
 	resp2, err := client.Get("https://raw.githubusercontent.com/grafana/grafana/master/latest.json")
 	if err != nil {
-		log.Trace("Failed to get lates.json repo from github: %v", err.Error())
+		log.Trace("Failed to get latest.json repo from github: %v", err.Error())
 		return
 	}
 
 	defer resp2.Body.Close()
 	body, err = ioutil.ReadAll(resp2.Body)
 	if err != nil {
-		log.Trace("Update check failed, reading response from github.net, %v", err.Error())
+		log.Trace("Update check failed, reading response from github.com, %v", err.Error())
 		return
 	}
 

+ 3 - 1
pkg/services/sqlstore/preferences.go

@@ -5,6 +5,8 @@ import (
 
 	"github.com/grafana/grafana/pkg/bus"
 	m "github.com/grafana/grafana/pkg/models"
+
+	"github.com/grafana/grafana/pkg/setting"
 )
 
 func init() {
@@ -26,7 +28,7 @@ func GetPreferencesWithDefaults(query *m.GetPreferencesWithDefaultsQuery) error
 	}
 
 	res := &m.Preferences{
-		Theme:           "dark",
+		Theme:           setting.DefaultTheme,
 		Timezone:        "browser",
 		HomeDashboardId: 0,
 	}

+ 18 - 6
pkg/setting/setting.go

@@ -88,6 +88,7 @@ var (
 	AutoAssignOrgRole  string
 	VerifyEmailEnabled bool
 	LoginHint          string
+	DefaultTheme       string
 
 	// Http auth
 	AdminUser     string
@@ -454,6 +455,7 @@ func NewConfigContext(args *CommandLineArgs) error {
 	AutoAssignOrgRole = users.Key("auto_assign_org_role").In("Editor", []string{"Editor", "Admin", "Read Only Editor", "Viewer"})
 	VerifyEmailEnabled = users.Key("verify_email_enabled").MustBool(false)
 	LoginHint = users.Key("login_hint").String()
+	DefaultTheme = users.Key("default_theme").String()
 
 	// anonymous access
 	AnonymousEnabled = Cfg.Section("auth.anonymous").Key("enabled").MustBool(false)
@@ -526,6 +528,17 @@ var logLevels = map[string]int{
 	"Critical": 5,
 }
 
+func getLogLevel(key string, defaultName string) (string, int) {
+	levelName := Cfg.Section(key).Key("level").In(defaultName, []string{"Trace", "Debug", "Info", "Warn", "Error", "Critical"})
+
+	level, ok := logLevels[levelName]
+	if !ok {
+		log.Fatal(4, "Unknown log level: %s", levelName)
+	}
+
+	return levelName, level
+}
+
 func initLogging(args *CommandLineArgs) {
 	//close any existing log handlers.
 	log.Close()
@@ -533,8 +546,12 @@ func initLogging(args *CommandLineArgs) {
 	LogModes = strings.Split(Cfg.Section("log").Key("mode").MustString("console"), ",")
 	LogsPath = makeAbsolute(Cfg.Section("paths").Key("logs").String(), HomePath)
 
+	defaultLevelName, _ := getLogLevel("log", "Info")
+
 	LogConfigs = make([]util.DynMap, len(LogModes))
+
 	for i, mode := range LogModes {
+
 		mode = strings.TrimSpace(mode)
 		sec, err := Cfg.GetSection("log." + mode)
 		if err != nil {
@@ -542,12 +559,7 @@ func initLogging(args *CommandLineArgs) {
 		}
 
 		// Log level.
-		levelName := Cfg.Section("log."+mode).Key("level").In("Trace",
-			[]string{"Trace", "Debug", "Info", "Warn", "Error", "Critical"})
-		level, ok := logLevels[levelName]
-		if !ok {
-			log.Fatal(4, "Unknown log level: %s", levelName)
-		}
+		_, level := getLogLevel("log."+mode, defaultLevelName)
 
 		// Generate log configuration.
 		switch mode {

+ 3 - 1
public/app/app.ts

@@ -42,7 +42,9 @@ export class GrafanaApp {
     app.constant('grafanaVersion', "@grafanaVersion@");
 
     app.config(($locationProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) => {
-      //$compileProvider.debugInfoEnabled(false);
+      if (config.buildInfo.env !== 'development') {
+        $compileProvider.debugInfoEnabled(false);
+      }
 
       this.registerFunctions.controller = $controllerProvider.register;
       this.registerFunctions.directive  = $compileProvider.directive;

+ 1 - 1
public/app/core/utils/datemath.ts

@@ -28,7 +28,7 @@ export function parse(text, roundUp?) {
       mathString = text.substring(index + 2);
     }
     // We're going to just require ISO8601 timestamps, k?
-    time = moment(parseString);
+    time = moment(parseString, moment.ISO_8601);
   }
 
   if (!mathString.length) {

+ 2 - 0
public/app/core/utils/kbn.js

@@ -396,6 +396,7 @@ function($, _) {
   kbn.valueFormats.ev           = kbn.formatBuilders.decimalSIPrefix('eV');
   kbn.valueFormats.amp          = kbn.formatBuilders.decimalSIPrefix('A');
   kbn.valueFormats.volt         = kbn.formatBuilders.decimalSIPrefix('V');
+  kbn.valueFormats.dBm          = kbn.formatBuilders.decimalSIPrefix('dBm');
 
   // Temperature
   kbn.valueFormats.celsius   = kbn.formatBuilders.fixedUnit('°C');
@@ -677,6 +678,7 @@ function($, _) {
           {text: 'electron volt (eV)',         value: 'ev'          },
           {text: 'Ampere (A)',                 value: 'amp'         },
           {text: 'Volt (V)',                   value: 'volt'        },
+          {text: 'Decibel-milliwatt (dBm)',    value: 'dBm'         },
         ]
       },
       {

+ 5 - 4
public/app/features/annotations/annotations_srv.js

@@ -55,10 +55,11 @@ define([
         }, this);
       });
 
-      promiseCached = $q.all(promises)
-        .then(function() {
-          return list;
-        });
+      promiseCached = $q.all(promises).then(function() {
+        return list;
+      }).catch(function(err) {
+        $rootScope.appEvent('alert-error', ['Annotations failed', (err.message || err)]);
+      });
 
       return promiseCached;
     };

+ 1 - 1
public/app/features/dashboard/dashboardSrv.js

@@ -65,7 +65,7 @@ function (angular, $, _, moment) {
 
     // cleans meta data and other non peristent state
     p.getSaveModelClone = function() {
-      var copy = angular.copy(this);
+      var copy = $.extend(true, {}, this);
       delete copy.meta;
       return copy;
     };

+ 2 - 1
public/app/features/dashboard/dynamicDashboardSrv.js

@@ -52,6 +52,8 @@ function (angular, _) {
           else if (panel.repeatPanelId && panel.repeatIteration !== this.iteration) {
             row.panels = _.without(row.panels, panel);
             j = j - 1;
+          } else if (row.repeat || row.repeatRowId) {
+            continue;
           } else if (!_.isEmpty(panel.scopedVars) && panel.repeatIteration !== this.iteration) {
             panel.scopedVars = {};
           }
@@ -118,7 +120,6 @@ function (angular, _) {
           panel = copy.panels[i];
           panel.scopedVars = {};
           panel.scopedVars[variable.name] = option;
-          panel.repeatIteration = this.iteration;
         }
       }, this);
     };

+ 1 - 1
public/app/features/dashboard/timeSrv.js

@@ -50,7 +50,7 @@ define([
 
       if (!isNaN(value)) {
         var epoch = parseInt(value);
-        return moment(epoch);
+        return moment.utc(epoch);
       }
 
       return null;

+ 1 - 1
public/app/features/panel/metrics_ds_selector.ts

@@ -10,7 +10,7 @@ var template = `
   <div class="gf-form-inline">
     <div class="gf-form">
       <label class="gf-form-label">
-        <i class="icon-gf icon-gf-datasource"></i>
+        <i class="icon-gf icon-gf-datasources"></i>
       </label>
       <label class="gf-form-label">
         Panel data source

+ 2 - 1
public/app/features/templating/templateSrv.js

@@ -97,7 +97,8 @@ function (angular, _) {
       if (!str) {
         return false;
       }
-      return str.indexOf('$' + variableName) !== -1 || str.indexOf('[[' + variableName + ']]') !== -1;
+      var match = this._regex.exec(str);
+      return match && (match[1] === variableName || match[2] === variableName);
     };
 
     this.highlightVariablesAsHtml = function(str) {

+ 1 - 1
public/app/features/templating/templateValuesSrv.js

@@ -204,7 +204,7 @@ function (angular, _, kbn) {
       }
 
       if (options.length === 0) {
-        options.push({text: 'No datasurces found', value: ''});
+        options.push({text: 'No data sources found', value: ''});
       }
 
       variable.options = options;

+ 7 - 0
public/app/plugins/datasource/cloudwatch/partials/config.html

@@ -24,4 +24,11 @@
 			Namespaces of Custom Metrics
 		</info-popover>
 	</div>
+	<div class="gf-form">
+		<label class="gf-form-label width-13">Assume Role ARN</label>
+		<input type="text" class="gf-form-input max-width-18" ng-model='ctrl.current.jsonData.assumeRoleArn' placeholder="arn:aws:iam:*"></input>
+		<info-popover mode="right-absolute">
+			ARN of Assume Role
+		</info-popover>
+	</div>
 </div>

+ 7 - 3
public/app/plugins/datasource/influxdb/datasource.ts

@@ -45,7 +45,7 @@ export default class InfluxDatasource {
     var i, y;
 
     var allQueries = _.map(options.targets, (target) => {
-      if (target.hide) { return []; }
+      if (target.hide) { return ""; }
 
       queryTargets.push(target);
 
@@ -54,8 +54,12 @@ export default class InfluxDatasource {
       var query =  queryModel.render(true);
       query = query.replace(/\$interval/g, (target.interval || options.interval));
       return query;
-
-    }).join(";");
+    }).reduce((acc, current) => {
+      if (current !== "") {
+        acc += ";" + current;
+      }
+      return acc;
+    });
 
     // replace grafana variables
     allQueries = allQueries.replace(/\$timeFilter/g, timeFilter);

+ 1 - 1
public/app/plugins/datasource/influxdb/partials/query.options.html

@@ -45,7 +45,7 @@
 			<ul>
 				<li>$m = replaced with measurement name</li>
 				<li>$measurement = replaced with measurement name</li>
-				<li>$1 - $9 = replaced with part of measurement name (if you seperate your measurement name with dots)</li>
+				<li>$1 - $9 = replaced with part of measurement name (if you separate your measurement name with dots)</li>
 				<li>$col = replaced with column name</li>
 				<li>$tag_hostname = replaced with the value of the hostname tag</li>
 				<li>You can also use [[tag_hostname]] pattern replacement syntax</li>

+ 2 - 1
public/app/plugins/datasource/opentsdb/config_ctrl.ts

@@ -16,7 +16,8 @@ export class OpenTsConfigCtrl {
 
   tsdbVersions = [
     {name: '<=2.1', value: 1},
-    {name: '>=2.2', value: 2},
+    {name: '==2.2', value: 2},
+    {name: '==2.3', value: 3},
   ];
 
   tsdbResolutions = [

+ 23 - 17
public/app/plugins/datasource/opentsdb/datasource.js

@@ -54,13 +54,12 @@ function (angular, _, dateMath) {
       });
 
       return this.performTimeSeriesQuery(queries, start, end).then(function(response) {
-        var metricToTargetMapping = mapMetricsToTargets(response.data, options);
+        var metricToTargetMapping = mapMetricsToTargets(response.data, options, this.tsdbVersion);
         var result = _.map(response.data, function(metricData, index) {
           index = metricToTargetMapping[index];
           if (index === -1) {
             index = 0;
           }
-
           this._saveTagKeys(metricData);
 
           return transformMetricData(metricData, groupByTags, options.targets[index], options, this.tsdbResolution);
@@ -114,6 +113,9 @@ function (angular, _, dateMath) {
         msResolution: msResolution,
         globalAnnotations: true
       };
+      if (this.tsdbVersion === 3) {
+        reqBody.showQuery = true;
+      }
 
       // Relative queries (e.g. last hour) don't include an end time
       if (end) {
@@ -393,23 +395,27 @@ function (angular, _, dateMath) {
       return query;
     }
 
-    function mapMetricsToTargets(metrics, options) {
+    function mapMetricsToTargets(metrics, options, tsdbVersion) {
       var interpolatedTagValue;
       return _.map(metrics, function(metricData) {
-        return _.findIndex(options.targets, function(target) {
-          if (target.filters && target.filters.length > 0) {
-            return target.metric === metricData.metric &&
-            _.all(target.filters, function(filter) {
-              return filter.tagk === interpolatedTagValue === "*";
-            });
-          } else {
-            return target.metric === metricData.metric &&
-            _.all(target.tags, function(tagV, tagK) {
-              interpolatedTagValue = templateSrv.replace(tagV, options.scopedVars, 'pipe');
-              return metricData.tags[tagK] === interpolatedTagValue || interpolatedTagValue === "*";
-            });
-          }
-        });
+        if (tsdbVersion === 3) {
+          return metricData.query.index;
+        } else {
+          return _.findIndex(options.targets, function(target) {
+            if (target.filters && target.filters.length > 0) {
+              return target.metric === metricData.metric &&
+              _.all(target.filters, function(filter) {
+                return filter.tagk === interpolatedTagValue === "*";
+              });
+            } else {
+              return target.metric === metricData.metric &&
+              _.all(target.tags, function(tagV, tagK) {
+                interpolatedTagValue = templateSrv.replace(tagV, options.scopedVars, 'pipe');
+                return metricData.tags[tagK] === interpolatedTagValue || interpolatedTagValue === "*";
+              });
+            }
+          });
+        }
       });
     }
 

+ 3 - 3
public/app/plugins/datasource/opentsdb/partials/query.editor.html

@@ -69,7 +69,7 @@
 			</div>
 		</div>
 
-		<div class="gf-form" ng-if="ctrl.tsdbVersion == 2">
+		<div class="gf-form" ng-if="ctrl.tsdbVersion >= 2">
 			<label class="gf-form-label query-keyword width-6">Fill</label>
 			<div class="gf-form-select-wrapper">
 				<select ng-model="ctrl.target.downsampleFillPolicy" class="gf-form-input"
@@ -91,7 +91,7 @@
 		</div>
 	</div>
 
-	<div class="gf-form-inline" ng-if="ctrl.tsdbVersion == 2">
+	<div class="gf-form-inline" ng-if="ctrl.tsdbVersion >= 2">
 		<div class="gf-form">
 
 			<label class="gf-form-label query-keyword width-8">
@@ -170,7 +170,7 @@
 		<div class="gf-form">
 			<label class="gf-form-label query-keyword width-8">
 				Tags
-				<info-popover mode="right-normal" ng-if="ctrl.tsdbVersion == 2">
+				<info-popover mode="right-normal" ng-if="ctrl.tsdbVersion >= 2">
 					Please use filters, tags are deprecated in opentsdb 2.2
 				</info-popover>
 			</label>

+ 7 - 7
public/app/plugins/datasource/prometheus/datasource.ts

@@ -10,7 +10,7 @@ import PrometheusMetricFindQuery from './metric_find_query';
 var durationSplitRegexp = /(\d+)(ms|s|m|h|d|w|M|y)/;
 
 /** @ngInject */
-export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv) {
+export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateSrv, timeSrv) {
   this.type = 'prometheus';
   this.editorSrc = 'app/features/prometheus/partials/query.editor.html';
   this.name = instanceSettings.name;
@@ -43,7 +43,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
     return value.replace(/[\\^$*+?.()|[\]{}]/g, '\\\\$&');
   }
 
-  function interpolateQueryExpr(value, variable, defaultFormatFn) {
+  this.interpolateQueryExpr = function(value, variable, defaultFormatFn) {
     // if no multi or include all do not regexEscape
     if (!variable.multi && !variable.includeAll) {
       return value;
@@ -59,6 +59,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
 
   // Called once per panel (graph)
   this.query = function(options) {
+    var self = this;
     var start = getPrometheusTime(options.range.from, false);
     var end = getPrometheusTime(options.range.to, true);
 
@@ -73,7 +74,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
       activeTargets.push(target);
 
       var query: any = {};
-      query.expr = templateSrv.replace(target.expr, options.scopedVars, interpolateQueryExpr);
+      query.expr = templateSrv.replace(target.expr, options.scopedVars, self.interpolateQueryExpr);
 
       var interval = target.interval || options.interval;
       var intervalFactor = target.intervalFactor || 1;
@@ -99,7 +100,6 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
       return this.performTimeSeriesQuery(query, start, end);
     }, this));
 
-    var self = this;
     return $q.all(allQueryPromise)
     .then(function(allResponse) {
       var result = [];
@@ -140,12 +140,12 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
 
     var interpolated;
     try {
-      interpolated = templateSrv.replace(query);
+      interpolated = templateSrv.replace(query, {}, this.interpolateQueryExpr);
     } catch (err) {
       return $q.reject(err);
     }
 
-    var metricFindQuery = new PrometheusMetricFindQuery(this, interpolated);
+    var metricFindQuery = new PrometheusMetricFindQuery(this, interpolated, timeSrv);
     return metricFindQuery.process();
   };
 
@@ -160,7 +160,7 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
 
     var interpolated;
     try {
-      interpolated = templateSrv.replace(expr, {}, interpolateQueryExpr);
+      interpolated = templateSrv.replace(expr, {}, this.interpolateQueryExpr);
     } catch (err) {
       return $q.reject(err);
     }

+ 11 - 7
public/app/plugins/datasource/prometheus/metric_find_query.js

@@ -1,13 +1,13 @@
 define([
-  'lodash',
-  'moment',
+  'lodash'
 ],
-function (_, moment) {
+function (_) {
   'use strict';
 
-  function PrometheusMetricFindQuery(datasource, query) {
+  function PrometheusMetricFindQuery(datasource, query, timeSrv) {
     this.datasource = datasource;
     this.query = query;
+    this.range = timeSrv.timeRange();
   }
 
   PrometheusMetricFindQuery.prototype.process = function() {
@@ -51,7 +51,9 @@ function (_, moment) {
         });
       });
     } else {
-      url = '/api/v1/series?match[]=' + encodeURIComponent(metric);
+      url = '/api/v1/series?match[]=' + encodeURIComponent(metric)
+        + '&start=' + (this.range.from.valueOf() / 1000)
+        + '&end=' + (this.range.to.valueOf() / 1000);
 
       return this.datasource._request('GET', url)
       .then(function(result) {
@@ -86,7 +88,7 @@ function (_, moment) {
   };
 
   PrometheusMetricFindQuery.prototype.queryResultQuery = function(query) {
-    var url = '/api/v1/query?query=' + encodeURIComponent(query) + '&time=' + (moment().valueOf() / 1000);
+    var url = '/api/v1/query?query=' + encodeURIComponent(query) + '&time=' + (this.range.to.valueOf() / 1000);
 
     return this.datasource._request('GET', url)
     .then(function(result) {
@@ -107,7 +109,9 @@ function (_, moment) {
   };
 
   PrometheusMetricFindQuery.prototype.metricNameAndLabelsQuery = function(query) {
-    var url = '/api/v1/series?match[]=' + encodeURIComponent(query);
+    var url = '/api/v1/series?match[]=' + encodeURIComponent(query)
+      + '&start=' + (this.range.from.valueOf() / 1000)
+      + '&end=' + (this.range.to.valueOf() / 1000);
 
     var self = this;
     return this.datasource._request('GET', url)

+ 1 - 1
public/app/plugins/datasource/prometheus/query_ctrl.ts

@@ -83,7 +83,7 @@ class PrometheusQueryCtrl extends QueryCtrl {
     var rangeDiff = Math.ceil((range.to.valueOf() - range.from.valueOf()) / 1000);
     var endTime = range.to.utc().format('YYYY-MM-DD HH:mm');
     var expr = {
-      expr: this.templateSrv.replace(this.target.expr, this.panelCtrl.panel.scopedVars),
+      expr: this.templateSrv.replace(this.target.expr, this.panelCtrl.panel.scopedVars, this.datasource.interpolateQueryExpr),
       range_input: rangeDiff + 's',
       end_input: endTime,
       step_input: '',

+ 16 - 7
public/app/plugins/datasource/prometheus/specs/metric_find_query_specs.ts

@@ -28,7 +28,7 @@ describe('PrometheusMetricFindQuery', function() {
         data: ["value1", "value2", "value3"]
       };
       ctx.$httpBackend.expect('GET', 'proxied/api/v1/label/resource/values').respond(response);
-      var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(resource)');
+      var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(resource)', ctx.timeSrv);
       pm.process().then(function(data) { results = data; });
       ctx.$httpBackend.flush();
       ctx.$rootScope.$apply();
@@ -43,13 +43,22 @@ describe('PrometheusMetricFindQuery', function() {
           {__name__: "metric", resource: "value3"}
         ]
       };
-      ctx.$httpBackend.expect('GET', 'proxied/api/v1/series?match[]=metric').respond(response);
-      var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(metric, resource)');
+      ctx.$httpBackend.expect('GET', /proxied\/api\/v1\/series\?match\[\]=metric&start=.*&end=.*/).respond(response);
+      var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(metric, resource)', ctx.timeSrv);
       pm.process().then(function(data) { results = data; });
       ctx.$httpBackend.flush();
       ctx.$rootScope.$apply();
       expect(results.length).to.be(3);
     });
+    it('label_values(metric, resource) should pass correct time', function() {
+      ctx.timeSrv.setTime({ from: moment.utc('2011-01-01'), to: moment.utc('2015-01-01') });
+      ctx.$httpBackend.expect('GET',
+        /proxied\/api\/v1\/series\?match\[\]=metric&start=1293840000&end=1420070400/).respond(response);
+      var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(metric, resource)', ctx.timeSrv);
+      pm.process().then(function(data) { results = data; });
+      ctx.$httpBackend.flush();
+      ctx.$rootScope.$apply();
+    });
     it('label_values(metric{label1="foo", label2="bar", label3="baz"}, resource) should generate series query', function() {
       response = {
         status: "success",
@@ -59,8 +68,8 @@ describe('PrometheusMetricFindQuery', function() {
           {__name__: "metric", resource: "value3"}
         ]
       };
-      ctx.$httpBackend.expect('GET', 'proxied/api/v1/series?match[]=metric').respond(response);
-      var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(metric, resource)');
+      ctx.$httpBackend.expect('GET', /proxied\/api\/v1\/series\?match\[\]=metric&start=.*&end=.*/).respond(response);
+      var pm = new PrometheusMetricFindQuery(ctx.ds, 'label_values(metric, resource)', ctx.timeSrv);
       pm.process().then(function(data) { results = data; });
       ctx.$httpBackend.flush();
       ctx.$rootScope.$apply();
@@ -72,7 +81,7 @@ describe('PrometheusMetricFindQuery', function() {
         data: ["metric1","metric2","metric3","nomatch"]
       };
       ctx.$httpBackend.expect('GET', 'proxied/api/v1/label/__name__/values').respond(response);
-      var pm = new PrometheusMetricFindQuery(ctx.ds, 'metrics(metric.*)');
+      var pm = new PrometheusMetricFindQuery(ctx.ds, 'metrics(metric.*)', ctx.timeSrv);
       pm.process().then(function(data) { results = data; });
       ctx.$httpBackend.flush();
       ctx.$rootScope.$apply();
@@ -90,7 +99,7 @@ describe('PrometheusMetricFindQuery', function() {
         }
       };
       ctx.$httpBackend.expect('GET', /proxied\/api\/v1\/query\?query=metric&time=.*/).respond(response);
-      var pm = new PrometheusMetricFindQuery(ctx.ds, 'query_result(metric)');
+      var pm = new PrometheusMetricFindQuery(ctx.ds, 'query_result(metric)', ctx.timeSrv);
       pm.process().then(function(data) { results = data; });
       ctx.$httpBackend.flush();
       ctx.$rootScope.$apply();

+ 16 - 7
public/app/plugins/panel/graph/graph.js

@@ -282,7 +282,7 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
 
           options.xaxis = {
             timezone: dashboard.getTimezone(),
-            show: panel['x-axis'],
+            show: panel.xaxis.show,
             mode: "time",
             min: min,
             max: max,
@@ -452,12 +452,21 @@ function (angular, $, moment, _, kbn, GraphTooltip) {
           url += panel.fill !== 0 ? ('&areaAlpha=' + (panel.fill/10).toFixed(1)) : '';
           url += panel.linewidth !== 0 ? '&lineWidth=' + panel.linewidth : '';
           url += panel.legend.show ? '&hideLegend=false' : '&hideLegend=true';
-          url += panel.grid.leftMin !== null ? '&yMin=' + panel.grid.leftMin : '';
-          url += panel.grid.leftMax !== null ? '&yMax=' + panel.grid.leftMax : '';
-          url += panel.grid.rightMin !== null ? '&yMin=' + panel.grid.rightMin : '';
-          url += panel.grid.rightMax !== null ? '&yMax=' + panel.grid.rightMax : '';
-          url += panel['x-axis'] ? '' : '&hideAxes=true';
-          url += panel['y-axis'] ? '' : '&hideYAxis=true';
+
+          if (panel.yaxes && panel.yaxes.length > 0) {
+            var showYaxis = false;
+            for(var i = 0; panel.yaxes.length > i; i++) {
+              if (panel.yaxes[i].show) {
+                url += (panel.yaxes[i].min !== null && panel.yaxes[i].min !== undefined) ? '&yMin=' + panel.yaxes[i].min : '';
+                url += (panel.yaxes[i].max !== null && panel.yaxes[i].max !== undefined) ? '&yMax=' + panel.yaxes[i].max : '';
+                showYaxis = true;
+                break;
+              }
+            }
+            url += showYaxis ? '' : '&hideYAxis=true';
+          }
+
+          url += panel.xaxis.show ? '' : '&hideAxes=true';
 
           switch(panel.yaxes[0].format) {
             case 'bytes':

+ 15 - 3
public/app/plugins/panel/graph/graph_tooltip.js

@@ -81,9 +81,9 @@ function ($) {
           // Stacked series can increase its length on each new stacked serie if null points found,
           // to speed the index search we begin always on the last found hoverIndex.
           var newhoverIndex = this.findHoverIndexFromDataPoints(pos.x, series, hoverIndex);
-          results.push({ value: value, hoverIndex: newhoverIndex });
+          results.push({ value: value, hoverIndex: newhoverIndex, color: series.color, label: series.label });
         } else {
-          results.push({ value: value, hoverIndex: hoverIndex });
+          results.push({ value: value, hoverIndex: hoverIndex, color: series.color, label: series.label });
         }
       }
 
@@ -133,6 +133,18 @@ function ($) {
 
         absoluteTime = dashboard.formatDate(seriesHoverInfo.time, tooltipFormat);
 
+        // Dynamically reorder the hovercard for the current time point if the
+        // option is enabled.
+        if (panel.tooltip.ordering === 'decreasing') {
+          seriesHoverInfo.sort(function(a, b) {
+            return parseFloat(b.value) - parseFloat(a.value);
+          });
+        } else if (panel.tooltip.ordering === 'increasing') {
+          seriesHoverInfo.sort(function(a, b) {
+            return parseFloat(a.value) - parseFloat(b.value);
+          });
+        }
+
         for (i = 0; i < seriesHoverInfo.length; i++) {
           hoverInfo = seriesHoverInfo[i];
 
@@ -150,7 +162,7 @@ function ($) {
           value = series.formatValue(hoverInfo.value);
 
           seriesHtml += '<div class="graph-tooltip-list-item ' + highlightClass + '"><div class="graph-tooltip-series-name">';
-          seriesHtml += '<i class="fa fa-minus" style="color:' + series.color +';"></i> ' + series.label + ':</div>';
+          seriesHtml += '<i class="fa fa-minus" style="color:' + hoverInfo.color +';"></i> ' + hoverInfo.label + ':</div>';
           seriesHtml += '<div class="graph-tooltip-value">' + value + '</div></div>';
           plot.highlight(i, hoverInfo.hoverIndex);
         }

+ 1 - 0
public/app/plugins/panel/graph/module.ts

@@ -92,6 +92,7 @@ class GraphCtrl extends MetricsPanelCtrl {
     tooltip       : {
       value_type: 'cumulative',
       shared: true,
+      ordering: 'alphabetical',
       msResolution: false,
     },
     // time overrides

+ 9 - 3
public/app/plugins/panel/graph/tab_display.html

@@ -42,23 +42,29 @@
 	<div class="section gf-form-group">
 		<h5 class="section-heading">Misc options</h5>
 		<div class="gf-form">
-			<label class="gf-form-label width-7">Null value</label>
+			<label class="gf-form-label width-9">Null value</label>
 			<div class="gf-form-select-wrapper">
 				<select class="gf-form-input max-width-8" ng-model="ctrl.panel.nullPointMode" ng-options="f for f in ['connected', 'null', 'null as zero']" ng-change="ctrl.render()"></select>
 			</div>
 		</div>
 		<div class="gf-form">
-			<label class="gf-form-label width-7">Renderer</label>
+			<label class="gf-form-label width-9">Renderer</label>
 			<div class="gf-form-select-wrapper max-width-8">
 				<select class="gf-form-input" ng-model="ctrl.panel.renderer" ng-options="f for f in ['flot', 'png']" ng-change="ctrl.render()"></select>
 			</div>
 		</div>
 		<div class="gf-form">
-			<label class="gf-form-label width-7">Tooltip mode</label>
+			<label class="gf-form-label width-9">Tooltip mode</label>
 			<div class="gf-form-select-wrapper max-width-8">
 				<select class="gf-form-input" ng-model="ctrl.panel.tooltip.shared" ng-options="f.value as f.text for f in [{text: 'All series', value: true}, {text: 'Single', value: false}]" ng-change="ctrl.render()"></select>
 			</div>
 		</div>
+		<div class="gf-form">
+			<label class="gf-form-label width-9">Tooltip ordering<tip>The ordering from top to bottom</tip></label>
+			<div class="gf-form-select-wrapper max-width-8">
+				<select class="gf-form-input" ng-model="ctrl.panel.tooltip.ordering" ng-options="f.value as f.text for f in [{text: 'Alphabetical', value: 'alphabetical'}, {text: 'Increasing', value: 'increasing'}, {text: 'Decreasing', value: 'decreasing'}]" ng-change="ctrl.render()"></select>
+			</div>
+		</div>
 	</div>
 
 	<div class="section gf-form-group">

+ 0 - 32
public/app/plugins/panel/singlestat/editor.html

@@ -204,35 +204,3 @@
 		</div>
 	</div>
 </div>
-
-<div class="editor-row">
-	<div class="section" style="margin-bottom: 20px">
-		<div class="tight-form last">
-			<ul class="tight-form-list">
-				<li class="tight-form-item">
-					<strong>Value to text mapping</strong>
-				</li>
-				<li class="tight-form-item"  ng-repeat-start="map in ctrl.panel.valueMaps">
-					<i class="fa fa-remove pointer" ng-click="ctrl.removeValueMap(map)"></i>
-				</li>
-				<li>
-					<input type="text" ng-model="map.value" placeholder="value" class="input-mini tight-form-input" ng-blur="ctrl.render()">
-				</li>
-				<li class="tight-form-item">
-					<i class="fa fa-arrow-right"></i>
-				</li>
-				<li ng-repeat-end>
-					<input type="text" placeholder="text" ng-model="map.text" class="input-mini tight-form-input" ng-blur="ctrl.render()">
-				</li>
-
-				<li>
-					<a class="pointer tight-form-item last" ng-click="ctrl.addValueMap();">
-						<i class="fa fa-plus"></i>
-					</a>
-				</li>
-
-			</ul>
-			<div class="clearfix"></div>
-		</div>
-	</div>
-</div>

+ 58 - 0
public/app/plugins/panel/singlestat/mappings.html

@@ -0,0 +1,58 @@
+<div class="editor-row">
+  <div class="gf-form-group">
+    <div class="gf-form">
+        <span class="gf-form-label">
+          Type
+        </span>
+        <div class="gf-form-select-wrapper">
+          <select class="gf-form-input" ng-model="ctrl.panel.mappingType"
+                                                        ng-options="f.value as f.name for f in ctrl.panel.mappingTypes" ng-change="ctrl.render()"></select>
+        </div>
+    </div>
+  </div>
+</div>
+<div class="editor-row" ng-if="ctrl.panel.mappingType==1">
+  <h5 class="page-heading">Set value mappings</h5>
+  <div class="gf-form-group">
+    <div class="gf-form" ng-repeat="map in ctrl.panel.valueMaps">
+      <span class="gf-form-label">
+        <i class="fa fa-remove pointer" ng-click="ctrl.removeValueMap(map)"></i>
+      </span>
+      <input type="text" ng-model="map.value" placeholder="value" class="gf-form-input max-width-6" ng-blur="ctrl.render()">
+      <span class="gf-form-label">
+        <i class="fa fa-arrow-right"></i>
+      </span>
+      <input type="text" placeholder="text" ng-model="map.text" class="gf-form-input max-width-8" ng-blur="ctrl.render()">
+    </div>
+
+    <div class="gf-form-button-row">
+      <button class="btn btn-inverse" ng-click="ctrl.addValueMap();">
+        <i class="fa fa-plus"></i>
+        Add a value mapping
+      </button>
+    </div>
+  </div>
+</div>
+<div class="editor-row" ng-if="ctrl.panel.mappingType==2">
+  <h5 class="page-heading">Set range mappings</h5>
+  <div class="gf-form-group">
+    <div class="gf-form" ng-repeat="rangeMap in ctrl.panel.rangeMaps">
+        <span class="gf-form-label">
+          <i class="fa fa-remove pointer" ng-click="ctrl.removeRangeMap(rangeMap)"></i>
+        </span>
+        <span class="gf-form-label">From</span>
+        <input type="text" ng-model="rangeMap.from" class="gf-form-input max-width-6" ng-blur="ctrl.render()">
+        <span class="gf-form-label">To</span>
+        <input type="text" ng-model="rangeMap.to" class="gf-form-input max-width-6" ng-blur="ctrl.render()">
+        <span class="gf-form-label">Text</span>
+        <input type="text" ng-model="rangeMap.text" class="gf-form-input max-width-8" ng-blur="ctrl.render()">
+    </div>
+
+    <div class="gf-form-button-row">
+      <button class="btn btn-inverse" ng-click="ctrl.addRangeMap()">
+        <i class="fa fa-plus"></i>
+        Add a range mapping
+      </button>
+    </div>
+  </div>
+</div>

+ 53 - 12
public/app/plugins/panel/singlestat/module.ts

@@ -35,6 +35,14 @@ class SingleStatCtrl extends MetricsPanelCtrl {
     valueMaps: [
       { value: 'null', op: '=', text: 'N/A' }
     ],
+    mappingTypes: [
+      {name: 'value to text', value: 1},
+      {name: 'range to text', value: 2},
+    ],
+    rangeMaps: [
+      { from: 'null', to: 'null', text: 'N/A' }
+    ],
+    mappingType: 1,
     nullPointMode: 'connected',
     valueName: 'avg',
     prefixFontSize: '50%',
@@ -73,6 +81,7 @@ class SingleStatCtrl extends MetricsPanelCtrl {
   onInitEditMode() {
     this.fontSizes = ['20%', '30%','50%','70%','80%','100%', '110%', '120%', '150%', '170%', '200%'];
     this.addEditorTab('Options', 'public/app/plugins/panel/singlestat/editor.html', 2);
+    this.addEditorTab('Value Mappings', 'public/app/plugins/panel/singlestat/mappings.html', 3);
     this.unitFormats = kbn.getUnitFormats();
   }
 
@@ -192,23 +201,45 @@ class SingleStatCtrl extends MetricsPanelCtrl {
       }
     }
 
-    // check value to text mappings
-    for (var i = 0; i < this.panel.valueMaps.length; i++) {
-      var map = this.panel.valueMaps[i];
-      // special null case
-      if (map.value === 'null') {
-        if (data.value === null || data.value === void 0) {
+    // check value to text mappings if its enabled
+    if (this.panel.mappingType === 1) {
+      for (var i = 0; i < this.panel.valueMaps.length; i++) {
+        var map = this.panel.valueMaps[i];
+        // special null case
+        if (map.value === 'null') {
+          if (data.value === null || data.value === void 0) {
+            data.valueFormated = map.text;
+            return;
+          }
+          continue;
+        }
+
+        // value/number to text mapping
+        var value = parseFloat(map.value);
+        if (value === data.valueRounded) {
           data.valueFormated = map.text;
           return;
         }
-        continue;
       }
+    } else if (this.panel.mappingType === 2) {
+      for (var i = 0; i < this.panel.rangeMaps.length; i++) {
+        var map = this.panel.rangeMaps[i];
+        // special null case
+        if (map.from === 'null' && map.to === 'null') {
+          if (data.value === null || data.value === void 0) {
+            data.valueFormated = map.text;
+            return;
+          }
+          continue;
+        }
 
-      // value/number to text mapping
-      var value = parseFloat(map.value);
-      if (value === data.valueRounded) {
-        data.valueFormated = map.text;
-        return;
+        // value/number to range mapping
+        var from = parseFloat(map.from);
+        var to = parseFloat(map.to);
+        if (to >= data.valueRounded && from <= data.valueRounded) {
+          data.valueFormated = map.text;
+          return;
+        }
       }
     }
 
@@ -227,6 +258,16 @@ class SingleStatCtrl extends MetricsPanelCtrl {
     this.panel.valueMaps.push({value: '', op: '=', text: '' });
   }
 
+  removeRangeMap(rangeMap) {
+    var index = _.indexOf(this.panel.rangeMaps, rangeMap);
+    this.panel.rangeMaps.splice(index, 1);
+    this.render();
+  };
+
+  addRangeMap() {
+    this.panel.rangeMaps.push({from: '', to: '', text: ''});
+  }
+
   link(scope, elem, attrs, ctrl) {
     var $location = this.$location;
     var linkSrv = this.linkSrv;

+ 25 - 0
public/app/plugins/panel/singlestat/specs/singlestat-specs.ts

@@ -84,4 +84,29 @@ describe('SingleStatCtrl', function() {
       expect(ctx.data.valueFormated).to.be('OK');
     });
   });
+
+  singleStatScenario('When range to text mapping is specifiedfor first range', function(ctx) {
+    ctx.setup(function() {
+      ctx.datapoints = [[41,50]];
+      ctx.ctrl.panel.mappingType = 2;
+      ctx.ctrl.panel.rangeMaps = [{from: '10', to: '50', text: 'OK'},{from: '51', to: '100', text: 'NOT OK'}];
+    });
+
+    it('Should replace value with text OK', function() {
+      expect(ctx.data.valueFormated).to.be('OK');
+    });
+  });
+
+  singleStatScenario('When range to text mapping is specified for other ranges', function(ctx) {
+    ctx.setup(function() {
+      ctx.datapoints = [[65,75]];
+      ctx.ctrl.panel.mappingType = 2;
+      ctx.ctrl.panel.rangeMaps = [{from: '10', to: '50', text: 'OK'},{from: '51', to: '100', text: 'NOT OK'}];
+    });
+
+    it('Should replace value with text NOT OK', function() {
+      expect(ctx.data.valueFormated).to.be('NOT OK');
+    });
+  });
+
 });

binární
public/fonts/grafana-icons.eot


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 3 - 3
public/fonts/grafana-icons.svg


binární
public/fonts/grafana-icons.ttf


binární
public/fonts/grafana-icons.woff


+ 19 - 17
public/sass/base/_grafana_icons.scss

@@ -1,10 +1,10 @@
 @font-face {
     font-family: 'grafana-icons';
-    src:    url('../fonts/grafana-icons.eot?h6rv8b');
-    src:    url('../fonts/grafana-icons.eot?h6rv8b#iefix') format('embedded-opentype'),
-        url('../fonts/grafana-icons.ttf?h6rv8b') format('truetype'),
-        url('../fonts/grafana-icons.woff?h6rv8b') format('woff'),
-        url('../fonts/grafana-icons.svg?h6rv8b#grafana-icons') format('svg');
+    src:    url('../fonts/grafana-icons.eot?okx5td');
+    src:    url('../fonts/grafana-icons.eot?okx5td#iefix') format('embedded-opentype'),
+        url('../fonts/grafana-icons.ttf?okx5td') format('truetype'),
+        url('../fonts/grafana-icons.woff?okx5td') format('woff'),
+        url('../fonts/grafana-icons.svg?okx5td#grafana-icons') format('svg');
     font-weight: normal;
     font-style: normal;
 }
@@ -61,6 +61,9 @@
 .icon-gf-endpoint:before {
     content: "\e609";
 }
+.icon-gf-page:before {
+    content: "\e908";
+}
 .icon-gf-filter:before {
     content: "\e60a";
 }
@@ -112,9 +115,6 @@
 .icon-gf-save:before {
     content: "\e614";
 }
-.icon-gf-settings:before {
-    content: "\e615";
-}
 .icon-gf-share:before {
     content: "\e616";
 }
@@ -124,10 +124,13 @@
 .icon-gf-search:before {
     content: "\e618";
 }
-.icon-gf-tag-add:before {
+.icon-gf-settings:before {
+    content: "\e615";
+}
+.icon-gf-add:before {
     content: "\e619";
 }
-.icon-gf-tag-remove:before {
+.icon-gf-remove:before {
     content: "\e61a";
 }
 .icon-gf-video:before {
@@ -169,6 +172,12 @@
 .icon-gf-scale:before {
     content: "\e906";
 }
+.icon-gf-pending:before {
+    content: "\e909";
+}
+.icon-gf-verified:before {
+    content: "\e90a";
+}
 .icon-gf-worldping:before {
     content: "\e627";
 }
@@ -176,10 +185,3 @@
     content: "\e903";
 }
 
-.icon-gf-app:before {
-  content: "\e902";
-}
-.icon-gf-datasource:before {
-  content: "\e607";
-}
-

+ 1 - 0
public/test/specs/dynamicDashboardSrv-specs.js

@@ -167,6 +167,7 @@ define([
 
     it('should generate a repeartRowId based on repeat row index', function() {
       expect(ctx.rows[1].repeatRowId).to.be(1);
+      expect(ctx.rows[1].repeatIteration).to.be(ctx.dynamicDashboardSrv.iteration);
     });
 
     it('should set scopedVars on row panels', function() {

+ 4 - 0
public/test/specs/helpers.js

@@ -138,6 +138,10 @@ define([
     this.replace = function(target) {
       return target;
     };
+
+    this.setTime = function(time) {
+      this.time = time;
+    };
   }
 
   function ContextSrvStub() {

+ 5 - 0
public/test/specs/templateSrv-specs.js

@@ -190,6 +190,11 @@ define([
         expect(contains).to.be(true);
       });
 
+      it('should not find it if only part matches with $var syntax', function() {
+        var contains = _templateSrv.containsVariable('this.$ServerDomain.filters', 'Server');
+        expect(contains).to.be(false);
+      });
+
       it('should find it with [[var]] syntax', function() {
         var contains = _templateSrv.containsVariable('this.[[test]].filters', 'test');
         expect(contains).to.be(true);

+ 1 - 0
public/test/specs/unsavedChangesSrv-specs.js

@@ -29,6 +29,7 @@ define([
 
     beforeEach(function() {
       dash = _dashboardSrv.create({
+        refresh: false,
         rows: [
           {
             panels: [{ test: "asd", legend: { } }]

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů