From 76bd173a365068ecad00c1e5777e2d7eff83bf32 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Mon, 13 Aug 2018 14:28:41 +0200 Subject: [PATCH 01/36] created a section under administration for authentication, moved ldap guide here, created pages for auth-proxy, oauth, anonymous auth, ldap sync with grafana ee, and overview, moved authentication guides from configuration to, added linksin configuration page to guides --- .../authentication/anonymous-auth.md | 30 ++ .../authentication/auth-proxy.md | 282 ++++++++++++ .../administration/authentication/index.md | 10 + .../authentication/ldap-sync-grafana-ee.md | 13 + .../authentication}/ldap.md | 20 +- .../administration/authentication/oauth.md | 399 ++++++++++++++++ .../administration/authentication/overview.md | 28 ++ docs/sources/http_api/auth.md | 2 +- docs/sources/installation/configuration.md | 426 +----------------- 9 files changed, 790 insertions(+), 420 deletions(-) create mode 100644 docs/sources/administration/authentication/anonymous-auth.md create mode 100644 docs/sources/administration/authentication/auth-proxy.md create mode 100644 docs/sources/administration/authentication/index.md create mode 100644 docs/sources/administration/authentication/ldap-sync-grafana-ee.md rename docs/sources/{installation => administration/authentication}/ldap.md (90%) create mode 100644 docs/sources/administration/authentication/oauth.md create mode 100644 docs/sources/administration/authentication/overview.md diff --git a/docs/sources/administration/authentication/anonymous-auth.md b/docs/sources/administration/authentication/anonymous-auth.md new file mode 100644 index 00000000000..f2cde75cacb --- /dev/null +++ b/docs/sources/administration/authentication/anonymous-auth.md @@ -0,0 +1,30 @@ ++++ +title = "Anonymous Authentication" +description = "Anonymous authentication " +keywords = ["grafana", "configuration", "documentation", "anonymous"] +type = "docs" +[menu.docs] +name = "Anonymous Auth" +identifier = "anonymous-auth" +parent = "authentication" +weight = 4 ++++ + +# Anonymous Authentication + +## [auth.anonymous] + +### enabled + +Set to `true` to enable anonymous access. Defaults to `false` + +### org_name + +Set the organization name that should be used for anonymous users. If +you change your organization name in the Grafana UI this setting needs +to be updated to match the new name. + +### org_role + +Specify role for anonymous users. Defaults to `Viewer`, other valid +options are `Editor` and `Admin`. diff --git a/docs/sources/administration/authentication/auth-proxy.md b/docs/sources/administration/authentication/auth-proxy.md new file mode 100644 index 00000000000..8ff61a8c40b --- /dev/null +++ b/docs/sources/administration/authentication/auth-proxy.md @@ -0,0 +1,282 @@ ++++ +title = "Auth Proxy" +description = "Grafana Auth Proxy Guide " +keywords = ["grafana", "configuration", "documentation", "proxy"] +type = "docs" +[menu.docs] +name = "Auth Proxy" +identifier = "auth-proxy" +parent = "authentication" +weight = 2 ++++ + +# Auth Proxy Authentication + +## [auth.proxy] + +This feature allows you to handle authentication in a http reverse proxy. + +### enabled + +Defaults to `false` + +### header_name + +Defaults to X-WEBAUTH-USER + +#### header_property + +Defaults to username but can also be set to email + +### auto_sign_up + +Set to `true` to enable auto sign up of users who do not exist in Grafana DB. Defaults to `true`. + +### whitelist + +Limit where auth proxy requests come from by configuring a list of IP addresses. This can be used to prevent users spoofing the X-WEBAUTH-USER header. + +### headers + +Used to define additional headers for `Name`, `Email` and/or `Login`, for example if the user's name is sent in the X-WEBAUTH-NAME header and their email address in the X-WEBAUTH-EMAIL header, set `headers = Name:X-WEBAUTH-NAME Email:X-WEBAUTH-EMAIL`. + +
+ +# Grafana Authproxy + +AuthProxy allows you to offload the authentication of users to a web server (there are many reasons why you’d want to run a web server in front of a production version of Grafana, especially if it’s exposed to the Internet). + +Popular web servers have a very extensive list of pluggable authentication modules, and any of them can be used with the AuthProxy feature. + +The Grafana AuthProxy feature is very simple in design, but it is this simplicity that makes it so powerful. + +## Interacting with Grafana’s AuthProxy via curl + +The AuthProxy feature can be configured through the Grafana configuration file with the following options: + +```js +[auth.proxy] +enabled = true +header_name = X-WEBAUTH-USER +header_property = username +auto_sign_up = true +ldap_sync_ttl = 60 +whitelist = +``` + +* **enabled**: this is to toggle the feature on or off +* **header_name**: this is the HTTP header name that passes the username or email address of the authenticated user to Grafana. Grafana will trust what ever username is contained in this header and automatically log the user in. +* **header_property**: this tells Grafana whether the value in the header_name is a username or an email address. (In Grafana you can log in using your account username or account email) +* **auto_sign_up**: If set to true, Grafana will automatically create user accounts in the Grafana DB if one does not exist. If set to false, users who do not exist in the GrafanaDB won’t be able to log in, even though their username and password are valid. +* **ldap_sync_ttl**: When both auth.proxy and auth.ldap are enabled, user's organisation and role are synchronised from ldap after the http proxy authentication. You can force ldap re-synchronisation after `ldap_sync_ttl` minutes. +* **whitelist**: Comma separated list of trusted authentication proxies IP. + +With a fresh install of Grafana, using the above configuration for the authProxy feature, we can send a simple API call to list all users. The only user that will be present is the default “Admin” user that is added the first time Grafana starts up. As you can see all we need to do to authenticate the request is to provide the “X-WEBAUTH-USER” header. + +```bash +curl -H "X-WEBAUTH-USER: admin" http://localhost:3000/api/users +[ + { + "id":1, + "name":"", + "login":"admin", + "email":"admin@localhost", + "isAdmin":true + } +] +``` + +We can then send a second request to the `/api/user` method which will return the details of the logged in user. We will use this request to show how Grafana automatically adds the new user we specify to the system. Here we create a new user called “anthony”. + +```bash +curl -H "X-WEBAUTH-USER: anthony" http://localhost:3000/api/user +{ + "email":"anthony", + "name":"", + "login":"anthony", + "theme":"", + "orgId":1, + "isGrafanaAdmin":false +} +``` + +## Making Apache’s auth work together with Grafana’s AuthProxy + +I’ll demonstrate how to use Apache for authenticating users. In this example we use BasicAuth with Apache’s text file based authentication handler, i.e. htpasswd files. However, any available Apache authentication capabilities could be used. + +### Apache BasicAuth + +In this example we use Apache as a reverseProxy in front of Grafana. Apache handles the Authentication of users before forwarding requests to the Grafana backend service. + +#### Apache configuration + +```bash + + ServerAdmin webmaster@authproxy + ServerName authproxy + ErrorLog "logs/authproxy-error_log" + CustomLog "logs/authproxy-access_log" common + + + AuthType Basic + AuthName GrafanaAuthProxy + AuthBasicProvider file + AuthUserFile /etc/apache2/grafana_htpasswd + Require valid-user + + RewriteEngine On + RewriteRule .* - [E=PROXY_USER:%{LA-U:REMOTE_USER},NS] + RequestHeader set X-WEBAUTH-USER "%{PROXY_USER}e" + + + RequestHeader unset Authorization + + ProxyRequests Off + ProxyPass / http://localhost:3000/ + ProxyPassReverse / http://localhost:3000/ + +``` + +* The first 4 lines of the virtualhost configuration are standard, so we won’t go into detail on what they do. + +* We use a **\** configuration block for applying our authentication rules to every proxied request. These rules include requiring basic authentication where user:password credentials are stored in the **/etc/apache2/grafana_htpasswd** file. This file can be created with the `htpasswd` command. + + * The next part of the configuration is the tricky part. We use Apache’s rewrite engine to create our **X-WEBAUTH-USER header**, populated with the authenticated user. + + * **RewriteRule .* - [E=PROXY_USER:%{LA-U:REMOTE_USER}, NS]**: This line is a little bit of magic. What it does, is for every request use the rewriteEngines look-ahead (LA-U) feature to determine what the REMOTE_USER variable would be set to after processing the request. Then assign the result to the variable PROXY_USER. This is necessary as the REMOTE_USER variable is not available to the RequestHeader function. + + * **RequestHeader set X-WEBAUTH-USER “%{PROXY_USER}e”**: With the authenticated username now stored in the PROXY_USER variable, we create a new HTTP request header that will be sent to our backend Grafana containing the username. + +* The **RequestHeader unset Authorization** removes the Authorization header from the HTTP request before it is forwarded to Grafana. This ensures that Grafana does not try to authenticate the user using these credentials (BasicAuth is a supported authentication handler in Grafana). + +* The last 3 lines are then just standard reverse proxy configuration to direct all authenticated requests to our Grafana server running on port 3000. + +#### Grafana configuration + +```bash +############# Users ################ +[users] + # disable user signup / registration +allow_sign_up = false + +# Set to true to automatically assign new users to the default organization (id 1) +auto_assign_org = true + +# Default role new users will be automatically assigned (if auto_assign_org above is set to true) + auto_assign_org_role = Editor + + +############ Auth Proxy ######## +[auth.proxy] +enabled = true + +# the Header name that contains the authenticated user. +header_name = X-WEBAUTH-USER + +# does the user authenticate against the proxy using a 'username' or an 'email' +header_property = username + +# automatically add the user to the system if they don't already exist. +auto_sign_up = true +``` + +#### Full walk through using Docker. + +##### Grafana Container + +For this example, we use the official Grafana docker image available at [Docker Hub](https://hub.docker.com/r/grafana/grafana/) + +* Create a file `grafana.ini` with the following contents + +```bash +[users] +allow_sign_up = false +auto_assign_org = true +auto_assign_org_role = Editor + +[auth.proxy] +enabled = true +header_name = X-WEBAUTH-USER +header_property = username +auto_sign_up = true +``` + +* Launch the Grafana container, using our custom grafana.ini to replace `/etc/grafana/grafana.ini`. We don't expose any ports for this container as it will only be connected to by our Apache container. + +```bash +docker run -i -v $(pwd)/grafana.ini:/etc/grafana/grafana.ini --name grafana grafana/grafana +``` + +### Apache Container + +For this example we use the official Apache docker image available at [Docker Hub](https://hub.docker.com/_/httpd/) + +* Create a file `httpd.conf` with the following contents + +```bash +ServerRoot "/usr/local/apache2" +Listen 80 +LoadModule authn_file_module modules/mod_authn_file.so +LoadModule authn_core_module modules/mod_authn_core.so +LoadModule authz_host_module modules/mod_authz_host.so +LoadModule authz_user_module modules/mod_authz_user.so +LoadModule authz_core_module modules/mod_authz_core.so +LoadModule auth_basic_module modules/mod_auth_basic.so +LoadModule log_config_module modules/mod_log_config.so +LoadModule env_module modules/mod_env.so +LoadModule headers_module modules/mod_headers.so +LoadModule unixd_module modules/mod_unixd.so +LoadModule rewrite_module modules/mod_rewrite.so +LoadModule proxy_module modules/mod_proxy.so +LoadModule proxy_http_module modules/mod_proxy_http.so + +User daemon +Group daemon + +ServerAdmin you@example.com + + AllowOverride none + Require all denied + +DocumentRoot "/usr/local/apache2/htdocs" +ErrorLog /proc/self/fd/2 +LogLevel error + + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined + LogFormat "%h %l %u %t \"%r\" %>s %b" common + + LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio + + CustomLog /proc/self/fd/1 common + + + AuthType Basic + AuthName GrafanaAuthProxy + AuthBasicProvider file + AuthUserFile /tmp/htpasswd + Require valid-user + RewriteEngine On + RewriteRule .* - [E=PROXY_USER:%{LA-U:REMOTE_USER},NS] + RequestHeader set X-WEBAUTH-USER "%{PROXY_USER}e" + +RequestHeader unset Authorization +ProxyRequests Off +ProxyPass / http://grafana:3000/ +ProxyPassReverse / http://grafana:3000/ +``` + +* Create a htpasswd file. We create a new user **anthony** with the password **password** + + ```bash + htpasswd -bc htpasswd anthony password + ``` + +* Launch the httpd container using our custom httpd.conf and our htpasswd file. The container will listen on port 80, and we create a link to the **grafana** container so that this container can resolve the hostname **grafana** to the grafana container’s ip address. + + ```bash + docker run -i -p 80:80 --link grafana:grafana -v $(pwd)/httpd.conf:/usr/local/apache2/conf/httpd.conf -v $(pwd)/htpasswd:/tmp/htpasswd httpd:2.4 + ``` + +### Use grafana. + +With our Grafana and Apache containers running, you can now connect to http://localhost/ and log in using the username/password we created in the htpasswd file. diff --git a/docs/sources/administration/authentication/index.md b/docs/sources/administration/authentication/index.md new file mode 100644 index 00000000000..f9bc9e5f13c --- /dev/null +++ b/docs/sources/administration/authentication/index.md @@ -0,0 +1,10 @@ ++++ +title = "Authentication" +description = "Authentication" +type = "docs" +[menu.docs] +name = "Authentication" +identifier = "authentication" +parent = "admin" +weight = 1 ++++ \ No newline at end of file diff --git a/docs/sources/administration/authentication/ldap-sync-grafana-ee.md b/docs/sources/administration/authentication/ldap-sync-grafana-ee.md new file mode 100644 index 00000000000..c60b21b0320 --- /dev/null +++ b/docs/sources/administration/authentication/ldap-sync-grafana-ee.md @@ -0,0 +1,13 @@ ++++ +title = "LDAP Sync with Grafana EE" +description = "LDAP Sync with Grafana EE Guide " +keywords = ["grafana", "configuration", "documentation", "ldap", "enterprise"] +type = "docs" +[menu.docs] +name = "LDAP Sync with Grafana EE" +identifier = "ldap-sync" +parent = "authentication" +weight = 2 ++++ + +# LDAP Sync with Grafana EE \ No newline at end of file diff --git a/docs/sources/installation/ldap.md b/docs/sources/administration/authentication/ldap.md similarity index 90% rename from docs/sources/installation/ldap.md rename to docs/sources/administration/authentication/ldap.md index 88cf40632db..f9208213aef 100644 --- a/docs/sources/installation/ldap.md +++ b/docs/sources/administration/authentication/ldap.md @@ -4,12 +4,28 @@ description = "Grafana LDAP Authentication Guide " keywords = ["grafana", "configuration", "documentation", "ldap"] type = "docs" [menu.docs] -name = "LDAP Authentication" +name = "LDAP Auth" identifier = "ldap" -parent = "admin" +parent = "authentication" weight = 2 +++ +## [auth.ldap] +### enabled +Set to `true` to enable LDAP integration (default: `false`) + +### config_file +Path to the LDAP specific configuration file (default: `/etc/grafana/ldap.toml`) + +### allow_sign_up + +Allow sign up should almost always be true (default) to allow new Grafana users to be created (if ldap authentication is ok). If set to +false only pre-existing Grafana users will be able to login (if ldap authentication is ok). + +> For details on LDAP Configuration, go to the [LDAP Integration]({{< relref "ldap.md" >}}) page. + +
+ # LDAP Authentication Grafana (2.1 and newer) ships with a strong LDAP integration feature. The LDAP integration in Grafana allows your diff --git a/docs/sources/administration/authentication/oauth.md b/docs/sources/administration/authentication/oauth.md new file mode 100644 index 00000000000..0fe60196ffa --- /dev/null +++ b/docs/sources/administration/authentication/oauth.md @@ -0,0 +1,399 @@ ++++ +title = "OAuth authentication" +description = "Grafana OAuthentication Guide " +keywords = ["grafana", "configuration", "documentation", "oauth"] +type = "docs" +[menu.docs] +name = "OAuth" +identifier = "oauth" +parent = "authentication" +weight = 2 ++++ + +# OAuth Authentication + +## [auth.generic_oauth] + +This option could be used if have your own oauth service. + +This callback URL must match the full HTTP address that you use in your +browser to access Grafana, but with the prefix path of `/login/generic_oauth`. + +```bash +[auth.generic_oauth] +enabled = true +client_id = YOUR_APP_CLIENT_ID +client_secret = YOUR_APP_CLIENT_SECRET +scopes = +auth_url = +token_url = +api_url = +allowed_domains = mycompany.com mycompany.org +allow_sign_up = true +``` + +Set api_url to the resource that returns [OpenID UserInfo](https://connect2id.com/products/server/docs/api/userinfo) compatible information. + +### Set up oauth2 with Okta + +First set up Grafana as an OpenId client "webapplication" in Okta. Then set the Base URIs to `https:///` and set the Login redirect URIs to `https:///login/generic_oauth`. + +Finally set up the generic oauth module like this: +```bash +[auth.generic_oauth] +name = Okta +enabled = true +scopes = openid profile email +client_id = +client_secret = +auth_url = https:///oauth2/v1/authorize +token_url = https:///oauth2/v1/token +api_url = https:///oauth2/v1/userinfo +``` + +### Set up oauth2 with Bitbucket + +```bash +[auth.generic_oauth] +name = BitBucket +enabled = true +allow_sign_up = true +client_id = +client_secret = +scopes = account email +auth_url = https://bitbucket.org/site/oauth2/authorize +token_url = https://bitbucket.org/site/oauth2/access_token +api_url = https://api.bitbucket.org/2.0/user +team_ids = +allowed_organizations = +``` + +### Set up oauth2 with OneLogin + +1. Create a new Custom Connector with the following settings: + - Name: Grafana + - Sign On Method: OpenID Connect + - Redirect URI: `https:///login/generic_oauth` + - Signing Algorithm: RS256 + - Login URL: `https:///login/generic_oauth` + + then: +2. Add an App to the Grafana Connector: + - Display Name: Grafana + + then: +3. Under the SSO tab on the Grafana App details page you'll find the Client ID and Client Secret. + + Your OneLogin Domain will match the url you use to access OneLogin. + + Configure Grafana as follows: + + ```bash + [auth.generic_oauth] + name = OneLogin + enabled = true + allow_sign_up = true + client_id = + client_secret = + scopes = openid email name + auth_url = https://.onelogin.com/oidc/auth + token_url = https://.onelogin.com/oidc/token + api_url = https://.onelogin.com/oidc/me + team_ids = + allowed_organizations = + ``` + +### Set up oauth2 with Auth0 + +1. Create a new Client in Auth0 + - Name: Grafana + - Type: Regular Web Application + +2. Go to the Settings tab and set: + - Allowed Callback URLs: `https:///login/generic_oauth` + +3. Click Save Changes, then use the values at the top of the page to configure Grafana: + + ```bash + [auth.generic_oauth] + enabled = true + allow_sign_up = true + team_ids = + allowed_organizations = + name = Auth0 + client_id = + client_secret = + scopes = openid profile email + auth_url = https:///authorize + token_url = https:///oauth/token + api_url = https:///userinfo + ``` + +### Set up oauth2 with Azure Active Directory + +1. Log in to portal.azure.com and click "Azure Active Directory" in the side menu, then click the "Properties" sub-menu item. + +2. Copy the "Directory ID", this is needed for setting URLs later + +3. Click "App Registrations" and add a new application registration: + - Name: Grafana + - Application type: Web app / API + - Sign-on URL: `https:///login/generic_oauth` + +4. Click the name of the new application to open the application details page. + +5. Note down the "Application ID", this will be the OAuth client id. + +6. Click "Settings", then click "Keys" and add a new entry under Passwords + - Key Description: Grafana OAuth + - Duration: Never Expires + +7. Click Save then copy the key value, this will be the OAuth client secret. + +8. Configure Grafana as follows: + + ```bash + [auth.generic_oauth] + name = Azure AD + enabled = true + allow_sign_up = true + client_id = + client_secret = + scopes = openid email name + auth_url = https://login.microsoftonline.com//oauth2/authorize + token_url = https://login.microsoftonline.com//oauth2/token + api_url = + team_ids = + allowed_organizations = + ``` + +
+ +## [auth.github] + +You need to create a GitHub OAuth application (you find this under the GitHub +settings page). When you create the application you will need to specify +a callback URL. Specify this as callback: + +```bash +http://:/login/github +``` + +This callback URL must match the full HTTP address that you use in your +browser to access Grafana, but with the prefix path of `/login/github`. +When the GitHub OAuth application is created you will get a Client ID and a +Client Secret. Specify these in the Grafana configuration file. For +example: + +```bash +[auth.github] +enabled = true +allow_sign_up = true +client_id = YOUR_GITHUB_APP_CLIENT_ID +client_secret = YOUR_GITHUB_APP_CLIENT_SECRET +scopes = user:email,read:org +auth_url = https://github.com/login/oauth/authorize +token_url = https://github.com/login/oauth/access_token +api_url = https://api.github.com/user +team_ids = +allowed_organizations = +``` + +Restart the Grafana back-end. You should now see a GitHub login button +on the login page. You can now login or sign up with your GitHub +accounts. + +You may allow users to sign-up via GitHub authentication by setting the +`allow_sign_up` option to `true`. When this option is set to `true`, any +user successfully authenticating via GitHub authentication will be +automatically signed up. + +### team_ids + +Require an active team membership for at least one of the given teams on +GitHub. If the authenticated user isn't a member of at least one of the +teams they will not be able to register or authenticate with your +Grafana instance. For example: + +```bash +[auth.github] +enabled = true +client_id = YOUR_GITHUB_APP_CLIENT_ID +client_secret = YOUR_GITHUB_APP_CLIENT_SECRET +scopes = user:email,read:org +team_ids = 150,300 +auth_url = https://github.com/login/oauth/authorize +token_url = https://github.com/login/oauth/access_token +api_url = https://api.github.com/user +allow_sign_up = true +``` + +### allowed_organizations + +Require an active organization membership for at least one of the given +organizations on GitHub. If the authenticated user isn't a member of at least +one of the organizations they will not be able to register or authenticate with +your Grafana instance. For example + +```bash +[auth.github] +enabled = true +client_id = YOUR_GITHUB_APP_CLIENT_ID +client_secret = YOUR_GITHUB_APP_CLIENT_SECRET +scopes = user:email,read:org +auth_url = https://github.com/login/oauth/authorize +token_url = https://github.com/login/oauth/access_token +api_url = https://api.github.com/user +allow_sign_up = true +# space-delimited organization names +allowed_organizations = github google +``` + +
+ +## [auth.gitlab] + +> Only available in Grafana v5.3+. + +You need to [create a GitLab OAuth +application](https://docs.gitlab.com/ce/integration/oauth_provider.html). +Choose a descriptive *Name*, and use the following *Redirect URI*: + +``` +https://grafana.example.com/login/gitlab +``` + +where `https://grafana.example.com` is the URL you use to connect to Grafana. +Adjust it as needed if you don't use HTTPS or if you use a different port; for +instance, if you access Grafana at `http://203.0.113.31:3000`, you should use + +``` +http://203.0.113.31:3000/login/gitlab +``` + +Finally, select *api* as the *Scope* and submit the form. Note that if you're +not going to use GitLab groups for authorization (i.e. not setting +`allowed_groups`, see below), you can select *read_user* instead of *api* as +the *Scope*, thus giving a more restricted access to your GitLab API. + +You'll get an *Application Id* and a *Secret* in return; we'll call them +`GITLAB_APPLICATION_ID` and `GITLAB_SECRET` respectively for the rest of this +section. + +Add the following to your Grafana configuration file to enable GitLab +authentication: + +```ini +[auth.gitlab] +enabled = false +allow_sign_up = false +client_id = GITLAB_APPLICATION_ID +client_secret = GITLAB_SECRET +scopes = api +auth_url = https://gitlab.com/oauth/authorize +token_url = https://gitlab.com/oauth/token +api_url = https://gitlab.com/api/v4 +allowed_groups = +``` + +Restart the Grafana backend for your changes to take effect. + +If you use your own instance of GitLab instead of `gitlab.com`, adjust +`auth_url`, `token_url` and `api_url` accordingly by replacing the `gitlab.com` +hostname with your own. + +With `allow_sign_up` set to `false`, only existing users will be able to login +using their GitLab account, but with `allow_sign_up` set to `true`, *any* user +who can authenticate on GitLab will be able to login on your Grafana instance; +if you use the public `gitlab.com`, it means anyone in the world would be able +to login on your Grafana instance. + +You can can however limit access to only members of a given group or list of +groups by setting the `allowed_groups` option. + +### allowed_groups + +To limit access to authenticated users that are members of one or more [GitLab +groups](https://docs.gitlab.com/ce/user/group/index.html), set `allowed_groups` +to a comma- or space-separated list of groups. For instance, if you want to +only give access to members of the `example` group, set + + +```ini +allowed_groups = example +``` + +If you want to also give access to members of the subgroup `bar`, which is in +the group `foo`, set + +```ini +allowed_groups = example, foo/bar +``` + +Note that in GitLab, the group or subgroup name doesn't always match its +display name, especially if the display name contains spaces or special +characters. Make sure you always use the group or subgroup name as it appears +in the URL of the group or subgroup. + +Here's a complete example with `alloed_sign_up` enabled, and access limited to +the `example` and `foo/bar` groups: + +```ini +[auth.gitlab] +enabled = false +allow_sign_up = true +client_id = GITLAB_APPLICATION_ID +client_secret = GITLAB_SECRET +scopes = api +auth_url = https://gitlab.com/oauth/authorize +token_url = https://gitlab.com/oauth/token +api_url = https://gitlab.com/api/v4 +allowed_groups = example, foo/bar +``` + +
+ +## [auth.google] + +First, you need to create a Google OAuth Client: + +1. Go to https://console.developers.google.com/apis/credentials + +2. Click the 'Create Credentials' button, then click 'OAuth Client ID' in the +menu that drops down + +3. Enter the following: + + - Application Type: Web Application + - Name: Grafana + - Authorized Javascript Origins: https://grafana.mycompany.com + - Authorized Redirect URLs: https://grafana.mycompany.com/login/google + + Replace https://grafana.mycompany.com with the URL of your Grafana instance. + +4. Click Create + +5. Copy the Client ID and Client Secret from the 'OAuth Client' modal + +Specify the Client ID and Secret in the Grafana configuration file. For example: + +```bash +[auth.google] +enabled = true +client_id = CLIENT_ID +client_secret = CLIENT_SECRET +scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email +auth_url = https://accounts.google.com/o/oauth2/auth +token_url = https://accounts.google.com/o/oauth2/token +allowed_domains = mycompany.com mycompany.org +allow_sign_up = true +``` + +Restart the Grafana back-end. You should now see a Google login button +on the login page. You can now login or sign up with your Google +accounts. The `allowed_domains` option is optional, and domains were separated by space. + +You may allow users to sign-up via Google authentication by setting the +`allow_sign_up` option to `true`. When this option is set to `true`, any +user successfully authenticating via Google authentication will be +automatically signed up. \ No newline at end of file diff --git a/docs/sources/administration/authentication/overview.md b/docs/sources/administration/authentication/overview.md new file mode 100644 index 00000000000..e7daf581abb --- /dev/null +++ b/docs/sources/administration/authentication/overview.md @@ -0,0 +1,28 @@ ++++ +title = "Overview" +description = "Overview for auth" +type = "docs" +[menu.docs] +name = "Overview" +identifier = "overview-auth" +parent = "authentication" +weight = 1 ++++ + +## [auth] + +### disable_login_form + +Set to true to disable (hide) the login form, useful if you use OAuth, defaults to false. + +### disable_signout_menu + +Set to true to disable the signout link in the side menu. useful if you use auth.proxy, defaults to false. + +
+ +## [auth.basic] +### enabled +When enabled is `true` (default) the http api will accept basic authentication. + +
\ No newline at end of file diff --git a/docs/sources/http_api/auth.md b/docs/sources/http_api/auth.md index 8ff40b5ef04..e87d3571322 100644 --- a/docs/sources/http_api/auth.md +++ b/docs/sources/http_api/auth.md @@ -5,7 +5,7 @@ keywords = ["grafana", "http", "documentation", "api", "authentication"] aliases = ["/http_api/authentication/"] type = "docs" [menu.docs] -name = "Authentication" +name = "Authentication HTTP API" parent = "http_api" +++ diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index 4b14829b689..f61274e36fa 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -333,405 +333,31 @@ Set to true to disable the signout link in the side menu. useful if you use auth ## [auth.anonymous] -### enabled +[Read guide here.](/administration/authentication/anonymous-auth) -Set to `true` to enable anonymous access. Defaults to `false` - -### org_name - -Set the organization name that should be used for anonymous users. If -you change your organization name in the Grafana UI this setting needs -to be updated to match the new name. - -### org_role - -Specify role for anonymous users. Defaults to `Viewer`, other valid -options are `Editor` and `Admin`. +
## [auth.github] -You need to create a GitHub OAuth application (you find this under the GitHub -settings page). When you create the application you will need to specify -a callback URL. Specify this as callback: - -```bash -http://:/login/github -``` - -This callback URL must match the full HTTP address that you use in your -browser to access Grafana, but with the prefix path of `/login/github`. -When the GitHub OAuth application is created you will get a Client ID and a -Client Secret. Specify these in the Grafana configuration file. For -example: - -```bash -[auth.github] -enabled = true -allow_sign_up = true -client_id = YOUR_GITHUB_APP_CLIENT_ID -client_secret = YOUR_GITHUB_APP_CLIENT_SECRET -scopes = user:email,read:org -auth_url = https://github.com/login/oauth/authorize -token_url = https://github.com/login/oauth/access_token -api_url = https://api.github.com/user -team_ids = -allowed_organizations = -``` - -Restart the Grafana back-end. You should now see a GitHub login button -on the login page. You can now login or sign up with your GitHub -accounts. - -You may allow users to sign-up via GitHub authentication by setting the -`allow_sign_up` option to `true`. When this option is set to `true`, any -user successfully authenticating via GitHub authentication will be -automatically signed up. - -### team_ids - -Require an active team membership for at least one of the given teams on -GitHub. If the authenticated user isn't a member of at least one of the -teams they will not be able to register or authenticate with your -Grafana instance. For example: - -```bash -[auth.github] -enabled = true -client_id = YOUR_GITHUB_APP_CLIENT_ID -client_secret = YOUR_GITHUB_APP_CLIENT_SECRET -scopes = user:email,read:org -team_ids = 150,300 -auth_url = https://github.com/login/oauth/authorize -token_url = https://github.com/login/oauth/access_token -api_url = https://api.github.com/user -allow_sign_up = true -``` - -### allowed_organizations - -Require an active organization membership for at least one of the given -organizations on GitHub. If the authenticated user isn't a member of at least -one of the organizations they will not be able to register or authenticate with -your Grafana instance. For example - -```bash -[auth.github] -enabled = true -client_id = YOUR_GITHUB_APP_CLIENT_ID -client_secret = YOUR_GITHUB_APP_CLIENT_SECRET -scopes = user:email,read:org -auth_url = https://github.com/login/oauth/authorize -token_url = https://github.com/login/oauth/access_token -api_url = https://api.github.com/user -allow_sign_up = true -# space-delimited organization names -allowed_organizations = github google -``` +[Read guide here.](/administration/authentication/oauth/#auth-github)
## [auth.gitlab] -> Only available in Grafana v5.3+. - -You need to [create a GitLab OAuth -application](https://docs.gitlab.com/ce/integration/oauth_provider.html). -Choose a descriptive *Name*, and use the following *Redirect URI*: - -``` -https://grafana.example.com/login/gitlab -``` - -where `https://grafana.example.com` is the URL you use to connect to Grafana. -Adjust it as needed if you don't use HTTPS or if you use a different port; for -instance, if you access Grafana at `http://203.0.113.31:3000`, you should use - -``` -http://203.0.113.31:3000/login/gitlab -``` - -Finally, select *api* as the *Scope* and submit the form. Note that if you're -not going to use GitLab groups for authorization (i.e. not setting -`allowed_groups`, see below), you can select *read_user* instead of *api* as -the *Scope*, thus giving a more restricted access to your GitLab API. - -You'll get an *Application Id* and a *Secret* in return; we'll call them -`GITLAB_APPLICATION_ID` and `GITLAB_SECRET` respectively for the rest of this -section. - -Add the following to your Grafana configuration file to enable GitLab -authentication: - -```ini -[auth.gitlab] -enabled = false -allow_sign_up = false -client_id = GITLAB_APPLICATION_ID -client_secret = GITLAB_SECRET -scopes = api -auth_url = https://gitlab.com/oauth/authorize -token_url = https://gitlab.com/oauth/token -api_url = https://gitlab.com/api/v4 -allowed_groups = -``` - -Restart the Grafana backend for your changes to take effect. - -If you use your own instance of GitLab instead of `gitlab.com`, adjust -`auth_url`, `token_url` and `api_url` accordingly by replacing the `gitlab.com` -hostname with your own. - -With `allow_sign_up` set to `false`, only existing users will be able to login -using their GitLab account, but with `allow_sign_up` set to `true`, *any* user -who can authenticate on GitLab will be able to login on your Grafana instance; -if you use the public `gitlab.com`, it means anyone in the world would be able -to login on your Grafana instance. - -You can can however limit access to only members of a given group or list of -groups by setting the `allowed_groups` option. - -### allowed_groups - -To limit access to authenticated users that are members of one or more [GitLab -groups](https://docs.gitlab.com/ce/user/group/index.html), set `allowed_groups` -to a comma- or space-separated list of groups. For instance, if you want to -only give access to members of the `example` group, set - - -```ini -allowed_groups = example -``` - -If you want to also give access to members of the subgroup `bar`, which is in -the group `foo`, set - -```ini -allowed_groups = example, foo/bar -``` - -Note that in GitLab, the group or subgroup name doesn't always match its -display name, especially if the display name contains spaces or special -characters. Make sure you always use the group or subgroup name as it appears -in the URL of the group or subgroup. - -Here's a complete example with `alloed_sign_up` enabled, and access limited to -the `example` and `foo/bar` groups: - -```ini -[auth.gitlab] -enabled = false -allow_sign_up = true -client_id = GITLAB_APPLICATION_ID -client_secret = GITLAB_SECRET -scopes = api -auth_url = https://gitlab.com/oauth/authorize -token_url = https://gitlab.com/oauth/token -api_url = https://gitlab.com/api/v4 -allowed_groups = example, foo/bar -``` +[Read guide here.](/administration/authentication/oauth/#auth-gitlab)
## [auth.google] -First, you need to create a Google OAuth Client: +[Read guide here.](/administration/authentication/oauth/#auth-google) -1. Go to https://console.developers.google.com/apis/credentials - -2. Click the 'Create Credentials' button, then click 'OAuth Client ID' in the -menu that drops down - -3. Enter the following: - - - Application Type: Web Application - - Name: Grafana - - Authorized Javascript Origins: https://grafana.mycompany.com - - Authorized Redirect URLs: https://grafana.mycompany.com/login/google - - Replace https://grafana.mycompany.com with the URL of your Grafana instance. - -4. Click Create - -5. Copy the Client ID and Client Secret from the 'OAuth Client' modal - -Specify the Client ID and Secret in the Grafana configuration file. For example: - -```bash -[auth.google] -enabled = true -client_id = CLIENT_ID -client_secret = CLIENT_SECRET -scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email -auth_url = https://accounts.google.com/o/oauth2/auth -token_url = https://accounts.google.com/o/oauth2/token -allowed_domains = mycompany.com mycompany.org -allow_sign_up = true -``` - -Restart the Grafana back-end. You should now see a Google login button -on the login page. You can now login or sign up with your Google -accounts. The `allowed_domains` option is optional, and domains were separated by space. - -You may allow users to sign-up via Google authentication by setting the -`allow_sign_up` option to `true`. When this option is set to `true`, any -user successfully authenticating via Google authentication will be -automatically signed up. +
## [auth.generic_oauth] -This option could be used if have your own oauth service. - -This callback URL must match the full HTTP address that you use in your -browser to access Grafana, but with the prefix path of `/login/generic_oauth`. - -```bash -[auth.generic_oauth] -enabled = true -client_id = YOUR_APP_CLIENT_ID -client_secret = YOUR_APP_CLIENT_SECRET -scopes = -auth_url = -token_url = -api_url = -allowed_domains = mycompany.com mycompany.org -allow_sign_up = true -``` - -Set api_url to the resource that returns [OpenID UserInfo](https://connect2id.com/products/server/docs/api/userinfo) compatible information. - -### Set up oauth2 with Okta - -First set up Grafana as an OpenId client "webapplication" in Okta. Then set the Base URIs to `https:///` and set the Login redirect URIs to `https:///login/generic_oauth`. - -Finally set up the generic oauth module like this: -```bash -[auth.generic_oauth] -name = Okta -enabled = true -scopes = openid profile email -client_id = -client_secret = -auth_url = https:///oauth2/v1/authorize -token_url = https:///oauth2/v1/token -api_url = https:///oauth2/v1/userinfo -``` - -### Set up oauth2 with Bitbucket - -```bash -[auth.generic_oauth] -name = BitBucket -enabled = true -allow_sign_up = true -client_id = -client_secret = -scopes = account email -auth_url = https://bitbucket.org/site/oauth2/authorize -token_url = https://bitbucket.org/site/oauth2/access_token -api_url = https://api.bitbucket.org/2.0/user -team_ids = -allowed_organizations = -``` - -### Set up oauth2 with OneLogin - -1. Create a new Custom Connector with the following settings: - - Name: Grafana - - Sign On Method: OpenID Connect - - Redirect URI: `https:///login/generic_oauth` - - Signing Algorithm: RS256 - - Login URL: `https:///login/generic_oauth` - - then: -2. Add an App to the Grafana Connector: - - Display Name: Grafana - - then: -3. Under the SSO tab on the Grafana App details page you'll find the Client ID and Client Secret. - - Your OneLogin Domain will match the url you use to access OneLogin. - - Configure Grafana as follows: - - ```bash - [auth.generic_oauth] - name = OneLogin - enabled = true - allow_sign_up = true - client_id = - client_secret = - scopes = openid email name - auth_url = https://.onelogin.com/oidc/auth - token_url = https://.onelogin.com/oidc/token - api_url = https://.onelogin.com/oidc/me - team_ids = - allowed_organizations = - ``` - -### Set up oauth2 with Auth0 - -1. Create a new Client in Auth0 - - Name: Grafana - - Type: Regular Web Application - -2. Go to the Settings tab and set: - - Allowed Callback URLs: `https:///login/generic_oauth` - -3. Click Save Changes, then use the values at the top of the page to configure Grafana: - - ```bash - [auth.generic_oauth] - enabled = true - allow_sign_up = true - team_ids = - allowed_organizations = - name = Auth0 - client_id = - client_secret = - scopes = openid profile email - auth_url = https:///authorize - token_url = https:///oauth/token - api_url = https:///userinfo - ``` - -### Set up oauth2 with Azure Active Directory - -1. Log in to portal.azure.com and click "Azure Active Directory" in the side menu, then click the "Properties" sub-menu item. - -2. Copy the "Directory ID", this is needed for setting URLs later - -3. Click "App Registrations" and add a new application registration: - - Name: Grafana - - Application type: Web app / API - - Sign-on URL: `https:///login/generic_oauth` - -4. Click the name of the new application to open the application details page. - -5. Note down the "Application ID", this will be the OAuth client id. - -6. Click "Settings", then click "Keys" and add a new entry under Passwords - - Key Description: Grafana OAuth - - Duration: Never Expires - -7. Click Save then copy the key value, this will be the OAuth client secret. - -8. Configure Grafana as follows: - - ```bash - [auth.generic_oauth] - name = Azure AD - enabled = true - allow_sign_up = true - client_id = - client_secret = - scopes = openid email name - auth_url = https://login.microsoftonline.com//oauth2/authorize - token_url = https://login.microsoftonline.com//oauth2/token - api_url = - team_ids = - allowed_organizations = - ``` - +[Read guide here.](/administration/authentication/oauth/#auth-generic-oauth)
## [auth.basic] @@ -741,48 +367,14 @@ When enabled is `true` (default) the http api will accept basic authentication.
## [auth.ldap] -### enabled -Set to `true` to enable LDAP integration (default: `false`) -### config_file -Path to the LDAP specific configuration file (default: `/etc/grafana/ldap.toml`) - -### allow_sign_up - -Allow sign up should almost always be true (default) to allow new Grafana users to be created (if ldap authentication is ok). If set to -false only pre-existing Grafana users will be able to login (if ldap authentication is ok). - -> For details on LDAP Configuration, go to the [LDAP Integration]({{< relref "ldap.md" >}}) page. +[Read guide here.](/administration/authentication/ldap/)
## [auth.proxy] -This feature allows you to handle authentication in a http reverse proxy. - -### enabled - -Defaults to `false` - -### header_name - -Defaults to X-WEBAUTH-USER - -#### header_property - -Defaults to username but can also be set to email - -### auto_sign_up - -Set to `true` to enable auto sign up of users who do not exist in Grafana DB. Defaults to `true`. - -### whitelist - -Limit where auth proxy requests come from by configuring a list of IP addresses. This can be used to prevent users spoofing the X-WEBAUTH-USER header. - -### headers - -Used to define additional headers for `Name`, `Email` and/or `Login`, for example if the user's name is sent in the X-WEBAUTH-NAME header and their email address in the X-WEBAUTH-EMAIL header, set `headers = Name:X-WEBAUTH-NAME Email:X-WEBAUTH-EMAIL`. +[Read guide here.](/administration/authentication/auth-proxy/)
From fda9790ba5b1a143eea59187d7c651ec00b7de53 Mon Sep 17 00:00:00 2001 From: bergquist Date: Sat, 25 Aug 2018 21:23:20 +0200 Subject: [PATCH 02/36] upgrades to golang 1.11 --- .circleci/config.yml | 8 ++++---- Dockerfile | 2 +- README.md | 2 +- appveyor.yml | 2 +- docs/sources/project/building_from_source.md | 2 +- scripts/build/Dockerfile | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1e046aec34d..b4480b4bade 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,7 +19,7 @@ version: 2 jobs: mysql-integration-test: docker: - - image: circleci/golang:1.10 + - image: circleci/golang:1.11 - image: circleci/mysql:5.6-ram environment: MYSQL_ROOT_PASSWORD: rootpass @@ -39,7 +39,7 @@ jobs: postgres-integration-test: docker: - - image: circleci/golang:1.10 + - image: circleci/golang:1.11 - image: circleci/postgres:9.3-ram environment: POSTGRES_USER: grafanatest @@ -74,7 +74,7 @@ jobs: gometalinter: docker: - - image: circleci/golang:1.10 + - image: circleci/golang:1.11 environment: # we need CGO because of go-sqlite3 CGO_ENABLED: 1 @@ -115,7 +115,7 @@ jobs: test-backend: docker: - - image: circleci/golang:1.10 + - image: circleci/golang:1.11 working_directory: /go/src/github.com/grafana/grafana steps: - checkout diff --git a/Dockerfile b/Dockerfile index f7e45893c38..28dd71952af 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Golang build container -FROM golang:1.10 +FROM golang:1.11 WORKDIR $GOPATH/src/github.com/grafana/grafana diff --git a/README.md b/README.md index 74fb10c8066..133d9e50d07 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ the latest master builds [here](https://grafana.com/grafana/download) ### Dependencies -- Go 1.10 +- Go 1.11 - NodeJS LTS ### Building the backend diff --git a/appveyor.yml b/appveyor.yml index 5cdec1b8bf5..52f23162033 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ clone_folder: c:\gopath\src\github.com\grafana\grafana environment: nodejs_version: "6" GOPATH: C:\gopath - GOVERSION: 1.10 + GOVERSION: 1.11 install: - rmdir c:\go /s /q diff --git a/docs/sources/project/building_from_source.md b/docs/sources/project/building_from_source.md index 08673404572..e83c62ca800 100644 --- a/docs/sources/project/building_from_source.md +++ b/docs/sources/project/building_from_source.md @@ -13,7 +13,7 @@ dev environment. Grafana ships with its own required backend server; also comple ## Dependencies -- [Go 1.10](https://golang.org/dl/) +- [Go 1.11](https://golang.org/dl/) - [Git](https://git-scm.com/downloads) - [NodeJS LTS](https://nodejs.org/download/) - node-gyp is the Node.js native addon build tool and it requires extra dependencies: python 2.7, make and GCC. These are already installed for most Linux distros and MacOS. See the Building On Windows section or the [node-gyp installation instructions](https://github.com/nodejs/node-gyp#installation) for more details. diff --git a/scripts/build/Dockerfile b/scripts/build/Dockerfile index 808e7f141e9..c7f4fecc649 100644 --- a/scripts/build/Dockerfile +++ b/scripts/build/Dockerfile @@ -21,7 +21,7 @@ RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A170311380 RUN curl --silent --location https://rpm.nodesource.com/setup_6.x | bash - && \ yum install -y nodejs --nogpgcheck -ENV GOLANG_VERSION 1.10 +ENV GOLANG_VERSION 1.11 RUN wget https://dl.yarnpkg.com/rpm/yarn.repo -O /etc/yum.repos.d/yarn.repo && \ yum install -y yarn --nogpgcheck && \ From ff7b0d4f6347366bcc6827d49359fba568e81f63 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 28 Aug 2018 22:14:15 +0200 Subject: [PATCH 03/36] go fmt fixes --- pkg/models/datasource.go | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/pkg/models/datasource.go b/pkg/models/datasource.go index b7e3e3eaa17..cbdd0136f4d 100644 --- a/pkg/models/datasource.go +++ b/pkg/models/datasource.go @@ -59,22 +59,22 @@ type DataSource struct { } var knownDatasourcePlugins = map[string]bool{ - DS_ES: true, - DS_GRAPHITE: true, - DS_INFLUXDB: true, - DS_INFLUXDB_08: true, - DS_KAIROSDB: true, - DS_CLOUDWATCH: true, - DS_PROMETHEUS: true, - DS_OPENTSDB: true, - DS_POSTGRES: true, - DS_MYSQL: true, - DS_MSSQL: true, - "opennms": true, - "abhisant-druid-datasource": true, - "dalmatinerdb-datasource": true, - "gnocci": true, - "zabbix": true, + DS_ES: true, + DS_GRAPHITE: true, + DS_INFLUXDB: true, + DS_INFLUXDB_08: true, + DS_KAIROSDB: true, + DS_CLOUDWATCH: true, + DS_PROMETHEUS: true, + DS_OPENTSDB: true, + DS_POSTGRES: true, + DS_MYSQL: true, + DS_MSSQL: true, + "opennms": true, + "abhisant-druid-datasource": true, + "dalmatinerdb-datasource": true, + "gnocci": true, + "zabbix": true, "alexanderzobnin-zabbix-datasource": true, "newrelic-app": true, "grafana-datadog-datasource": true, From 12c98608826250ed481197fa1eeeb2aae2457c3d Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 28 Aug 2018 22:26:47 +0200 Subject: [PATCH 04/36] string formating fixes --- pkg/api/live/conn.go | 2 +- pkg/cmd/grafana-cli/services/services.go | 4 ++-- pkg/components/imguploader/s3uploader.go | 2 +- pkg/log/log.go | 2 +- pkg/login/ext_user.go | 4 ++-- pkg/middleware/auth_proxy.go | 6 +++--- pkg/services/alerting/notifiers/telegram.go | 2 +- pkg/services/sqlstore/sqlstore.go | 2 +- pkg/services/sqlstore/transactions.go | 2 +- pkg/setting/setting.go | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/pkg/api/live/conn.go b/pkg/api/live/conn.go index f2a041d7631..0fae7f75b73 100644 --- a/pkg/api/live/conn.go +++ b/pkg/api/live/conn.go @@ -70,7 +70,7 @@ func (c *connection) readPump() { func (c *connection) handleMessage(message []byte) { json, err := simplejson.NewJson(message) if err != nil { - log.Error(3, "Unreadable message on websocket channel:", err) + log.Error(3, "Unreadable message on websocket channel. error: %v", err) } msgType := json.Get("action").MustString() diff --git a/pkg/cmd/grafana-cli/services/services.go b/pkg/cmd/grafana-cli/services/services.go index e743d42022c..b4e50ac84df 100644 --- a/pkg/cmd/grafana-cli/services/services.go +++ b/pkg/cmd/grafana-cli/services/services.go @@ -63,7 +63,7 @@ func ListAllPlugins(repoUrl string) (m.PluginRepo, error) { var data m.PluginRepo err = json.Unmarshal(body, &data) if err != nil { - logger.Info("Failed to unmarshal graphite response error: %v", err) + logger.Info("Failed to unmarshal graphite response error:", err) return m.PluginRepo{}, err } @@ -140,7 +140,7 @@ func GetPlugin(pluginId, repoUrl string) (m.Plugin, error) { var data m.Plugin err = json.Unmarshal(body, &data) if err != nil { - logger.Info("Failed to unmarshal graphite response error: %v", err) + logger.Info("Failed to unmarshal graphite response error:", err) return m.Plugin{}, err } diff --git a/pkg/components/imguploader/s3uploader.go b/pkg/components/imguploader/s3uploader.go index 62196357c61..a1e4aed0f47 100644 --- a/pkg/components/imguploader/s3uploader.go +++ b/pkg/components/imguploader/s3uploader.go @@ -60,7 +60,7 @@ func (u *S3Uploader) Upload(ctx context.Context, imageDiskPath string) (string, s3_endpoint, _ := endpoints.DefaultResolver().EndpointFor("s3", u.region) key := u.path + util.GetRandomString(20) + ".png" image_url := s3_endpoint.URL + "/" + u.bucket + "/" + key - log.Debug("Uploading image to s3", "url = ", image_url) + log.Debug("Uploading image to s3. url = %s", image_url) file, err := os.Open(imageDiskPath) if err != nil { diff --git a/pkg/log/log.go b/pkg/log/log.go index 0e6874e1b4b..8154b9b7f07 100644 --- a/pkg/log/log.go +++ b/pkg/log/log.go @@ -103,7 +103,7 @@ func Critical(skip int, format string, v ...interface{}) { } func Fatal(skip int, format string, v ...interface{}) { - Root.Crit(fmt.Sprintf(format, v)) + Root.Crit(fmt.Sprintf(format, v...)) Close() os.Exit(1) } diff --git a/pkg/login/ext_user.go b/pkg/login/ext_user.go index a421e3ebe0a..1262c1cc44f 100644 --- a/pkg/login/ext_user.go +++ b/pkg/login/ext_user.go @@ -35,7 +35,7 @@ func UpsertUser(cmd *m.UpsertUserCommand) error { limitReached, err := quota.QuotaReached(cmd.ReqContext, "user") if err != nil { - log.Warn("Error getting user quota", "err", err) + log.Warn("Error getting user quota. error: %v", err) return ErrGettingUserQuota } if limitReached { @@ -135,7 +135,7 @@ func updateUser(user *m.User, extUser *m.ExternalUserInfo) error { return nil } - log.Debug("Syncing user info", "id", user.Id, "update", updateCmd) + log.Debug2("Syncing user info", "id", user.Id, "update", updateCmd) return bus.Dispatch(updateCmd) } diff --git a/pkg/middleware/auth_proxy.go b/pkg/middleware/auth_proxy.go index 144a0ae3a69..29bd305b336 100644 --- a/pkg/middleware/auth_proxy.go +++ b/pkg/middleware/auth_proxy.go @@ -36,7 +36,7 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool { // initialize session if err := ctx.Session.Start(ctx.Context); err != nil { - log.Error(3, "Failed to start session", err) + log.Error(3, "Failed to start session. error %v", err) return false } @@ -146,12 +146,12 @@ func initContextWithAuthProxy(ctx *m.ReqContext, orgID int64) bool { if getRequestUserId(ctx) > 0 && getRequestUserId(ctx) != query.Result.UserId { // remove session if err := ctx.Session.Destory(ctx.Context); err != nil { - log.Error(3, "Failed to destroy session, err") + log.Error(3, "Failed to destroy session. error: %v", err) } // initialize a new session if err := ctx.Session.Start(ctx.Context); err != nil { - log.Error(3, "Failed to start session", err) + log.Error(3, "Failed to start session. error: %v", err) } } diff --git a/pkg/services/alerting/notifiers/telegram.go b/pkg/services/alerting/notifiers/telegram.go index ca24c996914..d79552079d5 100644 --- a/pkg/services/alerting/notifiers/telegram.go +++ b/pkg/services/alerting/notifiers/telegram.go @@ -216,7 +216,7 @@ func appendIfPossible(message string, extra string, sizeLimit int) string { if len(extra)+len(message) <= sizeLimit { return message + extra } - log.Debug("Line too long for image caption.", "value", extra) + log.Debug("Line too long for image caption. value: %s", extra) return message } diff --git a/pkg/services/sqlstore/sqlstore.go b/pkg/services/sqlstore/sqlstore.go index 13d706b6198..5477bc7b2d1 100644 --- a/pkg/services/sqlstore/sqlstore.go +++ b/pkg/services/sqlstore/sqlstore.go @@ -106,7 +106,7 @@ func (ss *SqlStore) inTransactionWithRetryCtx(ctx context.Context, callback dbTr if len(sess.events) > 0 { for _, e := range sess.events { if err = bus.Publish(e); err != nil { - log.Error(3, "Failed to publish event after commit", err) + log.Error(3, "Failed to publish event after commit. error: %v", err) } } } diff --git a/pkg/services/sqlstore/transactions.go b/pkg/services/sqlstore/transactions.go index eccd37f9a43..edf29fffb8f 100644 --- a/pkg/services/sqlstore/transactions.go +++ b/pkg/services/sqlstore/transactions.go @@ -89,7 +89,7 @@ func inTransactionWithRetryCtx(ctx context.Context, callback dbTransactionFunc, if len(sess.events) > 0 { for _, e := range sess.events { if err = bus.Publish(e); err != nil { - log.Error(3, "Failed to publish event after commit", err) + log.Error(3, "Failed to publish event after commit. error: %v", err) } } } diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index eb61568261d..aee9c00b526 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -324,7 +324,7 @@ func getCommandLineProperties(args []string) map[string]string { trimmed := strings.TrimPrefix(arg, "cfg:") parts := strings.Split(trimmed, "=") if len(parts) != 2 { - log.Fatal(3, "Invalid command line argument", arg) + log.Fatal(3, "Invalid command line argument. argument: %v", arg) return nil } From 4f91087d9a458b21f791a97674451416e5007839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 31 Aug 2018 07:15:07 +0200 Subject: [PATCH 05/36] docs: minor updates, more work to do --- .../authentication/ldap-sync-grafana-ee.md | 13 ----------- docs/sources/administration/permissions.md | 2 -- .../anonymous-auth.md => auth/anonymous.md} | 2 +- .../authentication => auth}/auth-proxy.md | 0 .../authentication => auth}/index.md | 4 ++-- .../authentication => auth}/ldap.md | 0 .../authentication => auth}/oauth.md | 0 .../authentication => auth}/overview.md | 22 ++++++++++++++----- 8 files changed, 19 insertions(+), 24 deletions(-) delete mode 100644 docs/sources/administration/authentication/ldap-sync-grafana-ee.md rename docs/sources/{administration/authentication/anonymous-auth.md => auth/anonymous.md} (96%) rename docs/sources/{administration/authentication => auth}/auth-proxy.md (100%) rename docs/sources/{administration/authentication => auth}/index.md (91%) rename docs/sources/{administration/authentication => auth}/ldap.md (100%) rename docs/sources/{administration/authentication => auth}/oauth.md (100%) rename docs/sources/{administration/authentication => auth}/overview.md (52%) diff --git a/docs/sources/administration/authentication/ldap-sync-grafana-ee.md b/docs/sources/administration/authentication/ldap-sync-grafana-ee.md deleted file mode 100644 index c60b21b0320..00000000000 --- a/docs/sources/administration/authentication/ldap-sync-grafana-ee.md +++ /dev/null @@ -1,13 +0,0 @@ -+++ -title = "LDAP Sync with Grafana EE" -description = "LDAP Sync with Grafana EE Guide " -keywords = ["grafana", "configuration", "documentation", "ldap", "enterprise"] -type = "docs" -[menu.docs] -name = "LDAP Sync with Grafana EE" -identifier = "ldap-sync" -parent = "authentication" -weight = 2 -+++ - -# LDAP Sync with Grafana EE \ No newline at end of file diff --git a/docs/sources/administration/permissions.md b/docs/sources/administration/permissions.md index e7b84a417c0..1d1a70607c8 100644 --- a/docs/sources/administration/permissions.md +++ b/docs/sources/administration/permissions.md @@ -52,8 +52,6 @@ This admin flag makes a user a `Super Admin`. This means they can access the `Se ### Dashboard & Folder Permissions -> Introduced in Grafana v5.0 - {{< docs-imagebox img="/img/docs/v50/folder_permissions.png" max-width="500px" class="docs-image--right" >}} For dashboards and dashboard folders there is a **Permissions** page that make it possible to diff --git a/docs/sources/administration/authentication/anonymous-auth.md b/docs/sources/auth/anonymous.md similarity index 96% rename from docs/sources/administration/authentication/anonymous-auth.md rename to docs/sources/auth/anonymous.md index f2cde75cacb..39d1059e92e 100644 --- a/docs/sources/administration/authentication/anonymous-auth.md +++ b/docs/sources/auth/anonymous.md @@ -4,7 +4,7 @@ description = "Anonymous authentication " keywords = ["grafana", "configuration", "documentation", "anonymous"] type = "docs" [menu.docs] -name = "Anonymous Auth" +name = "Anonymous" identifier = "anonymous-auth" parent = "authentication" weight = 4 diff --git a/docs/sources/administration/authentication/auth-proxy.md b/docs/sources/auth/auth-proxy.md similarity index 100% rename from docs/sources/administration/authentication/auth-proxy.md rename to docs/sources/auth/auth-proxy.md diff --git a/docs/sources/administration/authentication/index.md b/docs/sources/auth/index.md similarity index 91% rename from docs/sources/administration/authentication/index.md rename to docs/sources/auth/index.md index f9bc9e5f13c..455c361369a 100644 --- a/docs/sources/administration/authentication/index.md +++ b/docs/sources/auth/index.md @@ -6,5 +6,5 @@ type = "docs" name = "Authentication" identifier = "authentication" parent = "admin" -weight = 1 -+++ \ No newline at end of file +weight = 3 ++++ diff --git a/docs/sources/administration/authentication/ldap.md b/docs/sources/auth/ldap.md similarity index 100% rename from docs/sources/administration/authentication/ldap.md rename to docs/sources/auth/ldap.md diff --git a/docs/sources/administration/authentication/oauth.md b/docs/sources/auth/oauth.md similarity index 100% rename from docs/sources/administration/authentication/oauth.md rename to docs/sources/auth/oauth.md diff --git a/docs/sources/administration/authentication/overview.md b/docs/sources/auth/overview.md similarity index 52% rename from docs/sources/administration/authentication/overview.md rename to docs/sources/auth/overview.md index e7daf581abb..03a7a0e9fe4 100644 --- a/docs/sources/administration/authentication/overview.md +++ b/docs/sources/auth/overview.md @@ -9,20 +9,30 @@ parent = "authentication" weight = 1 +++ -## [auth] +# Authentication -### disable_login_form +Grafana provides many ways to authenticate users. By default it will use local users & passwords stored in the Grafana +database. + +## Settings + +Via the [server ini config file]({{< relref "installation/debian.md" >}}) you can setup many different authentication methods. Auth settings +are documented below. + +### [auth] + +#### disable_login_form Set to true to disable (hide) the login form, useful if you use OAuth, defaults to false. -### disable_signout_menu +#### disable_signout_menu Set to true to disable the signout link in the side menu. useful if you use auth.proxy, defaults to false.
-## [auth.basic] -### enabled +### [auth.basic] +#### enabled When enabled is `true` (default) the http api will accept basic authentication. -
\ No newline at end of file +
From a95453036b5f9a0f07e5e438d8ebee0e7e72e262 Mon Sep 17 00:00:00 2001 From: Sven Klemm Date: Wed, 5 Sep 2018 09:46:22 +0200 Subject: [PATCH 06/36] Add min time interval to postgres datasource --- public/app/plugins/datasource/postgres/datasource.ts | 2 ++ .../plugins/datasource/postgres/partials/config.html | 10 ++++++++++ public/app/plugins/datasource/postgres/plugin.json | 6 +++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/postgres/datasource.ts b/public/app/plugins/datasource/postgres/datasource.ts index 6522032b39f..7d4274c8d50 100644 --- a/public/app/plugins/datasource/postgres/datasource.ts +++ b/public/app/plugins/datasource/postgres/datasource.ts @@ -8,6 +8,7 @@ export class PostgresDatasource { jsonData: any; responseParser: ResponseParser; queryModel: PostgresQuery; + interval: string; /** @ngInject */ constructor(instanceSettings, private backendSrv, private $q, private templateSrv, private timeSrv) { @@ -16,6 +17,7 @@ export class PostgresDatasource { this.jsonData = instanceSettings.jsonData; this.responseParser = new ResponseParser(this.$q); this.queryModel = new PostgresQuery({}); + this.interval = instanceSettings.jsonData.timeInterval; } interpolateVariable(value, variable) { diff --git a/public/app/plugins/datasource/postgres/partials/config.html b/public/app/plugins/datasource/postgres/partials/config.html index a4df858db7e..c8b551c2aa8 100644 --- a/public/app/plugins/datasource/postgres/partials/config.html +++ b/public/app/plugins/datasource/postgres/partials/config.html @@ -61,6 +61,16 @@ +
+
+ Min time interval + + + A lower limit for the auto group by time interval. Recommended to be set to write frequency, + for example 1m if your data is written every minute. + +
+

diff --git a/public/app/plugins/datasource/postgres/plugin.json b/public/app/plugins/datasource/postgres/plugin.json index 2c2e1690a65..f236aa01b06 100644 --- a/public/app/plugins/datasource/postgres/plugin.json +++ b/public/app/plugins/datasource/postgres/plugin.json @@ -18,6 +18,10 @@ "alerting": true, "annotations": true, - "metrics": true + "metrics": true, + + "queryOptions": { + "minInterval": true + } } From fd269945c960cd85a7c7ebc4ebe9a4449bc8d063 Mon Sep 17 00:00:00 2001 From: Sven Klemm Date: Wed, 5 Sep 2018 09:54:05 +0200 Subject: [PATCH 07/36] document postgres min time interval --- docs/sources/administration/provisioning.md | 2 +- docs/sources/features/datasources/postgres.md | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/sources/administration/provisioning.md b/docs/sources/administration/provisioning.md index f3d4091defa..41a7ee7f2af 100644 --- a/docs/sources/administration/provisioning.md +++ b/docs/sources/administration/provisioning.md @@ -154,7 +154,7 @@ Since not all datasources have the same configuration settings we only have the | tlsAuthWithCACert | boolean | *All* | Enable TLS authentication using CA cert | | tlsSkipVerify | boolean | *All* | Controls whether a client verifies the server's certificate chain and host name. | | graphiteVersion | string | Graphite | Graphite version | -| timeInterval | string | Elastic, InfluxDB & Prometheus | Lowest interval/step value that should be used for this data source | +| timeInterval | string | Elastic, InfluxDB, PostgreSQL & Prometheus | Lowest interval/step value that should be used for this data source | | esVersion | number | Elastic | Elasticsearch version as a number (2/5/56) | | timeField | string | Elastic | Which field that should be used as timestamp | | interval | string | Elastic | Index date time format | diff --git a/docs/sources/features/datasources/postgres.md b/docs/sources/features/datasources/postgres.md index 4dfe6929bc1..630823cf781 100644 --- a/docs/sources/features/datasources/postgres.md +++ b/docs/sources/features/datasources/postgres.md @@ -34,6 +34,21 @@ Name | Description *Version* | This option determines which functions are available in the query builder (only available in Grafana 5.3+). *TimescaleDB* | TimescaleDB is a time-series database built as a PostgreSQL extension. If enabled, Grafana will use `time_bucket` in the `$__timeGroup` macro and display TimescaleDB specific aggregate functions in the query builder (only available in Grafana 5.3+). +### Min time interval +A lower limit for the `$__interval` variable. Recommended to be set to write frequency, for example `1m` if your data is written every minute. +This option can also be overridden/configured in a dashboard panel under data source options. It's important to note that this value **needs** to be formatted as a +number followed by a valid time identifier, e.g. `1m` (1 minute) or `30s` (30 seconds). The following time identifiers are supported: + +Identifier | Description +------------ | ------------- +`y` | year +`M` | month +`w` | week +`d` | day +`h` | hour +`m` | minute +`s` | second +`ms` | millisecond ### Database User Permissions (Important!) From e2c7b010acd23910abff5dfc6fc9b49c60159377 Mon Sep 17 00:00:00 2001 From: Sven Klemm Date: Wed, 5 Sep 2018 10:03:16 +0200 Subject: [PATCH 08/36] fix test failures for timeInterval --- public/app/plugins/datasource/postgres/datasource.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/postgres/datasource.ts b/public/app/plugins/datasource/postgres/datasource.ts index 7d4274c8d50..f1db05cabe8 100644 --- a/public/app/plugins/datasource/postgres/datasource.ts +++ b/public/app/plugins/datasource/postgres/datasource.ts @@ -17,7 +17,7 @@ export class PostgresDatasource { this.jsonData = instanceSettings.jsonData; this.responseParser = new ResponseParser(this.$q); this.queryModel = new PostgresQuery({}); - this.interval = instanceSettings.jsonData.timeInterval; + this.interval = (instanceSettings.jsonData || {}).timeInterval; } interpolateVariable(value, variable) { From 8ea2f7f8581cc821e8e1b82ac3cd9dc8a2946026 Mon Sep 17 00:00:00 2001 From: Leonard Gram Date: Wed, 5 Sep 2018 11:55:28 +0200 Subject: [PATCH 09/36] build: updated build-container with go1.11. --- .circleci/config.yml | 4 ++-- scripts/build/build-all.sh | 4 ++++ scripts/build/build.sh | 3 +++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b4480b4bade..fbc45e6abea 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -125,7 +125,7 @@ jobs: build-all: docker: - - image: grafana/build-container:1.0.0 + - image: grafana/build-container:build working_directory: /go/src/github.com/grafana/grafana steps: - checkout @@ -168,7 +168,7 @@ jobs: build: docker: - - image: grafana/build-container:1.0.0 + - image: grafana/build-container:build working_directory: /go/src/github.com/grafana/grafana steps: - checkout diff --git a/scripts/build/build-all.sh b/scripts/build/build-all.sh index 6029b14605a..0aaab2ce4a6 100755 --- a/scripts/build/build-all.sh +++ b/scripts/build/build-all.sh @@ -45,6 +45,10 @@ else fi echo "Building frontend" go run build.go ${OPT} build-frontend + +# Load ruby, needed for packing with fpm +source /etc/profile.d/rvm.sh + echo "Packaging" go run build.go -goos linux -pkg-arch amd64 ${OPT} package-only latest #removing amd64 phantomjs bin for armv7/arm64 packages diff --git a/scripts/build/build.sh b/scripts/build/build.sh index a02f079dd72..d4c1c788b30 100755 --- a/scripts/build/build.sh +++ b/scripts/build/build.sh @@ -33,5 +33,8 @@ fi echo "Building frontend" go run build.go ${OPT} build-frontend +# Load ruby, needed for packing with fpm +source /etc/profile.d/rvm.sh + echo "Packaging" go run build.go -goos linux -pkg-arch amd64 ${OPT} package-only latest From cb526d4557cf99bc038dbd5973607b3ced0d83be Mon Sep 17 00:00:00 2001 From: Sven Klemm Date: Wed, 5 Sep 2018 12:02:57 +0200 Subject: [PATCH 10/36] Add min time interval to mysql and mssql --- docs/sources/administration/provisioning.md | 2 +- docs/sources/features/datasources/mssql.md | 16 ++++++++++++++++ docs/sources/features/datasources/mysql.md | 16 ++++++++++++++++ .../app/plugins/datasource/mssql/datasource.ts | 2 ++ .../datasource/mssql/partials/config.html | 15 +++++++++++++++ public/app/plugins/datasource/mssql/plugin.json | 7 ++++++- .../app/plugins/datasource/mysql/datasource.ts | 2 ++ .../datasource/mysql/partials/config.html | 15 +++++++++++++++ public/app/plugins/datasource/mysql/plugin.json | 7 ++++++- 9 files changed, 79 insertions(+), 3 deletions(-) diff --git a/docs/sources/administration/provisioning.md b/docs/sources/administration/provisioning.md index 41a7ee7f2af..b2310378f16 100644 --- a/docs/sources/administration/provisioning.md +++ b/docs/sources/administration/provisioning.md @@ -154,7 +154,7 @@ Since not all datasources have the same configuration settings we only have the | tlsAuthWithCACert | boolean | *All* | Enable TLS authentication using CA cert | | tlsSkipVerify | boolean | *All* | Controls whether a client verifies the server's certificate chain and host name. | | graphiteVersion | string | Graphite | Graphite version | -| timeInterval | string | Elastic, InfluxDB, PostgreSQL & Prometheus | Lowest interval/step value that should be used for this data source | +| timeInterval | string | Elastic, InfluxDB, MSSQL, MySQL, PostgreSQL & Prometheus | Lowest interval/step value that should be used for this data source | | esVersion | number | Elastic | Elasticsearch version as a number (2/5/56) | | timeField | string | Elastic | Which field that should be used as timestamp | | interval | string | Elastic | Index date time format | diff --git a/docs/sources/features/datasources/mssql.md b/docs/sources/features/datasources/mssql.md index da0c9581e99..869f25f70cf 100644 --- a/docs/sources/features/datasources/mssql.md +++ b/docs/sources/features/datasources/mssql.md @@ -33,6 +33,22 @@ Name | Description *User* | Database user's login/username *Password* | Database user's password +### Min time interval +A lower limit for the `$__interval` variable. Recommended to be set to write frequency, for example `1m` if your data is written every minute. +This option can also be overridden/configured in a dashboard panel under data source options. It's important to note that this value **needs** to be formatted as a +number followed by a valid time identifier, e.g. `1m` (1 minute) or `30s` (30 seconds). The following time identifiers are supported: + +Identifier | Description +------------ | ------------- +`y` | year +`M` | month +`w` | week +`d` | day +`h` | hour +`m` | minute +`s` | second +`ms` | millisecond + ### Database User Permissions (Important!) The database user you specify when you add the data source should only be granted SELECT permissions on diff --git a/docs/sources/features/datasources/mysql.md b/docs/sources/features/datasources/mysql.md index afac746b050..91986866a85 100644 --- a/docs/sources/features/datasources/mysql.md +++ b/docs/sources/features/datasources/mysql.md @@ -36,6 +36,22 @@ Name | Description *User* | Database user's login/username *Password* | Database user's password +### Min time interval +A lower limit for the `$__interval` variable. Recommended to be set to write frequency, for example `1m` if your data is written every minute. +This option can also be overridden/configured in a dashboard panel under data source options. It's important to note that this value **needs** to be formatted as a +number followed by a valid time identifier, e.g. `1m` (1 minute) or `30s` (30 seconds). The following time identifiers are supported: + +Identifier | Description +------------ | ------------- +`y` | year +`M` | month +`w` | week +`d` | day +`h` | hour +`m` | minute +`s` | second +`ms` | millisecond + ### Database User Permissions (Important!) The database user you specify when you add the data source should only be granted SELECT permissions on diff --git a/public/app/plugins/datasource/mssql/datasource.ts b/public/app/plugins/datasource/mssql/datasource.ts index fc497b2c274..3dce972d241 100644 --- a/public/app/plugins/datasource/mssql/datasource.ts +++ b/public/app/plugins/datasource/mssql/datasource.ts @@ -5,12 +5,14 @@ export class MssqlDatasource { id: any; name: any; responseParser: ResponseParser; + interval: string; /** @ngInject */ constructor(instanceSettings, private backendSrv, private $q, private templateSrv) { this.name = instanceSettings.name; this.id = instanceSettings.id; this.responseParser = new ResponseParser(this.$q); + this.interval = (instanceSettings.jsonData || {}).timeInterval; } interpolateVariable(value, variable) { diff --git a/public/app/plugins/datasource/mssql/partials/config.html b/public/app/plugins/datasource/mssql/partials/config.html index 7f9dc03f286..f8a36502009 100644 --- a/public/app/plugins/datasource/mssql/partials/config.html +++ b/public/app/plugins/datasource/mssql/partials/config.html @@ -29,6 +29,21 @@

+

MSSQL details

+ +
+
+
+ Min time interval + + + A lower limit for the auto group by time interval. Recommended to be set to write frequency, + for example 1m if your data is written every minute. + +
+
+
+
User Permission
diff --git a/public/app/plugins/datasource/mssql/plugin.json b/public/app/plugins/datasource/mssql/plugin.json index ac5ea49ebe9..a3df148bc2b 100644 --- a/public/app/plugins/datasource/mssql/plugin.json +++ b/public/app/plugins/datasource/mssql/plugin.json @@ -17,5 +17,10 @@ "alerting": true, "annotations": true, - "metrics": true + "metrics": true, + + "queryOptions": { + "minInterval": true + } + } diff --git a/public/app/plugins/datasource/mysql/datasource.ts b/public/app/plugins/datasource/mysql/datasource.ts index eca223f2d6d..e09c18bb25a 100644 --- a/public/app/plugins/datasource/mysql/datasource.ts +++ b/public/app/plugins/datasource/mysql/datasource.ts @@ -5,12 +5,14 @@ export class MysqlDatasource { id: any; name: any; responseParser: ResponseParser; + interval: string; /** @ngInject */ constructor(instanceSettings, private backendSrv, private $q, private templateSrv) { this.name = instanceSettings.name; this.id = instanceSettings.id; this.responseParser = new ResponseParser(this.$q); + this.interval = (instanceSettings.jsonData || {}).timeInterval; } interpolateVariable(value, variable) { diff --git a/public/app/plugins/datasource/mysql/partials/config.html b/public/app/plugins/datasource/mysql/partials/config.html index 8cbeece71dd..6bc9cceb8f1 100644 --- a/public/app/plugins/datasource/mysql/partials/config.html +++ b/public/app/plugins/datasource/mysql/partials/config.html @@ -24,6 +24,21 @@
+

MySQL details

+ +
+
+
+ Min time interval + + + A lower limit for the auto group by time interval. Recommended to be set to write frequency, + for example 1m if your data is written every minute. + +
+
+
+
User Permission
diff --git a/public/app/plugins/datasource/mysql/plugin.json b/public/app/plugins/datasource/mysql/plugin.json index 363b9364016..f3a8efe267e 100644 --- a/public/app/plugins/datasource/mysql/plugin.json +++ b/public/app/plugins/datasource/mysql/plugin.json @@ -18,5 +18,10 @@ "alerting": true, "annotations": true, - "metrics": true + "metrics": true, + + "queryOptions": { + "minInterval": true + } + } From 275f6130503a92476766c827359bdcf428908671 Mon Sep 17 00:00:00 2001 From: Leonard Gram Date: Wed, 5 Sep 2018 12:12:46 +0200 Subject: [PATCH 11/36] Only authenticate logins when password is set (#13147) * auth: never authenticate passwords shorter than 4 chars. * auth: refactoring password length check. * auth: does not authenticate when password is empty. * auth: removes unneccesary change. --- pkg/login/auth.go | 13 ++++++++++++- pkg/login/auth_test.go | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/pkg/login/auth.go b/pkg/login/auth.go index 215a22cde33..991fa72fd54 100644 --- a/pkg/login/auth.go +++ b/pkg/login/auth.go @@ -2,7 +2,6 @@ package login import ( "errors" - "github.com/grafana/grafana/pkg/bus" m "github.com/grafana/grafana/pkg/models" ) @@ -14,6 +13,7 @@ var ( ErrProviderDeniedRequest = errors.New("Login provider denied login request") ErrSignUpNotAllowed = errors.New("Signup is not allowed for this adapter") ErrTooManyLoginAttempts = errors.New("Too many consecutive incorrect login attempts for user. Login for user temporarily blocked") + ErrPasswordEmpty = errors.New("No password provided.") ErrUsersQuotaReached = errors.New("Users quota reached") ErrGettingUserQuota = errors.New("Error getting user quota") ) @@ -28,6 +28,10 @@ func AuthenticateUser(query *m.LoginUserQuery) error { return err } + if err := validatePasswordSet(query.Password); err != nil { + return err + } + err := loginUsingGrafanaDB(query) if err == nil || (err != m.ErrUserNotFound && err != ErrInvalidCredentials) { return err @@ -52,3 +56,10 @@ func AuthenticateUser(query *m.LoginUserQuery) error { return err } +func validatePasswordSet(password string) error { + if len(password) == 0 { + return ErrPasswordEmpty + } + + return nil +} diff --git a/pkg/login/auth_test.go b/pkg/login/auth_test.go index 932125c410e..a4cd8284cdd 100644 --- a/pkg/login/auth_test.go +++ b/pkg/login/auth_test.go @@ -10,6 +10,24 @@ import ( func TestAuthenticateUser(t *testing.T) { Convey("Authenticate user", t, func() { + authScenario("When a user authenticates without setting a password", func(sc *authScenarioContext) { + mockLoginAttemptValidation(nil, sc) + mockLoginUsingGrafanaDB(nil, sc) + mockLoginUsingLdap(false, nil, sc) + + loginQuery := m.LoginUserQuery{ + Username: "user", + Password: "", + } + err := AuthenticateUser(&loginQuery) + + Convey("login should fail", func() { + So(sc.grafanaLoginWasCalled, ShouldBeFalse) + So(sc.ldapLoginWasCalled, ShouldBeFalse) + So(err, ShouldEqual, ErrPasswordEmpty) + }) + }) + authScenario("When a user authenticates having too many login attempts", func(sc *authScenarioContext) { mockLoginAttemptValidation(ErrTooManyLoginAttempts, sc) mockLoginUsingGrafanaDB(nil, sc) From eed141fb54162116d05589f3e72bd601c348e034 Mon Sep 17 00:00:00 2001 From: Leonard Gram Date: Wed, 5 Sep 2018 15:10:57 +0200 Subject: [PATCH 12/36] build: uses 1.1.0 of the build container. --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index fbc45e6abea..eb8724bed3c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -125,7 +125,7 @@ jobs: build-all: docker: - - image: grafana/build-container:build + - image: grafana/build-container:1.1.0 working_directory: /go/src/github.com/grafana/grafana steps: - checkout @@ -168,7 +168,7 @@ jobs: build: docker: - - image: grafana/build-container:build + - image: grafana/build-container:1.1.0 working_directory: /go/src/github.com/grafana/grafana steps: - checkout From 25f13bd3adafe1adceeee4542b7f33a4ea3d4e57 Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Wed, 5 Sep 2018 15:28:30 +0200 Subject: [PATCH 13/36] added only-arrow-functions rule and changed files to follow new rule (#13154) --- .../components/sql_part/sql_part_editor.ts | 20 ++++++++-------- public/app/core/services/analytics.ts | 2 +- public/app/core/services/ng_react.ts | 2 +- .../plugins/datasource/postgres/query_ctrl.ts | 12 +++++----- .../postgres/specs/postgres_query.test.ts | 24 +++++++++---------- tslint.json | 1 + 6 files changed, 31 insertions(+), 30 deletions(-) diff --git a/public/app/core/components/sql_part/sql_part_editor.ts b/public/app/core/components/sql_part/sql_part_editor.ts index 5d0f63a6953..8097dddeb3b 100644 --- a/public/app/core/components/sql_part/sql_part_editor.ts +++ b/public/app/core/components/sql_part/sql_part_editor.ts @@ -55,7 +55,7 @@ export function sqlPartEditorDirective($compile, templateSrv) { } function inputBlur($input, paramIndex) { - cancelBlur = setTimeout(function() { + cancelBlur = setTimeout(() => { switchToLink($input, paramIndex); }, 200); } @@ -95,20 +95,20 @@ export function sqlPartEditorDirective($compile, templateSrv) { return; } - const typeaheadSource = function(query, callback) { + const typeaheadSource = (query, callback) => { if (param.options) { let options = param.options; if (param.type === 'int') { - options = _.map(options, function(val) { + options = _.map(options, val => { return val.toString(); }); } return options; } - $scope.$apply(function() { - $scope.handleEvent({ $event: { name: 'get-param-options', param: param } }).then(function(result) { - const dynamicOptions = _.map(result, function(op) { + $scope.$apply(() => { + $scope.handleEvent({ $event: { name: 'get-param-options', param: param } }).then(result => { + const dynamicOptions = _.map(result, op => { return op.value; }); @@ -128,7 +128,7 @@ export function sqlPartEditorDirective($compile, templateSrv) { source: typeaheadSource, minLength: 0, items: 1000, - updater: function(value) { + updater: value => { if (value === part.params[paramIndex]) { clearTimeout(cancelBlur); $input.focus(); @@ -150,18 +150,18 @@ export function sqlPartEditorDirective($compile, templateSrv) { } } - $scope.showActionsMenu = function() { + $scope.showActionsMenu = () => { $scope.handleEvent({ $event: { name: 'get-part-actions' } }).then(res => { $scope.partActions = res; }); }; - $scope.triggerPartAction = function(action) { + $scope.triggerPartAction = action => { $scope.handleEvent({ $event: { name: 'action', action: action } }); }; function addElementsAndCompile() { - _.each(partDef.params, function(param, index) { + _.each(partDef.params, (param, index) => { if (param.optional && part.params.length <= index) { return; } diff --git a/public/app/core/services/analytics.ts b/public/app/core/services/analytics.ts index d50140bbd75..be4371adb26 100644 --- a/public/app/core/services/analytics.ts +++ b/public/app/core/services/analytics.ts @@ -14,8 +14,8 @@ export class Analytics { }); const ga = ((window as any).ga = (window as any).ga || + //tslint:disable-next-line:only-arrow-functions function() { - //tslint:disable-line:only-arrow-functions (ga.q = ga.q || []).push(arguments); }); ga.l = +new Date(); diff --git a/public/app/core/services/ng_react.ts b/public/app/core/services/ng_react.ts index 643e34dd62e..6a712b29dab 100644 --- a/public/app/core/services/ng_react.ts +++ b/public/app/core/services/ng_react.ts @@ -52,8 +52,8 @@ function applied(fn, scope) { if (fn.wrappedInApply) { return fn; } + //tslint:disable-next-line:only-arrow-functions const wrapped: any = function() { - //tslint:disable-line:only-arrow-functions const args = arguments; const phase = scope.$root.$$phase; if (phase === '$apply' || phase === '$digest') { diff --git a/public/app/plugins/datasource/postgres/query_ctrl.ts b/public/app/plugins/datasource/postgres/query_ctrl.ts index 1cb8bfa5a05..9343a260a9e 100644 --- a/public/app/plugins/datasource/postgres/query_ctrl.ts +++ b/public/app/plugins/datasource/postgres/query_ctrl.ts @@ -96,7 +96,7 @@ export class PostgresQueryCtrl extends QueryCtrl { } updateProjection() { - this.selectParts = _.map(this.target.select, function(parts: any) { + this.selectParts = _.map(this.target.select, (parts: any) => { return _.map(parts, sqlPart.create).filter(n => n); }); this.whereParts = _.map(this.target.where, sqlPart.create).filter(n => n); @@ -104,15 +104,15 @@ export class PostgresQueryCtrl extends QueryCtrl { } updatePersistedParts() { - this.target.select = _.map(this.selectParts, function(selectParts) { - return _.map(selectParts, function(part: any) { + this.target.select = _.map(this.selectParts, selectParts => { + return _.map(selectParts, (part: any) => { return { type: part.def.type, datatype: part.datatype, params: part.params }; }); }); - this.target.where = _.map(this.whereParts, function(part: any) { + this.target.where = _.map(this.whereParts, (part: any) => { return { type: part.def.type, datatype: part.datatype, name: part.name, params: part.params }; }); - this.target.group = _.map(this.groupParts, function(part: any) { + this.target.group = _.map(this.groupParts, (part: any) => { return { type: part.def.type, datatype: part.datatype, params: part.params }; }); } @@ -355,7 +355,7 @@ export class PostgresQueryCtrl extends QueryCtrl { switch (partType) { case 'column': - const parts = _.map(selectParts, function(part: any) { + const parts = _.map(selectParts, (part: any) => { return sqlPart.create({ type: part.def.type, params: _.clone(part.params) }); }); this.selectParts.push(parts); diff --git a/public/app/plugins/datasource/postgres/specs/postgres_query.test.ts b/public/app/plugins/datasource/postgres/specs/postgres_query.test.ts index 877bd47618b..0d6f61a8748 100644 --- a/public/app/plugins/datasource/postgres/specs/postgres_query.test.ts +++ b/public/app/plugins/datasource/postgres/specs/postgres_query.test.ts @@ -1,22 +1,22 @@ import PostgresQuery from '../postgres_query'; -describe('PostgresQuery', function() { +describe('PostgresQuery', () => { const templateSrv = { replace: jest.fn(text => text), }; - describe('When initializing', function() { - it('should not be in SQL mode', function() { + describe('When initializing', () => { + it('should not be in SQL mode', () => { const query = new PostgresQuery({}, templateSrv); expect(query.target.rawQuery).toBe(false); }); - it('should be in SQL mode for pre query builder queries', function() { + it('should be in SQL mode for pre query builder queries', () => { const query = new PostgresQuery({ rawSql: 'SELECT 1' }, templateSrv); expect(query.target.rawQuery).toBe(true); }); }); - describe('When generating time column SQL', function() { + describe('When generating time column SQL', () => { const query = new PostgresQuery({}, templateSrv); query.target.timeColumn = 'time'; @@ -25,7 +25,7 @@ describe('PostgresQuery', function() { expect(query.buildTimeColumn()).toBe('"time" AS "time"'); }); - describe('When generating time column SQL with group by time', function() { + describe('When generating time column SQL with group by time', () => { let query = new PostgresQuery( { timeColumn: 'time', group: [{ type: 'time', params: ['5m', 'none'] }] }, templateSrv @@ -44,7 +44,7 @@ describe('PostgresQuery', function() { expect(query.buildTimeColumn(false)).toBe('$__unixEpochGroup(time,5m)'); }); - describe('When generating metric column SQL', function() { + describe('When generating metric column SQL', () => { const query = new PostgresQuery({}, templateSrv); query.target.metricColumn = 'host'; @@ -53,7 +53,7 @@ describe('PostgresQuery', function() { expect(query.buildMetricColumn()).toBe('"host" AS metric'); }); - describe('When generating value column SQL', function() { + describe('When generating value column SQL', () => { const query = new PostgresQuery({}, templateSrv); let column = [{ type: 'column', params: ['value'] }]; @@ -76,7 +76,7 @@ describe('PostgresQuery', function() { ); }); - describe('When generating value column SQL with metric column', function() { + describe('When generating value column SQL with metric column', () => { const query = new PostgresQuery({}, templateSrv); query.target.metricColumn = 'host'; @@ -110,7 +110,7 @@ describe('PostgresQuery', function() { ); }); - describe('When generating WHERE clause', function() { + describe('When generating WHERE clause', () => { const query = new PostgresQuery({ where: [] }, templateSrv); expect(query.buildWhereClause()).toBe(''); @@ -126,7 +126,7 @@ describe('PostgresQuery', function() { expect(query.buildWhereClause()).toBe('\nWHERE\n $__timeFilter(t) AND\n v = 1'); }); - describe('When generating GROUP BY clause', function() { + describe('When generating GROUP BY clause', () => { const query = new PostgresQuery({ group: [], metricColumn: 'none' }, templateSrv); expect(query.buildGroupClause()).toBe(''); @@ -136,7 +136,7 @@ describe('PostgresQuery', function() { expect(query.buildGroupClause()).toBe('\nGROUP BY 1,2'); }); - describe('When generating complete statement', function() { + describe('When generating complete statement', () => { const target = { timeColumn: 't', table: 'table', diff --git a/tslint.json b/tslint.json index 13323068ec1..15dc83ec575 100644 --- a/tslint.json +++ b/tslint.json @@ -49,6 +49,7 @@ "no-var-keyword": true, "object-literal-sort-keys": false, "one-line": [true, "check-open-brace", "check-catch", "check-else"], + "only-arrow-functions": [true, "allow-declarations", "allow-named-functions"], "prefer-const": true, "radix": false, "typedef-whitespace": [ From 500a4b5f354d4fc7119117f82485dc4257f817f1 Mon Sep 17 00:00:00 2001 From: Leonard Gram Date: Wed, 5 Sep 2018 16:46:22 +0200 Subject: [PATCH 14/36] docs: default paths in the docker container. --- docs/sources/installation/docker.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/sources/installation/docker.md b/docs/sources/installation/docker.md index c71dc105ad4..ba0d6199ba4 100644 --- a/docs/sources/installation/docker.md +++ b/docs/sources/installation/docker.md @@ -20,7 +20,7 @@ $ docker run -d -p 3000:3000 grafana/grafana ## Configuration -All options defined in conf/grafana.ini can be overridden using environment +All options defined in `conf/grafana.ini` can be overridden using environment variables by using the syntax `GF__`. For example: @@ -40,6 +40,19 @@ those options. > For any changes to `conf/grafana.ini` (or corresponding environment variables) to take effect you need to restart Grafana by restarting the Docker container. +### Default Paths + +The following settings are hard-coded when launching the Grafana Docker container and can only be overridden using environment variables, not in `conf/grafana.ini`. + +Setting | Default value +----------------------|--------------------------- +GF_PATHS_CONFIG | /etc/grafana/grafana.ini +GF_PATHS_DATA | /var/lib/grafana +GF_PATHS_HOME | /usr/share/grafana +GF_PATHS_LOGS | /var/log/grafana +GF_PATHS_PLUGINS | /var/lib/grafana/plugins +GF_PATHS_PROVISIONING | /etc/grafana/provisioning + ## Running a Specific Version of Grafana ```bash From 2b74b1c4d615ca19f7f789ea245b809d4261fb6d Mon Sep 17 00:00:00 2001 From: Patrick O'Carroll Date: Wed, 5 Sep 2018 16:51:31 +0200 Subject: [PATCH 15/36] added radix rule and changed files to follow rule (#13153) --- public/app/containers/Explore/TimePicker.tsx | 2 +- public/app/core/utils/rangeutil.ts | 2 +- public/app/features/dashboard/time_srv.ts | 2 +- public/app/features/dashboard/view_state_srv.ts | 2 +- public/app/features/panel/solo_panel_ctrl.ts | 2 +- public/app/features/playlist/playlist_edit_ctrl.ts | 2 +- public/app/plugins/datasource/elasticsearch/bucket_agg.ts | 2 +- public/app/plugins/datasource/elasticsearch/metric_agg.ts | 2 +- public/app/plugins/datasource/influxdb/datasource.ts | 2 +- public/app/plugins/datasource/opentsdb/datasource.ts | 4 ++-- .../app/plugins/datasource/prometheus/result_transformer.ts | 2 +- public/app/plugins/panel/graph/threshold_manager.ts | 2 +- public/app/plugins/panel/heatmap/heatmap_data_converter.ts | 2 +- public/app/plugins/panel/singlestat/module.ts | 2 +- tslint.json | 2 +- 15 files changed, 16 insertions(+), 16 deletions(-) diff --git a/public/app/containers/Explore/TimePicker.tsx b/public/app/containers/Explore/TimePicker.tsx index 3ae4ea4a83c..08867f8d0fc 100644 --- a/public/app/containers/Explore/TimePicker.tsx +++ b/public/app/containers/Explore/TimePicker.tsx @@ -16,7 +16,7 @@ export function parseTime(value, isUtc = false, asString = false) { return value; } if (!isNaN(value)) { - const epoch = parseInt(value); + const epoch = parseInt(value, 10); const m = isUtc ? moment.utc(epoch) : moment(epoch); return asString ? m.format(DATE_FORMAT) : m; } diff --git a/public/app/core/utils/rangeutil.ts b/public/app/core/utils/rangeutil.ts index 852e2ed3c50..484dd0e3327 100644 --- a/public/app/core/utils/rangeutil.ts +++ b/public/app/core/utils/rangeutil.ts @@ -111,7 +111,7 @@ export function describeTextRange(expr: any) { const parts = /^now([-+])(\d+)(\w)/.exec(expr); if (parts) { const unit = parts[3]; - const amount = parseInt(parts[2]); + const amount = parseInt(parts[2], 10); const span = spans[unit]; if (span) { opt.display = isLast ? 'Last ' : 'Next '; diff --git a/public/app/features/dashboard/time_srv.ts b/public/app/features/dashboard/time_srv.ts index 4bd78ce776d..dd5a0ba758f 100644 --- a/public/app/features/dashboard/time_srv.ts +++ b/public/app/features/dashboard/time_srv.ts @@ -70,7 +70,7 @@ export class TimeSrv { } if (!isNaN(value)) { - const epoch = parseInt(value); + const epoch = parseInt(value, 10); return moment.utc(epoch); } diff --git a/public/app/features/dashboard/view_state_srv.ts b/public/app/features/dashboard/view_state_srv.ts index 521de4ecbad..d9ad6827567 100644 --- a/public/app/features/dashboard/view_state_srv.ts +++ b/public/app/features/dashboard/view_state_srv.ts @@ -49,7 +49,7 @@ export class DashboardViewState { getQueryStringState() { const state = this.$location.search(); - state.panelId = parseInt(state.panelId) || null; + state.panelId = parseInt(state.panelId, 10) || null; state.fullscreen = state.fullscreen ? true : null; state.edit = state.edit === 'true' || state.edit === true || null; state.editview = state.editview || null; diff --git a/public/app/features/panel/solo_panel_ctrl.ts b/public/app/features/panel/solo_panel_ctrl.ts index 0e45fe48c4d..15d35188d6d 100644 --- a/public/app/features/panel/solo_panel_ctrl.ts +++ b/public/app/features/panel/solo_panel_ctrl.ts @@ -12,7 +12,7 @@ export class SoloPanelCtrl { appEvents.emit('toggle-sidemenu-hidden'); const params = $location.search(); - panelId = parseInt(params.panelId); + panelId = parseInt(params.panelId, 10); $scope.onAppEvent('dashboard-initialized', $scope.initPanelScope); diff --git a/public/app/features/playlist/playlist_edit_ctrl.ts b/public/app/features/playlist/playlist_edit_ctrl.ts index 3c81aff1093..16da9a0a209 100644 --- a/public/app/features/playlist/playlist_edit_ctrl.ts +++ b/public/app/features/playlist/playlist_edit_ctrl.ts @@ -37,7 +37,7 @@ export class PlaylistEditCtrl { filterFoundPlaylistItems() { this.filteredDashboards = _.reject(this.dashboardresult, playlistItem => { return _.find(this.playlistItems, listPlaylistItem => { - return parseInt(listPlaylistItem.value) === playlistItem.id; + return parseInt(listPlaylistItem.value, 10) === playlistItem.id; }); }); diff --git a/public/app/plugins/datasource/elasticsearch/bucket_agg.ts b/public/app/plugins/datasource/elasticsearch/bucket_agg.ts index e17a34778ee..8963f2c3f4b 100644 --- a/public/app/plugins/datasource/elasticsearch/bucket_agg.ts +++ b/public/app/plugins/datasource/elasticsearch/bucket_agg.ts @@ -208,7 +208,7 @@ export class ElasticBucketAggCtrl { const id = _.reduce( $scope.target.bucketAggs.concat($scope.target.metrics), (max, val) => { - return parseInt(val.id) > max ? parseInt(val.id) : max; + return parseInt(val.id, 10) > max ? parseInt(val.id, 10) : max; }, 0 ); diff --git a/public/app/plugins/datasource/elasticsearch/metric_agg.ts b/public/app/plugins/datasource/elasticsearch/metric_agg.ts index 7e5300b43e1..623eed68914 100644 --- a/public/app/plugins/datasource/elasticsearch/metric_agg.ts +++ b/public/app/plugins/datasource/elasticsearch/metric_agg.ts @@ -177,7 +177,7 @@ export class ElasticMetricAggCtrl { const id = _.reduce( $scope.target.bucketAggs.concat($scope.target.metrics), (max, val) => { - return parseInt(val.id) > max ? parseInt(val.id) : max; + return parseInt(val.id, 10) > max ? parseInt(val.id, 10) : max; }, 0 ); diff --git a/public/app/plugins/datasource/influxdb/datasource.ts b/public/app/plugins/datasource/influxdb/datasource.ts index ec995de630a..5ffbf7cf418 100644 --- a/public/app/plugins/datasource/influxdb/datasource.ts +++ b/public/app/plugins/datasource/influxdb/datasource.ts @@ -314,7 +314,7 @@ export default class InfluxDatasource { const parts = /^now-(\d+)([d|h|m|s])$/.exec(date); if (parts) { - const amount = parseInt(parts[1]); + const amount = parseInt(parts[1], 10); const unit = parts[2]; return 'now() - ' + amount + unit; } diff --git a/public/app/plugins/datasource/opentsdb/datasource.ts b/public/app/plugins/datasource/opentsdb/datasource.ts index 08bd1585b42..7cb0806359d 100644 --- a/public/app/plugins/datasource/opentsdb/datasource.ts +++ b/public/app/plugins/datasource/opentsdb/datasource.ts @@ -408,11 +408,11 @@ export default class OpenTsDatasource { }; if (target.counterMax && target.counterMax.length) { - query.rateOptions.counterMax = parseInt(target.counterMax); + query.rateOptions.counterMax = parseInt(target.counterMax, 10); } if (target.counterResetValue && target.counterResetValue.length) { - query.rateOptions.resetValue = parseInt(target.counterResetValue); + query.rateOptions.resetValue = parseInt(target.counterResetValue, 10); } if (tsdbVersion >= 2) { diff --git a/public/app/plugins/datasource/prometheus/result_transformer.ts b/public/app/plugins/datasource/prometheus/result_transformer.ts index 96b8e0d4137..bf916bebf04 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.ts @@ -37,7 +37,7 @@ export class ResultTransformer { metricLabel = this.createMetricLabel(metricData.metric, options); - const stepMs = parseInt(options.step) * 1000; + const stepMs = parseInt(options.step, 10) * 1000; let baseTimestamp = start * 1000; if (metricData.values === undefined) { diff --git a/public/app/plugins/panel/graph/threshold_manager.ts b/public/app/plugins/panel/graph/threshold_manager.ts index 46ec9e61854..e7d874e7451 100644 --- a/public/app/plugins/panel/graph/threshold_manager.ts +++ b/public/app/plugins/panel/graph/threshold_manager.ts @@ -53,7 +53,7 @@ export class ThresholdManager { function stopped() { // calculate graph level let graphValue = plot.c2p({ left: 0, top: posTop }).y; - graphValue = parseInt(graphValue.toFixed(0)); + graphValue = parseInt(graphValue.toFixed(0), 10); model.value = graphValue; handleElem.off('mousemove', dragging); diff --git a/public/app/plugins/panel/heatmap/heatmap_data_converter.ts b/public/app/plugins/panel/heatmap/heatmap_data_converter.ts index 68ab6fee92f..99b61be40dc 100644 --- a/public/app/plugins/panel/heatmap/heatmap_data_converter.ts +++ b/public/app/plugins/panel/heatmap/heatmap_data_converter.ts @@ -271,7 +271,7 @@ function pushToYBuckets(buckets, bucketNum, value, point, bounds) { let count = 1; // Use the 3rd argument as scale/count if (point.length > 3) { - count = parseInt(point[2]); + count = parseInt(point[2], 10); } if (buckets[bucketNum]) { buckets[bucketNum].values.push(value); diff --git a/public/app/plugins/panel/singlestat/module.ts b/public/app/plugins/panel/singlestat/module.ts index fe79b5f5043..b10eb68b87e 100644 --- a/public/app/plugins/panel/singlestat/module.ts +++ b/public/app/plugins/panel/singlestat/module.ts @@ -493,7 +493,7 @@ class SingleStatCtrl extends MetricsPanelCtrl { const bgColor = config.bootData.user.lightTheme ? 'rgb(230,230,230)' : 'rgb(38,38,38)'; - const fontScale = parseInt(panel.valueFontSize) / 100; + const fontScale = parseInt(panel.valueFontSize, 10) / 100; const fontSize = Math.min(dimension / 5, 100) * fontScale; // Reduce gauge width if threshold labels enabled const gaugeWidthReduceRatio = panel.gauge.thresholdLabels ? 1.5 : 1; diff --git a/tslint.json b/tslint.json index 15dc83ec575..4c7ea71366c 100644 --- a/tslint.json +++ b/tslint.json @@ -51,7 +51,7 @@ "one-line": [true, "check-open-brace", "check-catch", "check-else"], "only-arrow-functions": [true, "allow-declarations", "allow-named-functions"], "prefer-const": true, - "radix": false, + "radix": true, "typedef-whitespace": [ true, { From 42d26400b1c810de25ef645d44a2dd6198246554 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Wed, 5 Sep 2018 18:47:26 +0200 Subject: [PATCH 16/36] changelog: add notes about closing #13030 [skip ci] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a623d5ea8e..e8afd55c222 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -84,6 +84,7 @@ These are new features that's still being worked on and are in an experimental p ### Tech * **Frontend**: Convert all Frontend Karma tests to Jest tests [#12224](https://github.com/grafana/grafana/issues/12224) +* **Backend**: Upgrade to golang 1.11 [#13030](https://github.com/grafana/grafana/issues/13030) # 5.2.3 (2018-08-29) From d76dad86c801aef31c7811e0fdcf1bcb3fcbe547 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Wed, 5 Sep 2018 18:49:08 +0200 Subject: [PATCH 17/36] changelog: order changes by group (ocd) [skip ci] --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e8afd55c222..d8470adc81a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,6 @@ ### Minor -* **Units**: Adds bitcoin axes unit. [#13125](https://github.com/grafana/grafana/pull/13125) * **GrafanaCli**: Fixed issue with grafana-cli install plugin resulting in corrupt http response from source error. Fixes [#13079](https://github.com/grafana/grafana/issues/13079) * **Logging**: Reopen log files after receiving a SIGHUP signal [#13112](https://github.com/grafana/grafana/pull/13112), thx [@filewalkwithme](https://github.com/filewalkwithme) * **Api**: Delete nonexistent datasource should return 404 [#12313](https://github.com/grafana/grafana/issues/12313), thx [@AustinWinstanley](https://github.com/AustinWinstanley) @@ -58,6 +57,7 @@ * **OAuth**: Fix overriding tls_skip_verify_insecure using environment variable [#12747](https://github.com/grafana/grafana/issues/12747), thx [@jangaraj](https://github.com/jangaraj) * **Units**: Change units to include characters for power of 2 and 3 [#12744](https://github.com/grafana/grafana/pull/12744), thx [@Worty](https://github.com/Worty) * **Units**: Polish złoty currency [#12691](https://github.com/grafana/grafana/pull/12691), thx [@mwegrzynek](https://github.com/mwegrzynek) +* **Units**: Adds bitcoin axes unit. [#13125](https://github.com/grafana/grafana/pull/13125) * **Graph**: Option to hide series from tooltip [#3341](https://github.com/grafana/grafana/issues/3341), thx [@mtanda](https://github.com/mtanda) * **UI**: Fix iOS home screen "app" icon and Windows 10 app experience [#12752](https://github.com/grafana/grafana/issues/12752), thx [@andig](https://github.com/andig) * **Datasource**: Fix UI issue with secret fields after updating datasource [#11270](https://github.com/grafana/grafana/issues/11270) From e983f8f54b85a4b7ca6543a1f68a82a98fcab47b Mon Sep 17 00:00:00 2001 From: Henrique Oliveira Date: Wed, 5 Sep 2018 17:35:22 -0300 Subject: [PATCH 18/36] Adding Action to view the graph by its public URL. --- pkg/services/alerting/notifiers/teams.go | 28 +++++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/pkg/services/alerting/notifiers/teams.go b/pkg/services/alerting/notifiers/teams.go index 09bcf600533..06fc8c1c5c2 100644 --- a/pkg/services/alerting/notifiers/teams.go +++ b/pkg/services/alerting/notifiers/teams.go @@ -96,14 +96,26 @@ func (this *TeamsNotifier) Notify(evalContext *alerting.EvalContext) error { }, }, "text": message, - "potentialAction": []map[string]interface{}{ - { - "@context": "http://schema.org", - "@type": "ViewAction", - "name": "View Rule", - "target": []string{ - ruleUrl, - }, + }, + }, + "potentialAction": []map[string]interface{}{ + { + "@context": "http://schema.org", + "@type": "OpenUri", + "name": "View Rule", + "targets": []map[string]interface{}{ + { + "os": "default", "uri": ruleUrl, + }, + }, + }, + { + "@context": "http://schema.org", + "@type": "OpenUri", + "name": "View Graph", + "targets": []map[string]interface{}{ + { + "os": "default", "uri": evalContext.ImagePublicUrl, }, }, }, From 3ce89cad71d58bb4cdd0cc63ba838706a512c313 Mon Sep 17 00:00:00 2001 From: bergquist Date: Thu, 6 Sep 2018 11:20:38 +0200 Subject: [PATCH 19/36] make default values for alerting configurable --- conf/defaults.ini | 6 ++++ conf/sample.ini | 6 ++++ docs/sources/installation/configuration.md | 8 +++++ pkg/api/frontendsettings.go | 30 ++++++++++--------- pkg/setting/setting.go | 8 +++-- public/app/core/config.ts | 2 ++ .../app/features/alerting/alert_tab_ctrl.ts | 4 +-- 7 files changed, 46 insertions(+), 18 deletions(-) diff --git a/conf/defaults.ini b/conf/defaults.ini index fff9f630690..cf924be3f9f 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -467,6 +467,12 @@ enabled = true # Makes it possible to turn off alert rule execution but alerting UI is visible execute_alerts = true +# Default setting for new alert rules. Defaults to categories error and timeouts as alerting. (alerting, keep_state) +error_or_timeout = alerting + +# Default setting for how Grafana handles nodata or null values in alerting. (alerting, no_data, keep_state, ok) +nodata_or_nullvalues = no_data + #################################### Explore ############################# [explore] # Enable the Explore section diff --git a/conf/sample.ini b/conf/sample.ini index 2b2ae497e36..67072814347 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -387,6 +387,12 @@ log_queries = # Makes it possible to turn off alert rule execution but alerting UI is visible ;execute_alerts = true +# Default setting for new alert rules. Defaults to categories error and timeouts as alerting. (alerting, keep_state) +;error_or_timeout = alerting + +# Default setting for how Grafana handles nodata or null values in alerting. (alerting, no_data, keep_state, ok) +;nodata_or_nullvalues = no_data + #################################### Explore ############################# [explore] # Enable the Explore section diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index 3394dfe16bc..1cd4d5d3893 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -1009,3 +1009,11 @@ Defaults to true. Set to false to disable alerting engine and hide Alerting from ### execute_alerts Makes it possible to turn off alert rule execution. + +### error_or_timeout + +Default setting for new alert rules. Defaults to categories error and timeouts as alerting. (alerting, keep_state) + +### nodata_or_nullvalues + +Default setting for how Grafana handles nodata or null values in alerting. (alerting, no_data, keep_state, ok) diff --git a/pkg/api/frontendsettings.go b/pkg/api/frontendsettings.go index da3c88566c1..a58be38781e 100644 --- a/pkg/api/frontendsettings.go +++ b/pkg/api/frontendsettings.go @@ -132,20 +132,22 @@ func getFrontendSettingsMap(c *m.ReqContext) (map[string]interface{}, error) { } jsonObj := map[string]interface{}{ - "defaultDatasource": defaultDatasource, - "datasources": datasources, - "panels": panels, - "appSubUrl": setting.AppSubUrl, - "allowOrgCreate": (setting.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin, - "authProxyEnabled": setting.AuthProxyEnabled, - "ldapEnabled": setting.LdapEnabled, - "alertingEnabled": setting.AlertingEnabled, - "exploreEnabled": setting.ExploreEnabled, - "googleAnalyticsId": setting.GoogleAnalyticsId, - "disableLoginForm": setting.DisableLoginForm, - "externalUserMngInfo": setting.ExternalUserMngInfo, - "externalUserMngLinkUrl": setting.ExternalUserMngLinkUrl, - "externalUserMngLinkName": setting.ExternalUserMngLinkName, + "defaultDatasource": defaultDatasource, + "datasources": datasources, + "panels": panels, + "appSubUrl": setting.AppSubUrl, + "allowOrgCreate": (setting.AllowUserOrgCreate && c.IsSignedIn) || c.IsGrafanaAdmin, + "authProxyEnabled": setting.AuthProxyEnabled, + "ldapEnabled": setting.LdapEnabled, + "alertingEnabled": setting.AlertingEnabled, + "alertingErrorOrTimeout": setting.AlertingErrorOrTimeout, + "alertingNoDataOrNullValues": setting.AlertingNoDataOrNullValues, + "exploreEnabled": setting.ExploreEnabled, + "googleAnalyticsId": setting.GoogleAnalyticsId, + "disableLoginForm": setting.DisableLoginForm, + "externalUserMngInfo": setting.ExternalUserMngInfo, + "externalUserMngLinkUrl": setting.ExternalUserMngLinkUrl, + "externalUserMngLinkName": setting.ExternalUserMngLinkName, "buildInfo": map[string]interface{}{ "version": setting.BuildVersion, "commit": setting.BuildCommit, diff --git a/pkg/setting/setting.go b/pkg/setting/setting.go index 789622ca0dd..d16fd4955d5 100644 --- a/pkg/setting/setting.go +++ b/pkg/setting/setting.go @@ -164,8 +164,10 @@ var ( Quota QuotaSettings // Alerting - AlertingEnabled bool - ExecuteAlerts bool + AlertingEnabled bool + ExecuteAlerts bool + AlertingErrorOrTimeout string + AlertingNoDataOrNullValues string // Explore UI ExploreEnabled bool @@ -672,6 +674,8 @@ func (cfg *Cfg) Load(args *CommandLineArgs) error { alerting := iniFile.Section("alerting") AlertingEnabled = alerting.Key("enabled").MustBool(true) ExecuteAlerts = alerting.Key("execute_alerts").MustBool(true) + AlertingErrorOrTimeout = alerting.Key("error_or_timeout").MustString("alerting") + AlertingNoDataOrNullValues = alerting.Key("nodata_or_nullvalues").MustString("no_data") explore := iniFile.Section("explore") ExploreEnabled = explore.Key("enabled").MustBool(false) diff --git a/public/app/core/config.ts b/public/app/core/config.ts index 3b8a087132c..bf5abe37d7f 100644 --- a/public/app/core/config.ts +++ b/public/app/core/config.ts @@ -22,6 +22,8 @@ export class Settings { disableLoginForm: boolean; defaultDatasource: string; alertingEnabled: boolean; + alertingErrorOrTimeout: string; + alertingNoDataOrNullValues: string; authProxyEnabled: boolean; exploreEnabled: boolean; ldapEnabled: boolean; diff --git a/public/app/features/alerting/alert_tab_ctrl.ts b/public/app/features/alerting/alert_tab_ctrl.ts index ef8e37483cc..53f7e57fd69 100644 --- a/public/app/features/alerting/alert_tab_ctrl.ts +++ b/public/app/features/alerting/alert_tab_ctrl.ts @@ -164,8 +164,8 @@ export class AlertTabCtrl { alert.conditions.push(this.buildDefaultCondition()); } - alert.noDataState = alert.noDataState || 'no_data'; - alert.executionErrorState = alert.executionErrorState || 'alerting'; + alert.noDataState = alert.noDataState || config.alertingNoDataOrNullValues; + alert.executionErrorState = alert.executionErrorState || config.alertingErrorOrTimeout; alert.frequency = alert.frequency || '60s'; alert.handler = alert.handler || 1; alert.notifications = alert.notifications || []; From 1e33a3780fbf4f29e4e9d4bc25264c387402682a Mon Sep 17 00:00:00 2001 From: bergquist Date: Thu, 6 Sep 2018 11:51:24 +0200 Subject: [PATCH 20/36] spelling errors --- conf/defaults.ini | 2 +- conf/sample.ini | 2 +- docs/sources/installation/configuration.md | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/conf/defaults.ini b/conf/defaults.ini index cf924be3f9f..85d0953c6af 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -467,7 +467,7 @@ enabled = true # Makes it possible to turn off alert rule execution but alerting UI is visible execute_alerts = true -# Default setting for new alert rules. Defaults to categories error and timeouts as alerting. (alerting, keep_state) +# Default setting for new alert rules. Defaults to categorize error and timeouts as alerting. (alerting, keep_state) error_or_timeout = alerting # Default setting for how Grafana handles nodata or null values in alerting. (alerting, no_data, keep_state, ok) diff --git a/conf/sample.ini b/conf/sample.ini index 67072814347..2ef254f79b9 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -387,7 +387,7 @@ log_queries = # Makes it possible to turn off alert rule execution but alerting UI is visible ;execute_alerts = true -# Default setting for new alert rules. Defaults to categories error and timeouts as alerting. (alerting, keep_state) +# Default setting for new alert rules. Defaults to categorize error and timeouts as alerting. (alerting, keep_state) ;error_or_timeout = alerting # Default setting for how Grafana handles nodata or null values in alerting. (alerting, no_data, keep_state, ok) diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index 1cd4d5d3893..6e3d36cc6d3 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -1011,9 +1011,11 @@ Defaults to true. Set to false to disable alerting engine and hide Alerting from Makes it possible to turn off alert rule execution. ### error_or_timeout +> Available in 5.3 and above -Default setting for new alert rules. Defaults to categories error and timeouts as alerting. (alerting, keep_state) +Default setting for new alert rules. Defaults to categorize error and timeouts as alerting. (alerting, keep_state) ### nodata_or_nullvalues +> Available in 5.3 and above Default setting for how Grafana handles nodata or null values in alerting. (alerting, no_data, keep_state, ok) From a25b5945064b46a46b6d6828a84f9b1962726d20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 6 Sep 2018 12:11:56 +0200 Subject: [PATCH 21/36] docs: updated --- docs/sources/auth/anonymous.md | 30 -- docs/sources/auth/auth-proxy.md | 105 ++---- docs/sources/auth/generic-oauth.md | 172 +++++++++ docs/sources/auth/github.md | 98 +++++ docs/sources/auth/gitlab.md | 115 ++++++ docs/sources/auth/google.md | 55 +++ docs/sources/auth/index.md | 2 + docs/sources/auth/ldap.md | 18 +- docs/sources/auth/oauth.md | 399 --------------------- docs/sources/auth/overview.md | 81 ++++- docs/sources/installation/configuration.md | 65 +--- docs/sources/tutorials/authproxy.md | 247 ------------- 12 files changed, 547 insertions(+), 840 deletions(-) delete mode 100644 docs/sources/auth/anonymous.md create mode 100644 docs/sources/auth/generic-oauth.md create mode 100644 docs/sources/auth/github.md create mode 100644 docs/sources/auth/gitlab.md create mode 100644 docs/sources/auth/google.md delete mode 100644 docs/sources/auth/oauth.md delete mode 100644 docs/sources/tutorials/authproxy.md diff --git a/docs/sources/auth/anonymous.md b/docs/sources/auth/anonymous.md deleted file mode 100644 index 39d1059e92e..00000000000 --- a/docs/sources/auth/anonymous.md +++ /dev/null @@ -1,30 +0,0 @@ -+++ -title = "Anonymous Authentication" -description = "Anonymous authentication " -keywords = ["grafana", "configuration", "documentation", "anonymous"] -type = "docs" -[menu.docs] -name = "Anonymous" -identifier = "anonymous-auth" -parent = "authentication" -weight = 4 -+++ - -# Anonymous Authentication - -## [auth.anonymous] - -### enabled - -Set to `true` to enable anonymous access. Defaults to `false` - -### org_name - -Set the organization name that should be used for anonymous users. If -you change your organization name in the Grafana UI this setting needs -to be updated to match the new name. - -### org_role - -Specify role for anonymous users. Defaults to `Viewer`, other valid -options are `Editor` and `Admin`. diff --git a/docs/sources/auth/auth-proxy.md b/docs/sources/auth/auth-proxy.md index 8ff61a8c40b..e066eed9190 100644 --- a/docs/sources/auth/auth-proxy.md +++ b/docs/sources/auth/auth-proxy.md @@ -3,6 +3,7 @@ title = "Auth Proxy" description = "Grafana Auth Proxy Guide " keywords = ["grafana", "configuration", "documentation", "proxy"] type = "docs" +aliases = ["/tutorials/authproxy/"] [menu.docs] name = "Auth Proxy" identifier = "auth-proxy" @@ -12,66 +13,31 @@ weight = 2 # Auth Proxy Authentication -## [auth.proxy] +You can configure Grafana to let a http reverse proxy handling authentication. Popular web servers have a very +extensive list of pluggable authentication modules, and any of them can be used with the AuthProxy feature. +Below we detail the configuration options for auth proxy. -This feature allows you to handle authentication in a http reverse proxy. - -### enabled - -Defaults to `false` - -### header_name - -Defaults to X-WEBAUTH-USER - -#### header_property - -Defaults to username but can also be set to email - -### auto_sign_up - -Set to `true` to enable auto sign up of users who do not exist in Grafana DB. Defaults to `true`. - -### whitelist - -Limit where auth proxy requests come from by configuring a list of IP addresses. This can be used to prevent users spoofing the X-WEBAUTH-USER header. - -### headers - -Used to define additional headers for `Name`, `Email` and/or `Login`, for example if the user's name is sent in the X-WEBAUTH-NAME header and their email address in the X-WEBAUTH-EMAIL header, set `headers = Name:X-WEBAUTH-NAME Email:X-WEBAUTH-EMAIL`. - -
- -# Grafana Authproxy - -AuthProxy allows you to offload the authentication of users to a web server (there are many reasons why you’d want to run a web server in front of a production version of Grafana, especially if it’s exposed to the Internet). - -Popular web servers have a very extensive list of pluggable authentication modules, and any of them can be used with the AuthProxy feature. - -The Grafana AuthProxy feature is very simple in design, but it is this simplicity that makes it so powerful. - -## Interacting with Grafana’s AuthProxy via curl - -The AuthProxy feature can be configured through the Grafana configuration file with the following options: - -```js +```bash [auth.proxy] +# Defaults to false, but set to true to enable this feature enabled = true +# HTTP Header name that will contain the username or email header_name = X-WEBAUTH-USER +# HTTP Header property, defaults to `username` but can also be `email` header_property = username +# Set to `true` to enable auto sign up of users who do not exist in Grafana DB. Defaults to `true`. auto_sign_up = true +# If combined with Grafana LDAP integration define sync interval ldap_sync_ttl = 60 +# Limit where auth proxy requests come from by configuring a list of IP addresses. +# This can be used to prevent users spoofing the X-WEBAUTH-USER header. whitelist = +# Optionally define more headers to sync other user attributes +# Example `headers = Name:X-WEBAUTH-NAME Email:X-WEBAUTH-EMAIL`` +headers = ``` -* **enabled**: this is to toggle the feature on or off -* **header_name**: this is the HTTP header name that passes the username or email address of the authenticated user to Grafana. Grafana will trust what ever username is contained in this header and automatically log the user in. -* **header_property**: this tells Grafana whether the value in the header_name is a username or an email address. (In Grafana you can log in using your account username or account email) -* **auto_sign_up**: If set to true, Grafana will automatically create user accounts in the Grafana DB if one does not exist. If set to false, users who do not exist in the GrafanaDB won’t be able to log in, even though their username and password are valid. -* **ldap_sync_ttl**: When both auth.proxy and auth.ldap are enabled, user's organisation and role are synchronised from ldap after the http proxy authentication. You can force ldap re-synchronisation after `ldap_sync_ttl` minutes. -* **whitelist**: Comma separated list of trusted authentication proxies IP. - -With a fresh install of Grafana, using the above configuration for the authProxy feature, we can send a simple API call to list all users. The only user that will be present is the default “Admin” user that is added the first time Grafana starts up. As you can see all we need to do to authenticate the request is to provide the “X-WEBAUTH-USER” header. +## Interacting with Grafana’s AuthProxy via curl ```bash curl -H "X-WEBAUTH-USER: admin" http://localhost:3000/api/users @@ -106,7 +72,8 @@ I’ll demonstrate how to use Apache for authenticating users. In this example w ### Apache BasicAuth -In this example we use Apache as a reverseProxy in front of Grafana. Apache handles the Authentication of users before forwarding requests to the Grafana backend service. +In this example we use Apache as a reverse proxy in front of Grafana. Apache handles the Authentication of users before forwarding requests to the Grafana backend service. + #### Apache configuration @@ -151,38 +118,7 @@ In this example we use Apache as a reverseProxy in front of Grafana. Apache hand * The last 3 lines are then just standard reverse proxy configuration to direct all authenticated requests to our Grafana server running on port 3000. -#### Grafana configuration - -```bash -############# Users ################ -[users] - # disable user signup / registration -allow_sign_up = false - -# Set to true to automatically assign new users to the default organization (id 1) -auto_assign_org = true - -# Default role new users will be automatically assigned (if auto_assign_org above is set to true) - auto_assign_org_role = Editor - - -############ Auth Proxy ######## -[auth.proxy] -enabled = true - -# the Header name that contains the authenticated user. -header_name = X-WEBAUTH-USER - -# does the user authenticate against the proxy using a 'username' or an 'email' -header_property = username - -# automatically add the user to the system if they don't already exist. -auto_sign_up = true -``` - -#### Full walk through using Docker. - -##### Grafana Container +## Full walk through using Docker. For this example, we use the official Grafana docker image available at [Docker Hub](https://hub.docker.com/r/grafana/grafana/) @@ -201,7 +137,8 @@ header_property = username auto_sign_up = true ``` -* Launch the Grafana container, using our custom grafana.ini to replace `/etc/grafana/grafana.ini`. We don't expose any ports for this container as it will only be connected to by our Apache container. +Launch the Grafana container, using our custom grafana.ini to replace `/etc/grafana/grafana.ini`. We don't expose +any ports for this container as it will only be connected to by our Apache container. ```bash docker run -i -v $(pwd)/grafana.ini:/etc/grafana/grafana.ini --name grafana grafana/grafana diff --git a/docs/sources/auth/generic-oauth.md b/docs/sources/auth/generic-oauth.md new file mode 100644 index 00000000000..70c1b937427 --- /dev/null +++ b/docs/sources/auth/generic-oauth.md @@ -0,0 +1,172 @@ ++++ +title = "OAuth authentication" +description = "Grafana OAuthentication Guide " +keywords = ["grafana", "configuration", "documentation", "oauth"] +type = "docs" +[menu.docs] +name = "Generic OAuth2" +identifier = "generic_oauth" +parent = "authentication" +weight = 3 ++++ + +# Generic OAuth Authentication + +You can configure many different oauth2 authentication services with Grafana using the generic oauth2 feature. Below you +can find examples using Okta, BitBucket, OneLogin and Azure. + +This callback URL must match the full HTTP address that you use in your browser to access Grafana, but with the prefix path of `/login/generic_oauth`. + +Example config: + +```bash +[auth.generic_oauth] +enabled = true +client_id = YOUR_APP_CLIENT_ID +client_secret = YOUR_APP_CLIENT_SECRET +scopes = +auth_url = +token_url = +api_url = +allowed_domains = mycompany.com mycompany.org +allow_sign_up = true +``` + +Set api_url to the resource that returns [OpenID UserInfo](https://connect2id.com/products/server/docs/api/userinfo) compatible information. + +## Set up OAuth2 with Okta + +First set up Grafana as an OpenId client "webapplication" in Okta. Then set the Base URIs to `https:///` and set the Login redirect URIs to `https:///login/generic_oauth`. + +Finally set up the generic oauth module like this: +```bash +[auth.generic_oauth] +name = Okta +enabled = true +scopes = openid profile email +client_id = +client_secret = +auth_url = https:///oauth2/v1/authorize +token_url = https:///oauth2/v1/token +api_url = https:///oauth2/v1/userinfo +``` + +## Set up OAuth2 with Bitbucket + +```bash +[auth.generic_oauth] +name = BitBucket +enabled = true +allow_sign_up = true +client_id = +client_secret = +scopes = account email +auth_url = https://bitbucket.org/site/oauth2/authorize +token_url = https://bitbucket.org/site/oauth2/access_token +api_url = https://api.bitbucket.org/2.0/user +team_ids = +allowed_organizations = +``` + +## Set up OAuth2 with OneLogin + +1. Create a new Custom Connector with the following settings: + - Name: Grafana + - Sign On Method: OpenID Connect + - Redirect URI: `https:///login/generic_oauth` + - Signing Algorithm: RS256 + - Login URL: `https:///login/generic_oauth` + + then: +2. Add an App to the Grafana Connector: + - Display Name: Grafana + + then: +3. Under the SSO tab on the Grafana App details page you'll find the Client ID and Client Secret. + + Your OneLogin Domain will match the url you use to access OneLogin. + + Configure Grafana as follows: + + ```bash + [auth.generic_oauth] + name = OneLogin + enabled = true + allow_sign_up = true + client_id = + client_secret = + scopes = openid email name + auth_url = https://.onelogin.com/oidc/auth + token_url = https://.onelogin.com/oidc/token + api_url = https://.onelogin.com/oidc/me + team_ids = + allowed_organizations = + ``` + +### Set up OAuth2 with Auth0 + +1. Create a new Client in Auth0 + - Name: Grafana + - Type: Regular Web Application + +2. Go to the Settings tab and set: + - Allowed Callback URLs: `https:///login/generic_oauth` + +3. Click Save Changes, then use the values at the top of the page to configure Grafana: + + ```bash + [auth.generic_oauth] + enabled = true + allow_sign_up = true + team_ids = + allowed_organizations = + name = Auth0 + client_id = + client_secret = + scopes = openid profile email + auth_url = https:///authorize + token_url = https:///oauth/token + api_url = https:///userinfo + ``` + +### Set up OAuth2 with Azure Active Directory + +1. Log in to portal.azure.com and click "Azure Active Directory" in the side menu, then click the "Properties" sub-menu item. + +2. Copy the "Directory ID", this is needed for setting URLs later + +3. Click "App Registrations" and add a new application registration: + - Name: Grafana + - Application type: Web app / API + - Sign-on URL: `https:///login/generic_oauth` + +4. Click the name of the new application to open the application details page. + +5. Note down the "Application ID", this will be the OAuth client id. + +6. Click "Settings", then click "Keys" and add a new entry under Passwords + - Key Description: Grafana OAuth + - Duration: Never Expires + +7. Click Save then copy the key value, this will be the OAuth client secret. + +8. Configure Grafana as follows: + + ```bash + [auth.generic_oauth] + name = Azure AD + enabled = true + allow_sign_up = true + client_id = + client_secret = + scopes = openid email name + auth_url = https://login.microsoftonline.com//oauth2/authorize + token_url = https://login.microsoftonline.com//oauth2/token + api_url = + team_ids = + allowed_organizations = + ``` + +
+ + diff --git a/docs/sources/auth/github.md b/docs/sources/auth/github.md new file mode 100644 index 00000000000..0e14798d45e --- /dev/null +++ b/docs/sources/auth/github.md @@ -0,0 +1,98 @@ ++++ +title = "Google OAuth2 Authentication" +description = "Grafana OAuthentication Guide " +keywords = ["grafana", "configuration", "documentation", "oauth"] +type = "docs" +[menu.docs] +name = "GitHub OAuth2" +identifier = "github_oauth2" +parent = "authentication" +weight = 4 ++++ + +# GitHub OAuth2 Authentication + +To enable the GitHub OAuth2 you must register your application with GitHub. GitHub will generate a client ID and secret key for you to use. + +## Configure GitHub OAuth application + +You need to create a GitHub OAuth application (you find this under the GitHub +settings page). When you create the application you will need to specify +a callback URL. Specify this as callback: + +```bash +http://:/login/github +``` + +This callback URL must match the full HTTP address that you use in your +browser to access Grafana, but with the prefix path of `/login/github`. +When the GitHub OAuth application is created you will get a Client ID and a +Client Secret. Specify these in the Grafana configuration file. For +example: + +## Enable GitHub in Grafana + +```bash +[auth.github] +enabled = true +allow_sign_up = true +client_id = YOUR_GITHUB_APP_CLIENT_ID +client_secret = YOUR_GITHUB_APP_CLIENT_SECRET +scopes = user:email,read:org +auth_url = https://github.com/login/oauth/authorize +token_url = https://github.com/login/oauth/access_token +api_url = https://api.github.com/user +team_ids = +allowed_organizations = +``` + +Restart the Grafana back-end. You should now see a GitHub login button +on the login page. You can now login or sign up with your GitHub +accounts. + +You may allow users to sign-up via GitHub authentication by setting the +`allow_sign_up` option to `true`. When this option is set to `true`, any +user successfully authenticating via GitHub authentication will be +automatically signed up. + +### team_ids + +Require an active team membership for at least one of the given teams on +GitHub. If the authenticated user isn't a member of at least one of the +teams they will not be able to register or authenticate with your +Grafana instance. For example: + +```bash +[auth.github] +enabled = true +client_id = YOUR_GITHUB_APP_CLIENT_ID +client_secret = YOUR_GITHUB_APP_CLIENT_SECRET +scopes = user:email,read:org +team_ids = 150,300 +auth_url = https://github.com/login/oauth/authorize +token_url = https://github.com/login/oauth/access_token +api_url = https://api.github.com/user +allow_sign_up = true +``` + +### allowed_organizations + +Require an active organization membership for at least one of the given +organizations on GitHub. If the authenticated user isn't a member of at least +one of the organizations they will not be able to register or authenticate with +your Grafana instance. For example + +```bash +[auth.github] +enabled = true +client_id = YOUR_GITHUB_APP_CLIENT_ID +client_secret = YOUR_GITHUB_APP_CLIENT_SECRET +scopes = user:email,read:org +auth_url = https://github.com/login/oauth/authorize +token_url = https://github.com/login/oauth/access_token +api_url = https://api.github.com/user +allow_sign_up = true +# space-delimited organization names +allowed_organizations = github google +``` + diff --git a/docs/sources/auth/gitlab.md b/docs/sources/auth/gitlab.md new file mode 100644 index 00000000000..6d587353aae --- /dev/null +++ b/docs/sources/auth/gitlab.md @@ -0,0 +1,115 @@ ++++ +title = "Google OAuth2 Authentication" +description = "Grafana OAuthentication Guide " +keywords = ["grafana", "configuration", "documentation", "oauth"] +type = "docs" +[menu.docs] +name = "GitLab OAuth2" +identifier = "gitlab_oauth" +parent = "authentication" +weight = 5 ++++ + +# GitLab OAuth2 Authentication + +To enable the GitLab OAuth2 you must register an application in GitLab. GitLab will generate a client ID and secret key for you to use. + +## Create GitLab OAuth keys + +You need to [create a GitLab OAuth application](https://docs.gitlab.com/ce/integration/oauth_provider.html). +Choose a descriptive *Name*, and use the following *Redirect URI*: + +``` +https://grafana.example.com/login/gitlab +``` + +where `https://grafana.example.com` is the URL you use to connect to Grafana. +Adjust it as needed if you don't use HTTPS or if you use a different port; for +instance, if you access Grafana at `http://203.0.113.31:3000`, you should use + +``` +http://203.0.113.31:3000/login/gitlab +``` + +Finally, select *api* as the *Scope* and submit the form. Note that if you're +not going to use GitLab groups for authorization (i.e. not setting +`allowed_groups`, see below), you can select *read_user* instead of *api* as +the *Scope*, thus giving a more restricted access to your GitLab API. + +You'll get an *Application Id* and a *Secret* in return; we'll call them +`GITLAB_APPLICATION_ID` and `GITLAB_SECRET` respectively for the rest of this +section. + +## Enable GitLab in Grafana + +Add the following to your Grafana configuration file to enable GitLab +authentication: + +```ini +[auth.gitlab] +enabled = false +allow_sign_up = false +client_id = GITLAB_APPLICATION_ID +client_secret = GITLAB_SECRET +scopes = api +auth_url = https://gitlab.com/oauth/authorize +token_url = https://gitlab.com/oauth/token +api_url = https://gitlab.com/api/v4 +allowed_groups = +``` + +Restart the Grafana backend for your changes to take effect. + +If you use your own instance of GitLab instead of `gitlab.com`, adjust +`auth_url`, `token_url` and `api_url` accordingly by replacing the `gitlab.com` +hostname with your own. + +With `allow_sign_up` set to `false`, only existing users will be able to login +using their GitLab account, but with `allow_sign_up` set to `true`, *any* user +who can authenticate on GitLab will be able to login on your Grafana instance; +if you use the public `gitlab.com`, it means anyone in the world would be able +to login on your Grafana instance. + +You can can however limit access to only members of a given group or list of +groups by setting the `allowed_groups` option. + +### allowed_groups + +To limit access to authenticated users that are members of one or more [GitLab +groups](https://docs.gitlab.com/ce/user/group/index.html), set `allowed_groups` +to a comma- or space-separated list of groups. For instance, if you want to +only give access to members of the `example` group, set + + +```ini +allowed_groups = example +``` + +If you want to also give access to members of the subgroup `bar`, which is in +the group `foo`, set + +```ini +allowed_groups = example, foo/bar +``` + +Note that in GitLab, the group or subgroup name doesn't always match its +display name, especially if the display name contains spaces or special +characters. Make sure you always use the group or subgroup name as it appears +in the URL of the group or subgroup. + +Here's a complete example with `alloed_sign_up` enabled, and access limited to +the `example` and `foo/bar` groups: + +```ini +[auth.gitlab] +enabled = false +allow_sign_up = true +client_id = GITLAB_APPLICATION_ID +client_secret = GITLAB_SECRET +scopes = api +auth_url = https://gitlab.com/oauth/authorize +token_url = https://gitlab.com/oauth/token +api_url = https://gitlab.com/api/v4 +allowed_groups = example, foo/bar +``` + diff --git a/docs/sources/auth/google.md b/docs/sources/auth/google.md new file mode 100644 index 00000000000..c11983829f1 --- /dev/null +++ b/docs/sources/auth/google.md @@ -0,0 +1,55 @@ ++++ +title = "Google OAuth2 Authentication" +description = "Grafana OAuthentication Guide " +keywords = ["grafana", "configuration", "documentation", "oauth"] +type = "docs" +[menu.docs] +name = "Google OAuth2" +identifier = "ggogle_oauth2" +parent = "authentication" +weight = 3 ++++ + +# Google OAuth2 Authentication + +To enable the Google OAuth2 you must register your application with Google. Google will generate a client ID and secret key for you to use. + +## Create Google OAuth keys + +First, you need to create a Google OAuth Client: + +1. Go to https://console.developers.google.com/apis/credentials +2. Click the 'Create Credentials' button, then click 'OAuth Client ID' in the menu that drops down +3. Enter the following: + - Application Type: Web Application + - Name: Grafana + - Authorized Javascript Origins: https://grafana.mycompany.com + - Authorized Redirect URLs: https://grafana.mycompany.com/login/google + - Replace https://grafana.mycompany.com with the URL of your Grafana instance. +4. Click Create +5. Copy the Client ID and Client Secret from the 'OAuth Client' modal + +## Enable Google OAuth in Grafana + +Specify the Client ID and Secret in the [Grafana configuration file]({{< relref "installation/configuration.md/#config-file-locations" >}}). For example: + +```bash +[auth.google] +enabled = true +client_id = CLIENT_ID +client_secret = CLIENT_SECRET +scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email +auth_url = https://accounts.google.com/o/oauth2/auth +token_url = https://accounts.google.com/o/oauth2/token +allowed_domains = mycompany.com mycompany.org +allow_sign_up = true +``` + +Restart the Grafana back-end. You should now see a Google login button +on the login page. You can now login or sign up with your Google +accounts. The `allowed_domains` option is optional, and domains were separated by space. + +You may allow users to sign-up via Google authentication by setting the +`allow_sign_up` option to `true`. When this option is set to `true`, any +user successfully authenticating via Google authentication will be +automatically signed up. diff --git a/docs/sources/auth/index.md b/docs/sources/auth/index.md index 455c361369a..7fdcc082319 100644 --- a/docs/sources/auth/index.md +++ b/docs/sources/auth/index.md @@ -8,3 +8,5 @@ identifier = "authentication" parent = "admin" weight = 3 +++ + + diff --git a/docs/sources/auth/ldap.md b/docs/sources/auth/ldap.md index f9208213aef..6e0cf5606b4 100644 --- a/docs/sources/auth/ldap.md +++ b/docs/sources/auth/ldap.md @@ -4,13 +4,20 @@ description = "Grafana LDAP Authentication Guide " keywords = ["grafana", "configuration", "documentation", "ldap"] type = "docs" [menu.docs] -name = "LDAP Auth" +name = "LDAP" identifier = "ldap" parent = "authentication" weight = 2 +++ +# LDAP + +The LDAP integration in Grafana allows your Grafana users to login with their LDAP credentials. You can also specify mappings between LDAP +group memberships and Grafana Organization user roles. Below we detail grafana.ini config file +settings and ldap.toml config file options. + ## [auth.ldap] + ### enabled Set to `true` to enable LDAP integration (default: `false`) @@ -22,16 +29,9 @@ Path to the LDAP specific configuration file (default: `/etc/grafana/ldap.toml`) Allow sign up should almost always be true (default) to allow new Grafana users to be created (if ldap authentication is ok). If set to false only pre-existing Grafana users will be able to login (if ldap authentication is ok). -> For details on LDAP Configuration, go to the [LDAP Integration]({{< relref "ldap.md" >}}) page. -
-# LDAP Authentication - -Grafana (2.1 and newer) ships with a strong LDAP integration feature. The LDAP integration in Grafana allows your -Grafana users to login with their LDAP credentials. You can also specify mappings between LDAP -group memberships and Grafana Organization user roles. - +Grafana (2.1 and newer) ships with a strong LDAP integration feature. ## Configuration You turn on LDAP in the [main config file]({{< relref "configuration.md#auth-ldap" >}}) as well as specify the path to the LDAP specific configuration file (default: `/etc/grafana/ldap.toml`). diff --git a/docs/sources/auth/oauth.md b/docs/sources/auth/oauth.md deleted file mode 100644 index 0fe60196ffa..00000000000 --- a/docs/sources/auth/oauth.md +++ /dev/null @@ -1,399 +0,0 @@ -+++ -title = "OAuth authentication" -description = "Grafana OAuthentication Guide " -keywords = ["grafana", "configuration", "documentation", "oauth"] -type = "docs" -[menu.docs] -name = "OAuth" -identifier = "oauth" -parent = "authentication" -weight = 2 -+++ - -# OAuth Authentication - -## [auth.generic_oauth] - -This option could be used if have your own oauth service. - -This callback URL must match the full HTTP address that you use in your -browser to access Grafana, but with the prefix path of `/login/generic_oauth`. - -```bash -[auth.generic_oauth] -enabled = true -client_id = YOUR_APP_CLIENT_ID -client_secret = YOUR_APP_CLIENT_SECRET -scopes = -auth_url = -token_url = -api_url = -allowed_domains = mycompany.com mycompany.org -allow_sign_up = true -``` - -Set api_url to the resource that returns [OpenID UserInfo](https://connect2id.com/products/server/docs/api/userinfo) compatible information. - -### Set up oauth2 with Okta - -First set up Grafana as an OpenId client "webapplication" in Okta. Then set the Base URIs to `https:///` and set the Login redirect URIs to `https:///login/generic_oauth`. - -Finally set up the generic oauth module like this: -```bash -[auth.generic_oauth] -name = Okta -enabled = true -scopes = openid profile email -client_id = -client_secret = -auth_url = https:///oauth2/v1/authorize -token_url = https:///oauth2/v1/token -api_url = https:///oauth2/v1/userinfo -``` - -### Set up oauth2 with Bitbucket - -```bash -[auth.generic_oauth] -name = BitBucket -enabled = true -allow_sign_up = true -client_id = -client_secret = -scopes = account email -auth_url = https://bitbucket.org/site/oauth2/authorize -token_url = https://bitbucket.org/site/oauth2/access_token -api_url = https://api.bitbucket.org/2.0/user -team_ids = -allowed_organizations = -``` - -### Set up oauth2 with OneLogin - -1. Create a new Custom Connector with the following settings: - - Name: Grafana - - Sign On Method: OpenID Connect - - Redirect URI: `https:///login/generic_oauth` - - Signing Algorithm: RS256 - - Login URL: `https:///login/generic_oauth` - - then: -2. Add an App to the Grafana Connector: - - Display Name: Grafana - - then: -3. Under the SSO tab on the Grafana App details page you'll find the Client ID and Client Secret. - - Your OneLogin Domain will match the url you use to access OneLogin. - - Configure Grafana as follows: - - ```bash - [auth.generic_oauth] - name = OneLogin - enabled = true - allow_sign_up = true - client_id = - client_secret = - scopes = openid email name - auth_url = https://.onelogin.com/oidc/auth - token_url = https://.onelogin.com/oidc/token - api_url = https://.onelogin.com/oidc/me - team_ids = - allowed_organizations = - ``` - -### Set up oauth2 with Auth0 - -1. Create a new Client in Auth0 - - Name: Grafana - - Type: Regular Web Application - -2. Go to the Settings tab and set: - - Allowed Callback URLs: `https:///login/generic_oauth` - -3. Click Save Changes, then use the values at the top of the page to configure Grafana: - - ```bash - [auth.generic_oauth] - enabled = true - allow_sign_up = true - team_ids = - allowed_organizations = - name = Auth0 - client_id = - client_secret = - scopes = openid profile email - auth_url = https:///authorize - token_url = https:///oauth/token - api_url = https:///userinfo - ``` - -### Set up oauth2 with Azure Active Directory - -1. Log in to portal.azure.com and click "Azure Active Directory" in the side menu, then click the "Properties" sub-menu item. - -2. Copy the "Directory ID", this is needed for setting URLs later - -3. Click "App Registrations" and add a new application registration: - - Name: Grafana - - Application type: Web app / API - - Sign-on URL: `https:///login/generic_oauth` - -4. Click the name of the new application to open the application details page. - -5. Note down the "Application ID", this will be the OAuth client id. - -6. Click "Settings", then click "Keys" and add a new entry under Passwords - - Key Description: Grafana OAuth - - Duration: Never Expires - -7. Click Save then copy the key value, this will be the OAuth client secret. - -8. Configure Grafana as follows: - - ```bash - [auth.generic_oauth] - name = Azure AD - enabled = true - allow_sign_up = true - client_id = - client_secret = - scopes = openid email name - auth_url = https://login.microsoftonline.com//oauth2/authorize - token_url = https://login.microsoftonline.com//oauth2/token - api_url = - team_ids = - allowed_organizations = - ``` - -
- -## [auth.github] - -You need to create a GitHub OAuth application (you find this under the GitHub -settings page). When you create the application you will need to specify -a callback URL. Specify this as callback: - -```bash -http://:/login/github -``` - -This callback URL must match the full HTTP address that you use in your -browser to access Grafana, but with the prefix path of `/login/github`. -When the GitHub OAuth application is created you will get a Client ID and a -Client Secret. Specify these in the Grafana configuration file. For -example: - -```bash -[auth.github] -enabled = true -allow_sign_up = true -client_id = YOUR_GITHUB_APP_CLIENT_ID -client_secret = YOUR_GITHUB_APP_CLIENT_SECRET -scopes = user:email,read:org -auth_url = https://github.com/login/oauth/authorize -token_url = https://github.com/login/oauth/access_token -api_url = https://api.github.com/user -team_ids = -allowed_organizations = -``` - -Restart the Grafana back-end. You should now see a GitHub login button -on the login page. You can now login or sign up with your GitHub -accounts. - -You may allow users to sign-up via GitHub authentication by setting the -`allow_sign_up` option to `true`. When this option is set to `true`, any -user successfully authenticating via GitHub authentication will be -automatically signed up. - -### team_ids - -Require an active team membership for at least one of the given teams on -GitHub. If the authenticated user isn't a member of at least one of the -teams they will not be able to register or authenticate with your -Grafana instance. For example: - -```bash -[auth.github] -enabled = true -client_id = YOUR_GITHUB_APP_CLIENT_ID -client_secret = YOUR_GITHUB_APP_CLIENT_SECRET -scopes = user:email,read:org -team_ids = 150,300 -auth_url = https://github.com/login/oauth/authorize -token_url = https://github.com/login/oauth/access_token -api_url = https://api.github.com/user -allow_sign_up = true -``` - -### allowed_organizations - -Require an active organization membership for at least one of the given -organizations on GitHub. If the authenticated user isn't a member of at least -one of the organizations they will not be able to register or authenticate with -your Grafana instance. For example - -```bash -[auth.github] -enabled = true -client_id = YOUR_GITHUB_APP_CLIENT_ID -client_secret = YOUR_GITHUB_APP_CLIENT_SECRET -scopes = user:email,read:org -auth_url = https://github.com/login/oauth/authorize -token_url = https://github.com/login/oauth/access_token -api_url = https://api.github.com/user -allow_sign_up = true -# space-delimited organization names -allowed_organizations = github google -``` - -
- -## [auth.gitlab] - -> Only available in Grafana v5.3+. - -You need to [create a GitLab OAuth -application](https://docs.gitlab.com/ce/integration/oauth_provider.html). -Choose a descriptive *Name*, and use the following *Redirect URI*: - -``` -https://grafana.example.com/login/gitlab -``` - -where `https://grafana.example.com` is the URL you use to connect to Grafana. -Adjust it as needed if you don't use HTTPS or if you use a different port; for -instance, if you access Grafana at `http://203.0.113.31:3000`, you should use - -``` -http://203.0.113.31:3000/login/gitlab -``` - -Finally, select *api* as the *Scope* and submit the form. Note that if you're -not going to use GitLab groups for authorization (i.e. not setting -`allowed_groups`, see below), you can select *read_user* instead of *api* as -the *Scope*, thus giving a more restricted access to your GitLab API. - -You'll get an *Application Id* and a *Secret* in return; we'll call them -`GITLAB_APPLICATION_ID` and `GITLAB_SECRET` respectively for the rest of this -section. - -Add the following to your Grafana configuration file to enable GitLab -authentication: - -```ini -[auth.gitlab] -enabled = false -allow_sign_up = false -client_id = GITLAB_APPLICATION_ID -client_secret = GITLAB_SECRET -scopes = api -auth_url = https://gitlab.com/oauth/authorize -token_url = https://gitlab.com/oauth/token -api_url = https://gitlab.com/api/v4 -allowed_groups = -``` - -Restart the Grafana backend for your changes to take effect. - -If you use your own instance of GitLab instead of `gitlab.com`, adjust -`auth_url`, `token_url` and `api_url` accordingly by replacing the `gitlab.com` -hostname with your own. - -With `allow_sign_up` set to `false`, only existing users will be able to login -using their GitLab account, but with `allow_sign_up` set to `true`, *any* user -who can authenticate on GitLab will be able to login on your Grafana instance; -if you use the public `gitlab.com`, it means anyone in the world would be able -to login on your Grafana instance. - -You can can however limit access to only members of a given group or list of -groups by setting the `allowed_groups` option. - -### allowed_groups - -To limit access to authenticated users that are members of one or more [GitLab -groups](https://docs.gitlab.com/ce/user/group/index.html), set `allowed_groups` -to a comma- or space-separated list of groups. For instance, if you want to -only give access to members of the `example` group, set - - -```ini -allowed_groups = example -``` - -If you want to also give access to members of the subgroup `bar`, which is in -the group `foo`, set - -```ini -allowed_groups = example, foo/bar -``` - -Note that in GitLab, the group or subgroup name doesn't always match its -display name, especially if the display name contains spaces or special -characters. Make sure you always use the group or subgroup name as it appears -in the URL of the group or subgroup. - -Here's a complete example with `alloed_sign_up` enabled, and access limited to -the `example` and `foo/bar` groups: - -```ini -[auth.gitlab] -enabled = false -allow_sign_up = true -client_id = GITLAB_APPLICATION_ID -client_secret = GITLAB_SECRET -scopes = api -auth_url = https://gitlab.com/oauth/authorize -token_url = https://gitlab.com/oauth/token -api_url = https://gitlab.com/api/v4 -allowed_groups = example, foo/bar -``` - -
- -## [auth.google] - -First, you need to create a Google OAuth Client: - -1. Go to https://console.developers.google.com/apis/credentials - -2. Click the 'Create Credentials' button, then click 'OAuth Client ID' in the -menu that drops down - -3. Enter the following: - - - Application Type: Web Application - - Name: Grafana - - Authorized Javascript Origins: https://grafana.mycompany.com - - Authorized Redirect URLs: https://grafana.mycompany.com/login/google - - Replace https://grafana.mycompany.com with the URL of your Grafana instance. - -4. Click Create - -5. Copy the Client ID and Client Secret from the 'OAuth Client' modal - -Specify the Client ID and Secret in the Grafana configuration file. For example: - -```bash -[auth.google] -enabled = true -client_id = CLIENT_ID -client_secret = CLIENT_SECRET -scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email -auth_url = https://accounts.google.com/o/oauth2/auth -token_url = https://accounts.google.com/o/oauth2/token -allowed_domains = mycompany.com mycompany.org -allow_sign_up = true -``` - -Restart the Grafana back-end. You should now see a Google login button -on the login page. You can now login or sign up with your Google -accounts. The `allowed_domains` option is optional, and domains were separated by space. - -You may allow users to sign-up via Google authentication by setting the -`allow_sign_up` option to `true`. When this option is set to `true`, any -user successfully authenticating via Google authentication will be -automatically signed up. \ No newline at end of file diff --git a/docs/sources/auth/overview.md b/docs/sources/auth/overview.md index 03a7a0e9fe4..fc01a713ca8 100644 --- a/docs/sources/auth/overview.md +++ b/docs/sources/auth/overview.md @@ -9,30 +9,79 @@ parent = "authentication" weight = 1 +++ -# Authentication +# User Authentication Overview -Grafana provides many ways to authenticate users. By default it will use local users & passwords stored in the Grafana -database. +Grafana provides many ways to authenticate users. Some authentication integrations also enable syncing user +permissions and org memberships. -## Settings +## OAuth2 Integrations -Via the [server ini config file]({{< relref "installation/debian.md" >}}) you can setup many different authentication methods. Auth settings -are documented below. +- [Google OAuth]({{< relref "auth/google.md" >}}) +- [GitHub OAuth]({{< relref "auth/github.md" >}}) +- [Gitlab OAuth]({{< relref "auth/gitlab.md" >}}) +- [Generic OAuth]({{< relref "auth/oauth.md" >}}) (Okta2, BitBucket, Azure, OneLogin, Auth0) -### [auth] +## LDAP integrations -#### disable_login_form +- [LDAP Authentication]({{< relref "auth/ldap.md" >}}) (OpenLDAP, ActiveDirectory, etc) -Set to true to disable (hide) the login form, useful if you use OAuth, defaults to false. +## Auth proxy -#### disable_signout_menu +- [Auth Proxy]({{< relref "auth/auth-proxy.md" >}}) If you want to handle authentication outside Grafana using a reverse + proxy. -Set to true to disable the signout link in the side menu. useful if you use auth.proxy, defaults to false. +## Grafana Auth -
+Grafana of course has a built in user authentication system with password authenticaten enabled by default. You can +disable authentication by enabling anonymous access. You can also hide login form and only allow login through an auth +provider (listed above). There is also options for allowing self sign up. -### [auth.basic] -#### enabled -When enabled is `true` (default) the http api will accept basic authentication. +### Anonymous authenticaten + +You can make Grafana accessible without any login required by enabling anonymous access in the configuration file. + +Example: + +```bash +[auth.anonymous] +enabled = true + +# Organization name that should be used for unauthenticated users +org_name = Main Org. + +# Role for unauthenticated users, other valid values are `Editor` and `Admin` +org_role = Viewer +``` + +If you change your organization name in the Grafana UI this setting needs to be updated to match the new name. + +### Basic authentication + +Basic auth is enabled by default and works with the built in Grafana user password authentication system and LDAP +authenticaten integration. + +To disable basic auth: + +```bash +[auth.basic] +enabled = false +``` + +### Disable login form + +You can hide the Grafana login form using the below configuration settings. + +```bash +[auth] +disable_login_form ⁼ true +``` + +### Hide sign-out menu + +Set to the option detailed below to true to hide sign-out menu link. Useful if you use an auth proxy. + +```bash +[auth] +disable_signout_menu = true +``` -
diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index f61274e36fa..5aee2c5f594 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -321,62 +321,17 @@ Defaults to `false`. ## [auth] -### disable_login_form +Grafana provides many ways to authenticate users. The docs for authentication has been split in to many differnet pages +below. -Set to true to disable (hide) the login form, useful if you use OAuth, defaults to false. - -### disable_signout_menu - -Set to true to disable the signout link in the side menu. useful if you use auth.proxy, defaults to false. - -
- -## [auth.anonymous] - -[Read guide here.](/administration/authentication/anonymous-auth) - -
- -## [auth.github] - -[Read guide here.](/administration/authentication/oauth/#auth-github) - -
- -## [auth.gitlab] - -[Read guide here.](/administration/authentication/oauth/#auth-gitlab) - -
- -## [auth.google] - -[Read guide here.](/administration/authentication/oauth/#auth-google) - -
- -## [auth.generic_oauth] - -[Read guide here.](/administration/authentication/oauth/#auth-generic-oauth) -
- -## [auth.basic] -### enabled -When enabled is `true` (default) the http api will accept basic authentication. - -
- -## [auth.ldap] - -[Read guide here.](/administration/authentication/ldap/) - -
- -## [auth.proxy] - -[Read guide here.](/administration/authentication/auth-proxy/) - -
+- [Anonymous access]({{< relref "auth/overview.md" >}}) (auth.anonymous) +- [Google OAuth]({{< relref "auth/google.md" >}}) (auth.google) +- [GitHub OAuth]({{< relref "auth/github.md" >}}) (auth.github) +- [Gitlab OAuth]({{< relref "auth/gitlab.md" >}}) (auth.gitlab) +- [Generic OAuth]({{< relref "auth/generic-oauth.md" >}}) (auth.generic_oauth, okta2, auth0, bitbucket, azure) +- [Basic Authentication]({{< relref "auth/overview.md" >}}) (auth.basic) +- [LDAP Authentication]({{< relref "auth/ldap.md" >}}) (auth.ldap) +- [Auth Proxy]({{< relref "auth/auth-proxy.md" >}}) (auth.proxy) ## [session] diff --git a/docs/sources/tutorials/authproxy.md b/docs/sources/tutorials/authproxy.md deleted file mode 100644 index 6f13de85c18..00000000000 --- a/docs/sources/tutorials/authproxy.md +++ /dev/null @@ -1,247 +0,0 @@ -+++ -title = "Grafana Authproxy" -type = "docs" -keywords = ["grafana", "tutorials", "authproxy"] -[menu.docs] -parent = "tutorials" -weight = 10 -+++ - -# Grafana Authproxy - -AuthProxy allows you to offload the authentication of users to a web server (there are many reasons why you’d want to run a web server in front of a production version of Grafana, especially if it’s exposed to the Internet). - -Popular web servers have a very extensive list of pluggable authentication modules, and any of them can be used with the AuthProxy feature. - -The Grafana AuthProxy feature is very simple in design, but it is this simplicity that makes it so powerful. - -## Interacting with Grafana’s AuthProxy via curl - -The AuthProxy feature can be configured through the Grafana configuration file with the following options: - -```js -[auth.proxy] -enabled = true -header_name = X-WEBAUTH-USER -header_property = username -auto_sign_up = true -ldap_sync_ttl = 60 -whitelist = -``` - -* **enabled**: this is to toggle the feature on or off -* **header_name**: this is the HTTP header name that passes the username or email address of the authenticated user to Grafana. Grafana will trust what ever username is contained in this header and automatically log the user in. -* **header_property**: this tells Grafana whether the value in the header_name is a username or an email address. (In Grafana you can log in using your account username or account email) -* **auto_sign_up**: If set to true, Grafana will automatically create user accounts in the Grafana DB if one does not exist. If set to false, users who do not exist in the GrafanaDB won’t be able to log in, even though their username and password are valid. -* **ldap_sync_ttl**: When both auth.proxy and auth.ldap are enabled, user's organisation and role are synchronised from ldap after the http proxy authentication. You can force ldap re-synchronisation after `ldap_sync_ttl` minutes. -* **whitelist**: Comma separated list of trusted authentication proxies IP. - -With a fresh install of Grafana, using the above configuration for the authProxy feature, we can send a simple API call to list all users. The only user that will be present is the default “Admin” user that is added the first time Grafana starts up. As you can see all we need to do to authenticate the request is to provide the “X-WEBAUTH-USER” header. - -```bash -curl -H "X-WEBAUTH-USER: admin" http://localhost:3000/api/users -[ - { - "id":1, - "name":"", - "login":"admin", - "email":"admin@localhost", - "isAdmin":true - } -] -``` - -We can then send a second request to the `/api/user` method which will return the details of the logged in user. We will use this request to show how Grafana automatically adds the new user we specify to the system. Here we create a new user called “anthony”. - -```bash -curl -H "X-WEBAUTH-USER: anthony" http://localhost:3000/api/user -{ - "email":"anthony", - "name":"", - "login":"anthony", - "theme":"", - "orgId":1, - "isGrafanaAdmin":false -} -``` - -## Making Apache’s auth work together with Grafana’s AuthProxy - -I’ll demonstrate how to use Apache for authenticating users. In this example we use BasicAuth with Apache’s text file based authentication handler, i.e. htpasswd files. However, any available Apache authentication capabilities could be used. - -### Apache BasicAuth - -In this example we use Apache as a reverseProxy in front of Grafana. Apache handles the Authentication of users before forwarding requests to the Grafana backend service. - -#### Apache configuration - -```bash - - ServerAdmin webmaster@authproxy - ServerName authproxy - ErrorLog "logs/authproxy-error_log" - CustomLog "logs/authproxy-access_log" common - - - AuthType Basic - AuthName GrafanaAuthProxy - AuthBasicProvider file - AuthUserFile /etc/apache2/grafana_htpasswd - Require valid-user - - RewriteEngine On - RewriteRule .* - [E=PROXY_USER:%{LA-U:REMOTE_USER},NS] - RequestHeader set X-WEBAUTH-USER "%{PROXY_USER}e" - - - RequestHeader unset Authorization - - ProxyRequests Off - ProxyPass / http://localhost:3000/ - ProxyPassReverse / http://localhost:3000/ - -``` - -* The first 4 lines of the virtualhost configuration are standard, so we won’t go into detail on what they do. - -* We use a **\** configuration block for applying our authentication rules to every proxied request. These rules include requiring basic authentication where user:password credentials are stored in the **/etc/apache2/grafana_htpasswd** file. This file can be created with the `htpasswd` command. - - * The next part of the configuration is the tricky part. We use Apache’s rewrite engine to create our **X-WEBAUTH-USER header**, populated with the authenticated user. - - * **RewriteRule .* - [E=PROXY_USER:%{LA-U:REMOTE_USER}, NS]**: This line is a little bit of magic. What it does, is for every request use the rewriteEngines look-ahead (LA-U) feature to determine what the REMOTE_USER variable would be set to after processing the request. Then assign the result to the variable PROXY_USER. This is necessary as the REMOTE_USER variable is not available to the RequestHeader function. - - * **RequestHeader set X-WEBAUTH-USER “%{PROXY_USER}e”**: With the authenticated username now stored in the PROXY_USER variable, we create a new HTTP request header that will be sent to our backend Grafana containing the username. - -* The **RequestHeader unset Authorization** removes the Authorization header from the HTTP request before it is forwarded to Grafana. This ensures that Grafana does not try to authenticate the user using these credentials (BasicAuth is a supported authentication handler in Grafana). - -* The last 3 lines are then just standard reverse proxy configuration to direct all authenticated requests to our Grafana server running on port 3000. - -#### Grafana configuration - -```bash -############# Users ################ -[users] - # disable user signup / registration -allow_sign_up = false - -# Set to true to automatically assign new users to the default organization (id 1) -auto_assign_org = true - -# Default role new users will be automatically assigned (if auto_assign_org above is set to true) - auto_assign_org_role = Editor - - -############ Auth Proxy ######## -[auth.proxy] -enabled = true - -# the Header name that contains the authenticated user. -header_name = X-WEBAUTH-USER - -# does the user authenticate against the proxy using a 'username' or an 'email' -header_property = username - -# automatically add the user to the system if they don't already exist. -auto_sign_up = true -``` - -#### Full walk through using Docker. - -##### Grafana Container - -For this example, we use the official Grafana docker image available at [Docker Hub](https://hub.docker.com/r/grafana/grafana/) - -* Create a file `grafana.ini` with the following contents - -```bash -[users] -allow_sign_up = false -auto_assign_org = true -auto_assign_org_role = Editor - -[auth.proxy] -enabled = true -header_name = X-WEBAUTH-USER -header_property = username -auto_sign_up = true -``` - -* Launch the Grafana container, using our custom grafana.ini to replace `/etc/grafana/grafana.ini`. We don't expose any ports for this container as it will only be connected to by our Apache container. - -```bash -docker run -i -v $(pwd)/grafana.ini:/etc/grafana/grafana.ini --name grafana grafana/grafana -``` - -### Apache Container - -For this example we use the official Apache docker image available at [Docker Hub](https://hub.docker.com/_/httpd/) - -* Create a file `httpd.conf` with the following contents - -```bash -ServerRoot "/usr/local/apache2" -Listen 80 -LoadModule authn_file_module modules/mod_authn_file.so -LoadModule authn_core_module modules/mod_authn_core.so -LoadModule authz_host_module modules/mod_authz_host.so -LoadModule authz_user_module modules/mod_authz_user.so -LoadModule authz_core_module modules/mod_authz_core.so -LoadModule auth_basic_module modules/mod_auth_basic.so -LoadModule log_config_module modules/mod_log_config.so -LoadModule env_module modules/mod_env.so -LoadModule headers_module modules/mod_headers.so -LoadModule unixd_module modules/mod_unixd.so -LoadModule rewrite_module modules/mod_rewrite.so -LoadModule proxy_module modules/mod_proxy.so -LoadModule proxy_http_module modules/mod_proxy_http.so - -User daemon -Group daemon - -ServerAdmin you@example.com - - AllowOverride none - Require all denied - -DocumentRoot "/usr/local/apache2/htdocs" -ErrorLog /proc/self/fd/2 -LogLevel error - - LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined - LogFormat "%h %l %u %t \"%r\" %>s %b" common - - LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio - - CustomLog /proc/self/fd/1 common - - - AuthType Basic - AuthName GrafanaAuthProxy - AuthBasicProvider file - AuthUserFile /tmp/htpasswd - Require valid-user - RewriteEngine On - RewriteRule .* - [E=PROXY_USER:%{LA-U:REMOTE_USER},NS] - RequestHeader set X-WEBAUTH-USER "%{PROXY_USER}e" - -RequestHeader unset Authorization -ProxyRequests Off -ProxyPass / http://grafana:3000/ -ProxyPassReverse / http://grafana:3000/ -``` - -* Create a htpasswd file. We create a new user **anthony** with the password **password** - - ```bash - htpasswd -bc htpasswd anthony password - ``` - -* Launch the httpd container using our custom httpd.conf and our htpasswd file. The container will listen on port 80, and we create a link to the **grafana** container so that this container can resolve the hostname **grafana** to the grafana container’s ip address. - - ```bash - docker run -i -p 80:80 --link grafana:grafana -v $(pwd)/httpd.conf:/usr/local/apache2/conf/httpd.conf -v $(pwd)/htpasswd:/tmp/htpasswd httpd:2.4 - ``` - -### Use grafana. - -With our Grafana and Apache containers running, you can now connect to http://localhost/ and log in using the username/password we created in the htpasswd file. From d6f9ebab63478e347997f6d51559c7a17521566e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 6 Sep 2018 13:15:36 +0200 Subject: [PATCH 22/36] docs: Updated auth docs --- docs/sources/auth/github.md | 2 +- docs/sources/auth/gitlab.md | 4 +-- docs/sources/auth/google.md | 2 +- docs/sources/auth/ldap.md | 36 ++++++++++------------ docs/sources/auth/overview.md | 2 +- docs/sources/installation/configuration.md | 2 +- 6 files changed, 22 insertions(+), 26 deletions(-) diff --git a/docs/sources/auth/github.md b/docs/sources/auth/github.md index 0e14798d45e..263b3cc5d4d 100644 --- a/docs/sources/auth/github.md +++ b/docs/sources/auth/github.md @@ -4,7 +4,7 @@ description = "Grafana OAuthentication Guide " keywords = ["grafana", "configuration", "documentation", "oauth"] type = "docs" [menu.docs] -name = "GitHub OAuth2" +name = "GitHub" identifier = "github_oauth2" parent = "authentication" weight = 4 diff --git a/docs/sources/auth/gitlab.md b/docs/sources/auth/gitlab.md index 6d587353aae..32910167f16 100644 --- a/docs/sources/auth/gitlab.md +++ b/docs/sources/auth/gitlab.md @@ -4,7 +4,7 @@ description = "Grafana OAuthentication Guide " keywords = ["grafana", "configuration", "documentation", "oauth"] type = "docs" [menu.docs] -name = "GitLab OAuth2" +name = "GitLab" identifier = "gitlab_oauth" parent = "authentication" weight = 5 @@ -45,7 +45,7 @@ section. Add the following to your Grafana configuration file to enable GitLab authentication: -```ini +```bash [auth.gitlab] enabled = false allow_sign_up = false diff --git a/docs/sources/auth/google.md b/docs/sources/auth/google.md index c11983829f1..2a79037c430 100644 --- a/docs/sources/auth/google.md +++ b/docs/sources/auth/google.md @@ -4,7 +4,7 @@ description = "Grafana OAuthentication Guide " keywords = ["grafana", "configuration", "documentation", "oauth"] type = "docs" [menu.docs] -name = "Google OAuth2" +name = "Google" identifier = "ggogle_oauth2" parent = "authentication" weight = 3 diff --git a/docs/sources/auth/ldap.md b/docs/sources/auth/ldap.md index 6e0cf5606b4..f63a44e1750 100644 --- a/docs/sources/auth/ldap.md +++ b/docs/sources/auth/ldap.md @@ -16,29 +16,25 @@ The LDAP integration in Grafana allows your Grafana users to login with their LD group memberships and Grafana Organization user roles. Below we detail grafana.ini config file settings and ldap.toml config file options. -## [auth.ldap] +## Enable LDAP -### enabled -Set to `true` to enable LDAP integration (default: `false`) - -### config_file -Path to the LDAP specific configuration file (default: `/etc/grafana/ldap.toml`) - -### allow_sign_up - -Allow sign up should almost always be true (default) to allow new Grafana users to be created (if ldap authentication is ok). If set to -false only pre-existing Grafana users will be able to login (if ldap authentication is ok). - -
- -Grafana (2.1 and newer) ships with a strong LDAP integration feature. -## Configuration -You turn on LDAP in the [main config file]({{< relref "configuration.md#auth-ldap" >}}) as well as specify the path to the LDAP +You turn on LDAP in the [main config file]({{< relref "installation/configuration.md" >}}) as well as specify the path to the LDAP specific configuration file (default: `/etc/grafana/ldap.toml`). -### Example config +```bash +[auth.ldap] +# Set to `true` to enable LDAP integration (default: `false`) +enabled = true +# Path to the LDAP specific configuration file (default: `/etc/grafana/ldap.toml`) +config_file = /etc/grafana/ldap.toml` +# Allow sign up should almost always be true (default) to allow new Grafana users to be created (if ldap authentication is ok). If set to +# false only pre-existing Grafana users will be able to login (if ldap authentication is ok). +allow_sign_up = true +``` -```toml +## LDAP Configuration + +```bash # To troubleshoot and get more log info enable ldap debug logging in grafana.ini # [log] # filters = ldap:debug @@ -135,7 +131,7 @@ The search filter and search bases settings are still needed to perform the LDAP ## POSIX schema (no memberOf attribute) If your ldap server does not support the memberOf attribute add these options: -```toml +```bash ## Group search filter, to retrieve the groups of which the user is a member (only set if memberOf attribute is not available) group_search_filter = "(&(objectClass=posixGroup)(memberUid=%s))" ## An array of the base DNs to search through for groups. Typically uses ou=groups diff --git a/docs/sources/auth/overview.md b/docs/sources/auth/overview.md index fc01a713ca8..a9f682ec000 100644 --- a/docs/sources/auth/overview.md +++ b/docs/sources/auth/overview.md @@ -14,7 +14,7 @@ weight = 1 Grafana provides many ways to authenticate users. Some authentication integrations also enable syncing user permissions and org memberships. -## OAuth2 Integrations +## OAuth Integrations - [Google OAuth]({{< relref "auth/google.md" >}}) - [GitHub OAuth]({{< relref "auth/github.md" >}}) diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index 5aee2c5f594..9882d1073cf 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -324,7 +324,7 @@ Defaults to `false`. Grafana provides many ways to authenticate users. The docs for authentication has been split in to many differnet pages below. -- [Anonymous access]({{< relref "auth/overview.md" >}}) (auth.anonymous) +- [Authentication Overview]({{< relref "auth/overview.md" >}}) (anonymous access options, hide login and more) - [Google OAuth]({{< relref "auth/google.md" >}}) (auth.google) - [GitHub OAuth]({{< relref "auth/github.md" >}}) (auth.github) - [Gitlab OAuth]({{< relref "auth/gitlab.md" >}}) (auth.gitlab) From e3641197749ba07198a5fa53887f9fd887e6078d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Thu, 6 Sep 2018 13:21:11 +0200 Subject: [PATCH 23/36] docs: minor fixes --- docs/sources/auth/generic-oauth.md | 2 +- docs/sources/auth/google.md | 2 +- docs/sources/auth/overview.md | 2 +- docs/sources/installation/configuration.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/sources/auth/generic-oauth.md b/docs/sources/auth/generic-oauth.md index 70c1b937427..bec5a98e04a 100644 --- a/docs/sources/auth/generic-oauth.md +++ b/docs/sources/auth/generic-oauth.md @@ -4,7 +4,7 @@ description = "Grafana OAuthentication Guide " keywords = ["grafana", "configuration", "documentation", "oauth"] type = "docs" [menu.docs] -name = "Generic OAuth2" +name = "Generic OAuth" identifier = "generic_oauth" parent = "authentication" weight = 3 diff --git a/docs/sources/auth/google.md b/docs/sources/auth/google.md index 2a79037c430..eeb78044d3e 100644 --- a/docs/sources/auth/google.md +++ b/docs/sources/auth/google.md @@ -31,7 +31,7 @@ First, you need to create a Google OAuth Client: ## Enable Google OAuth in Grafana -Specify the Client ID and Secret in the [Grafana configuration file]({{< relref "installation/configuration.md/#config-file-locations" >}}). For example: +Specify the Client ID and Secret in the [Grafana configuration file]({{< relref "installation/configuration.md#config-file-locations" >}}). For example: ```bash [auth.google] diff --git a/docs/sources/auth/overview.md b/docs/sources/auth/overview.md index a9f682ec000..3a38ed83988 100644 --- a/docs/sources/auth/overview.md +++ b/docs/sources/auth/overview.md @@ -19,7 +19,7 @@ permissions and org memberships. - [Google OAuth]({{< relref "auth/google.md" >}}) - [GitHub OAuth]({{< relref "auth/github.md" >}}) - [Gitlab OAuth]({{< relref "auth/gitlab.md" >}}) -- [Generic OAuth]({{< relref "auth/oauth.md" >}}) (Okta2, BitBucket, Azure, OneLogin, Auth0) +- [Generic OAuth]({{< relref "auth/generic-oauth.md" >}}) (Okta2, BitBucket, Azure, OneLogin, Auth0) ## LDAP integrations diff --git a/docs/sources/installation/configuration.md b/docs/sources/installation/configuration.md index d62b949ead4..cbcea1df1f1 100644 --- a/docs/sources/installation/configuration.md +++ b/docs/sources/installation/configuration.md @@ -322,7 +322,7 @@ Defaults to `false`. ## [auth] -Grafana provides many ways to authenticate users. The docs for authentication has been split in to many differnet pages +Grafana provides many ways to authenticate users. The docs for authentication has been split in to many different pages below. - [Authentication Overview]({{< relref "auth/overview.md" >}}) (anonymous access options, hide login and more) From 4ce41c16fc23e41c314f5ee01dc1c6a5df428414 Mon Sep 17 00:00:00 2001 From: bergquist Date: Thu, 6 Sep 2018 13:33:38 +0200 Subject: [PATCH 24/36] changelog: note about closing #10424 --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8470adc81a..1f5360035fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ ### Minor +* **Alerting**: Its now possible to configure the default value for how to handle errors and no data in alerting. [#10424](https://github.com/grafana/grafana/issues/10424) * **GrafanaCli**: Fixed issue with grafana-cli install plugin resulting in corrupt http response from source error. Fixes [#13079](https://github.com/grafana/grafana/issues/13079) * **Logging**: Reopen log files after receiving a SIGHUP signal [#13112](https://github.com/grafana/grafana/pull/13112), thx [@filewalkwithme](https://github.com/filewalkwithme) * **Api**: Delete nonexistent datasource should return 404 [#12313](https://github.com/grafana/grafana/issues/12313), thx [@AustinWinstanley](https://github.com/AustinWinstanley) From db639684bb9df8669e56da62ad4ba5bbfe612469 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Thu, 6 Sep 2018 13:52:16 +0200 Subject: [PATCH 25/36] docs: sql datasources min time interval --- docs/sources/administration/provisioning.md | 2 +- docs/sources/features/datasources/mssql.md | 6 ++++-- docs/sources/features/datasources/mysql.md | 4 +++- docs/sources/features/datasources/postgres.md | 4 +++- docs/sources/reference/templating.md | 2 +- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/sources/administration/provisioning.md b/docs/sources/administration/provisioning.md index b2310378f16..c8d83ea1c54 100644 --- a/docs/sources/administration/provisioning.md +++ b/docs/sources/administration/provisioning.md @@ -154,7 +154,7 @@ Since not all datasources have the same configuration settings we only have the | tlsAuthWithCACert | boolean | *All* | Enable TLS authentication using CA cert | | tlsSkipVerify | boolean | *All* | Controls whether a client verifies the server's certificate chain and host name. | | graphiteVersion | string | Graphite | Graphite version | -| timeInterval | string | Elastic, InfluxDB, MSSQL, MySQL, PostgreSQL & Prometheus | Lowest interval/step value that should be used for this data source | +| timeInterval | string | Prometheus, Elasticsearch, InfluxDB, MySQL, PostgreSQL & MSSQL | Lowest interval/step value that should be used for this data source | | esVersion | number | Elastic | Elasticsearch version as a number (2/5/56) | | timeField | string | Elastic | Which field that should be used as timestamp | | interval | string | Elastic | Index date time format | diff --git a/docs/sources/features/datasources/mssql.md b/docs/sources/features/datasources/mssql.md index 869f25f70cf..6bfcfd807f1 100644 --- a/docs/sources/features/datasources/mssql.md +++ b/docs/sources/features/datasources/mssql.md @@ -6,7 +6,7 @@ type = "docs" [menu.docs] name = "Microsoft SQL Server" parent = "datasources" -weight = 7 +weight = 8 +++ # Using Microsoft SQL Server in Grafana @@ -34,7 +34,9 @@ Name | Description *Password* | Database user's password ### Min time interval -A lower limit for the `$__interval` variable. Recommended to be set to write frequency, for example `1m` if your data is written every minute. + +A lower limit for the [$__interval](/reference/templating/#the-interval-variable) and [$__interval_ms](/reference/templating/#the-interval-ms-variable) variables. +Recommended to be set to write frequency, for example `1m` if your data is written every minute. This option can also be overridden/configured in a dashboard panel under data source options. It's important to note that this value **needs** to be formatted as a number followed by a valid time identifier, e.g. `1m` (1 minute) or `30s` (30 seconds). The following time identifiers are supported: diff --git a/docs/sources/features/datasources/mysql.md b/docs/sources/features/datasources/mysql.md index 91986866a85..e13abcf80a2 100644 --- a/docs/sources/features/datasources/mysql.md +++ b/docs/sources/features/datasources/mysql.md @@ -37,7 +37,9 @@ Name | Description *Password* | Database user's password ### Min time interval -A lower limit for the `$__interval` variable. Recommended to be set to write frequency, for example `1m` if your data is written every minute. + +A lower limit for the [$__interval](/reference/templating/#the-interval-variable) and [$__interval_ms](/reference/templating/#the-interval-ms-variable) variables. +Recommended to be set to write frequency, for example `1m` if your data is written every minute. This option can also be overridden/configured in a dashboard panel under data source options. It's important to note that this value **needs** to be formatted as a number followed by a valid time identifier, e.g. `1m` (1 minute) or `30s` (30 seconds). The following time identifiers are supported: diff --git a/docs/sources/features/datasources/postgres.md b/docs/sources/features/datasources/postgres.md index 630823cf781..013d6342634 100644 --- a/docs/sources/features/datasources/postgres.md +++ b/docs/sources/features/datasources/postgres.md @@ -35,7 +35,9 @@ Name | Description *TimescaleDB* | TimescaleDB is a time-series database built as a PostgreSQL extension. If enabled, Grafana will use `time_bucket` in the `$__timeGroup` macro and display TimescaleDB specific aggregate functions in the query builder (only available in Grafana 5.3+). ### Min time interval -A lower limit for the `$__interval` variable. Recommended to be set to write frequency, for example `1m` if your data is written every minute. + +A lower limit for the [$__interval](/reference/templating/#the-interval-variable) and [$__interval_ms](/reference/templating/#the-interval-ms-variable) variables. +Recommended to be set to write frequency, for example `1m` if your data is written every minute. This option can also be overridden/configured in a dashboard panel under data source options. It's important to note that this value **needs** to be formatted as a number followed by a valid time identifier, e.g. `1m` (1 minute) or `30s` (30 seconds). The following time identifiers are supported: diff --git a/docs/sources/reference/templating.md b/docs/sources/reference/templating.md index 7f86465312c..31251fd6389 100644 --- a/docs/sources/reference/templating.md +++ b/docs/sources/reference/templating.md @@ -245,7 +245,7 @@ Grafana has global built-in variables that can be used in expressions in the que ### The $__interval Variable -This $__interval variable is similar to the `auto` interval variable that is described above. It can be used as a parameter to group by time (for InfluxDB), Date histogram interval (for Elasticsearch) or as a *summarize* function parameter (for Graphite). +This $__interval variable is similar to the `auto` interval variable that is described above. It can be used as a parameter to group by time (for InfluxDB, MySQL, Postgres, MSSQL), Date histogram interval (for Elasticsearch) or as a *summarize* function parameter (for Graphite). Grafana automatically calculates an interval that can be used to group by time in queries. When there are more data points than can be shown on a graph then queries can be made more efficient by grouping by a larger interval. It is more efficient to group by 1 day than by 10s when looking at 3 months of data and the graph will look the same and the query will be faster. The `$__interval` is calculated using the time range and the width of the graph (the number of pixels). From cf832e7db483743630b8509474f600ebd058d6fb Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 6 Sep 2018 14:23:28 +0300 Subject: [PATCH 26/36] wrapper for react-custom-scrollbars component --- package.json | 2 + .../components/ScrollBar/withScrollBar.tsx | 53 +++++++++++++++++++ public/sass/components/_scrollbar.scss | 43 +++++++++++++++ yarn.lock | 42 ++++++++++++++- 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 public/app/core/components/ScrollBar/withScrollBar.tsx diff --git a/package.json b/package.json index 87ba147fb4d..9ee81d7f8ac 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@types/jest": "^21.1.4", "@types/node": "^8.0.31", "@types/react": "^16.0.25", + "@types/react-custom-scrollbars": "^4.0.5", "@types/react-dom": "^16.0.3", "angular-mocks": "1.6.6", "autoprefixer": "^6.4.0", @@ -154,6 +155,7 @@ "prop-types": "^15.6.0", "rc-cascader": "^0.14.0", "react": "^16.2.0", + "react-custom-scrollbars": "^4.2.1", "react-dom": "^16.2.0", "react-grid-layout": "0.16.6", "react-highlight-words": "^0.10.0", diff --git a/public/app/core/components/ScrollBar/withScrollBar.tsx b/public/app/core/components/ScrollBar/withScrollBar.tsx new file mode 100644 index 00000000000..9f8ad942167 --- /dev/null +++ b/public/app/core/components/ScrollBar/withScrollBar.tsx @@ -0,0 +1,53 @@ +import React from 'react'; +import Scrollbars from 'react-custom-scrollbars'; + +interface WithScrollBarProps { + customClassName?: string; + autoHide?: boolean; + autoHideTimeout?: number; + autoHideDuration?: number; + hideTracksWhenNotNeeded?: boolean; +} + +const withScrollBarDefaultProps: Partial = { + customClassName: 'custom-scrollbars', + autoHide: true, + autoHideTimeout: 200, + autoHideDuration: 200, + hideTracksWhenNotNeeded: false, +}; + +/** + * Wraps component into component from `react-custom-scrollbars` + */ +export default function withScrollBar

(WrappedComponent: React.ComponentType

) { + return class extends React.Component

{ + static defaultProps = withScrollBarDefaultProps; + + render() { + // Use type casting here in order to get rest of the props working. See more + // https://github.com/Microsoft/TypeScript/issues/14409 + // https://github.com/Microsoft/TypeScript/pull/13288 + const { autoHide, autoHideTimeout, autoHideDuration, hideTracksWhenNotNeeded, customClassName, ...props } = this + .props as WithScrollBarProps; + const scrollProps = { autoHide, autoHideTimeout, autoHideDuration, hideTracksWhenNotNeeded }; + + return ( +

} + renderTrackVertical={props =>
} + renderThumbHorizontal={props =>
} + renderThumbVertical={props =>
} + renderView={props =>
} + {...scrollProps} + > + + + ); + } + }; +} diff --git a/public/sass/components/_scrollbar.scss b/public/sass/components/_scrollbar.scss index 78173b73f47..adb9e0c54c0 100644 --- a/public/sass/components/_scrollbar.scss +++ b/public/sass/components/_scrollbar.scss @@ -294,3 +294,46 @@ padding-top: 1px; } } + +// Custom styles for 'react-custom-scrollbars' + +.custom-scrollbars { + // Fix for Firefox. For some reason sometimes .view container gets a height of its content, but in order to + // make scroll working it should fit outer container size (scroll appears only when inner container size is + // greater than outer one). + display: flex; + flex-grow: 1; + + .view { + display: flex; + flex-grow: 1; + } + + .track-vertical { + border-radius: 3px; + width: 6px !important; + + right: 2px; + bottom: 2px; + top: 2px; + } + + .track-horizontal { + border-radius: 3px; + height: 6px !important; + + right: 2px; + bottom: 2px; + left: 2px; + } + + .thumb-vertical { + @include gradient-vertical($scrollbarBackground, $scrollbarBackground2); + border-radius: 6px; + } + + .thumb-horizontal { + @include gradient-horizontal($scrollbarBackground, $scrollbarBackground2); + border-radius: 6px; + } +} diff --git a/yarn.lock b/yarn.lock index c15c77cc45f..54f7572d5d2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -473,6 +473,10 @@ add-dom-event-listener@1.x: dependencies: object-assign "4.x" +add-px-to-style@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/add-px-to-style/-/add-px-to-style-1.0.0.tgz#d0c135441fa8014a8137904531096f67f28f263a" + agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.0.tgz#9838b5c3392b962bad031e6a4c5e1024abec45ce" @@ -3406,6 +3410,14 @@ dom-converter@~0.1: dependencies: utila "~0.3" +dom-css@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/dom-css/-/dom-css-2.1.0.tgz#fdbc2d5a015d0a3e1872e11472bbd0e7b9e6a202" + dependencies: + add-px-to-style "1.0.0" + prefix-style "2.0.1" + to-camel-case "1.0.0" + dom-helpers@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6" @@ -9137,6 +9149,10 @@ prebuild-install@^2.3.0: tunnel-agent "^0.6.0" which-pm-runs "^1.0.0" +prefix-style@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/prefix-style/-/prefix-style-2.0.1.tgz#66bba9a870cfda308a5dc20e85e9120932c95a06" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -9388,7 +9404,7 @@ qw@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/qw/-/qw-1.0.1.tgz#efbfdc740f9ad054304426acb183412cc8b996d4" -raf@^3.4.0: +raf@^3.1.0, raf@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.0.tgz#a28876881b4bc2ca9117d4138163ddb80f781575" dependencies: @@ -9496,6 +9512,14 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" +react-custom-scrollbars@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/react-custom-scrollbars/-/react-custom-scrollbars-4.2.1.tgz#830fd9502927e97e8a78c2086813899b2a8b66db" + dependencies: + dom-css "^2.0.0" + prop-types "^15.5.10" + raf "^3.1.0" + react-dom@^16.2.0: version "16.4.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.4.0.tgz#099f067dd5827ce36a29eaf9a6cdc7cbf6216b1e" @@ -11335,10 +11359,20 @@ to-buffer@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" +to-camel-case@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-camel-case/-/to-camel-case-1.0.0.tgz#1a56054b2f9d696298ce66a60897322b6f423e46" + dependencies: + to-space-case "^1.0.0" + to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" +to-no-case@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-no-case/-/to-no-case-1.0.2.tgz#c722907164ef6b178132c8e69930212d1b4aa16a" + to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -11361,6 +11395,12 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +to-space-case@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-space-case/-/to-space-case-1.0.0.tgz#b052daafb1b2b29dc770cea0163e5ec0ebc9fc17" + dependencies: + to-no-case "^1.0.0" + toposort@^1.0.0: version "1.0.7" resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029" From 3f4099c4a6bff3369406390861f58ae44276891a Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Thu, 6 Sep 2018 14:09:27 +0200 Subject: [PATCH 27/36] changelog: add notes about closing #13157 [skip ci] --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f5360035fe..3ba62a921fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ * **Postgres/MySQL/MSSQL**: Use metric column as prefix when returning multiple value columns [#12727](https://github.com/grafana/grafana/issues/12727), thx [@svenklemm](https://github.com/svenklemm) * **Postgres/MySQL/MSSQL**: New $__timeGroupAlias macro. Postgres $__timeGroup no longer automatically adds time column alias [#12749](https://github.com/grafana/grafana/issues/12749), thx [@svenklemm](https://github.com/svenklemm) * **Postgres/MySQL/MSSQL**: Escape single quotes in variables [#12785](https://github.com/grafana/grafana/issues/12785), thx [@eMerzh](https://github.com/eMerzh) +* **Postgres/MySQL/MSSQL**: Min time interval support [#13157](https://github.com/grafana/grafana/issues/13157), thx [@svenklemm](https://github.com/svenklemm) * **MySQL/MSSQL**: Use datetime format instead of epoch for $__timeFilter, $__timeFrom and $__timeTo macros [#11618](https://github.com/grafana/grafana/issues/11618) [#11619](https://github.com/grafana/grafana/issues/11619), thx [@AustinWinstanley](https://github.com/AustinWinstanley) * **Postgres**: Escape ssl mode parameter in connectionstring [#12644](https://github.com/grafana/grafana/issues/12644), thx [@yogyrahmawan](https://github.com/yogyrahmawan) * **Github OAuth**: Allow changes of user info at Github to be synched to Grafana when signing in [#11818](https://github.com/grafana/grafana/issues/11818), thx [@rwaweber](https://github.com/rwaweber) From bdc3acbd2c15461a604c1a5f4b7ef541de6acc20 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Thu, 6 Sep 2018 14:21:36 +0200 Subject: [PATCH 28/36] changelog: restructure and add 5.3.0-beta1 header [skip ci] --- CHANGELOG.md | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ba62a921fe..08c51cf97e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # 5.3.0 (unreleased) +# 5.3.0-beta1 (2018-09-06) + ### New Major Features * **Alerting**: Notification reminders [#7330](https://github.com/grafana/grafana/issues/7330), thx [@jbaublitz](https://github.com/jbaublitz) @@ -21,19 +23,19 @@ ### Minor * **Alerting**: Its now possible to configure the default value for how to handle errors and no data in alerting. [#10424](https://github.com/grafana/grafana/issues/10424) +* **Alerting**: Fix diff and percent_diff reducers [#11563](https://github.com/grafana/grafana/issues/11563), thx [@jessetane](https://github.com/jessetane) +* **Alerting**: Fix rendering timeout which could cause notifications to not be sent due to rendering timing out [#12151](https://github.com/grafana/grafana/issues/12151) +* **Docker**: Make it possible to set a specific plugin url [#12861](https://github.com/grafana/grafana/pull/12861), thx [ClementGautier](https://github.com/ClementGautier) * **GrafanaCli**: Fixed issue with grafana-cli install plugin resulting in corrupt http response from source error. Fixes [#13079](https://github.com/grafana/grafana/issues/13079) -* **Logging**: Reopen log files after receiving a SIGHUP signal [#13112](https://github.com/grafana/grafana/pull/13112), thx [@filewalkwithme](https://github.com/filewalkwithme) -* **Api**: Delete nonexistent datasource should return 404 [#12313](https://github.com/grafana/grafana/issues/12313), thx [@AustinWinstanley](https://github.com/AustinWinstanley) -* **Dashboard**: Fix selecting current dashboard from search should not reload dashboard [#12248](https://github.com/grafana/grafana/issues/12248) -* **Dashboard**: Use uid when linking to dashboards internally in a dashboard [#10705](https://github.com/grafana/grafana/issues/10705) -* **Singlestat**: Make colorization of prefix and postfix optional in singlestat [#11892](https://github.com/grafana/grafana/pull/11892), thx [@ApsOps](https://github.com/ApsOps) +* **Provisioning**: Should allow one default datasource per organisation [#12229](https://github.com/grafana/grafana/issues/12229) +* **Github OAuth**: Allow changes of user info at Github to be synched to Grafana when signing in [#11818](https://github.com/grafana/grafana/issues/11818), thx [@rwaweber](https://github.com/rwaweber) +* **OAuth**: Fix overriding tls_skip_verify_insecure using environment variable [#12747](https://github.com/grafana/grafana/issues/12747), thx [@jangaraj](https://github.com/jangaraj) * **Prometheus**: Fix graph panel bar width issue in aligned prometheus queries [#12379](https://github.com/grafana/grafana/issues/12379) * **Prometheus**: Heatmap - fix unhandled error when some points are missing [#12484](https://github.com/grafana/grafana/issues/12484) * **Prometheus**: Add $__interval, $__interval_ms, $__range, $__range_s & $__range_ms support for dashboard and template queries [#12597](https://github.com/grafana/grafana/issues/12597) [#12882](https://github.com/grafana/grafana/issues/12882), thx [@roidelapluie](https://github.com/roidelapluie) -* **Variables**: Skip unneeded extra query request when de-selecting variable values used for repeated panels [#8186](https://github.com/grafana/grafana/issues/8186), thx [@mtanda](https://github.com/mtanda) -* **Variables**: Limit amount of queries executed when updating variable that other variable(s) are dependent on [#11890](https://github.com/grafana/grafana/issues/11890) -* **Variables**: Support query variable refresh when another variable referenced in `Regex` field change its value [#12952](https://github.com/grafana/grafana/issues/12952), thx [@franciscocpg](https://github.com/franciscocpg) -* **Variables**: Support variables in query variable `Custom all value` field [#12965](https://github.com/grafana/grafana/issues/12965), thx [@franciscocpg](https://github.com/franciscocpg) +* **Elasticsearch**: For alerting/backend, support having index name to the right of pattern in index pattern [#12731](https://github.com/grafana/grafana/issues/12731) +* **Graphite**: Fix for quoting of int function parameters (when using variables) [#11927](https://github.com/grafana/grafana/pull/11927) +* **InfluxDB**: Support timeFilter in query templating for InfluxDB [#12598](https://github.com/grafana/grafana/pull/12598), thx [kichristensen](https://github.com/kichristensen) * **Postgres/MySQL/MSSQL**: New $__unixEpochGroup and $__unixEpochGroupAlias macros [#12892](https://github.com/grafana/grafana/issues/12892), thx [@svenklemm](https://github.com/svenklemm) * **Postgres/MySQL/MSSQL**: Add previous fill mode to $__timeGroup macro which will fill in previously seen value when point is missing [#12756](https://github.com/grafana/grafana/issues/12756), thx [@svenklemm](https://github.com/svenklemm) * **Postgres/MySQL/MSSQL**: Use floor rounding in $__timeGroup macro function [#12460](https://github.com/grafana/grafana/issues/12460), thx [@svenklemm](https://github.com/svenklemm) @@ -43,33 +45,33 @@ * **Postgres/MySQL/MSSQL**: Min time interval support [#13157](https://github.com/grafana/grafana/issues/13157), thx [@svenklemm](https://github.com/svenklemm) * **MySQL/MSSQL**: Use datetime format instead of epoch for $__timeFilter, $__timeFrom and $__timeTo macros [#11618](https://github.com/grafana/grafana/issues/11618) [#11619](https://github.com/grafana/grafana/issues/11619), thx [@AustinWinstanley](https://github.com/AustinWinstanley) * **Postgres**: Escape ssl mode parameter in connectionstring [#12644](https://github.com/grafana/grafana/issues/12644), thx [@yogyrahmawan](https://github.com/yogyrahmawan) -* **Github OAuth**: Allow changes of user info at Github to be synched to Grafana when signing in [#11818](https://github.com/grafana/grafana/issues/11818), thx [@rwaweber](https://github.com/rwaweber) -* **Alerting**: Fix diff and percent_diff reducers [#11563](https://github.com/grafana/grafana/issues/11563), thx [@jessetane](https://github.com/jessetane) -* **Alerting**: Fix rendering timeout which could cause notifications to not be sent due to rendering timing out [#12151](https://github.com/grafana/grafana/issues/12151) * **Cloudwatch**: Improved error handling [#12489](https://github.com/grafana/grafana/issues/12489), thx [@mtanda](https://github.com/mtanda) * **Cloudwatch**: AppSync metrics and dimensions [#12300](https://github.com/grafana/grafana/issues/12300), thx [@franciscocpg](https://github.com/franciscocpg) * **Cloudwatch**: Direct Connect metrics and dimensions [#12762](https://github.com/grafana/grafana/pulls/12762), thx [@mindriot88](https://github.com/mindriot88) * **Cloudwatch**: Added BurstBalance metric to list of AWS RDS metrics [#12561](https://github.com/grafana/grafana/pulls/12561), thx [@activeshadow](https://github.com/activeshadow) * **Cloudwatch**: Add new Redshift metrics and dimensions [#12063](https://github.com/grafana/grafana/pulls/12063), thx [@A21z](https://github.com/A21z) +* **Dashboard**: Fix selecting current dashboard from search should not reload dashboard [#12248](https://github.com/grafana/grafana/issues/12248) +* **Dashboard**: Use uid when linking to dashboards internally in a dashboard [#10705](https://github.com/grafana/grafana/issues/10705) +* **Graph**: Option to hide series from tooltip [#3341](https://github.com/grafana/grafana/issues/3341), thx [@mtanda](https://github.com/mtanda) +* **Singlestat**: Make colorization of prefix and postfix optional in singlestat [#11892](https://github.com/grafana/grafana/pull/11892), thx [@ApsOps](https://github.com/ApsOps) * **Table**: Adjust header contrast for the light theme [#12668](https://github.com/grafana/grafana/issues/12668) * **Table**: Fix link color when using light theme and thresholds in use [#12766](https://github.com/grafana/grafana/issues/12766) * **Table**: Fix for useless horizontal scrollbar for table panel [#9964](https://github.com/grafana/grafana/issues/9964) * **Table**: Make table sorting stable when null values exist [#12362](https://github.com/grafana/grafana/pull/12362), thx [@bz2](https://github.com/bz2) -* **Elasticsearch**: For alerting/backend, support having index name to the right of pattern in index pattern [#12731](https://github.com/grafana/grafana/issues/12731) -* **OAuth**: Fix overriding tls_skip_verify_insecure using environment variable [#12747](https://github.com/grafana/grafana/issues/12747), thx [@jangaraj](https://github.com/jangaraj) +* **Heatmap**: Fix broken tooltip and crosshair on Firefox [#12486](https://github.com/grafana/grafana/issues/12486) +* **Datasource**: Fix UI issue with secret fields after updating datasource [#11270](https://github.com/grafana/grafana/issues/11270) +* **Variables**: Skip unneeded extra query request when de-selecting variable values used for repeated panels [#8186](https://github.com/grafana/grafana/issues/8186), thx [@mtanda](https://github.com/mtanda) +* **Variables**: Limit amount of queries executed when updating variable that other variable(s) are dependent on [#11890](https://github.com/grafana/grafana/issues/11890) +* **Variables**: Support query variable refresh when another variable referenced in `Regex` field change its value [#12952](https://github.com/grafana/grafana/issues/12952), thx [@franciscocpg](https://github.com/franciscocpg) +* **Variables**: Support variables in query variable `Custom all value` field [#12965](https://github.com/grafana/grafana/issues/12965), thx [@franciscocpg](https://github.com/franciscocpg) * **Units**: Change units to include characters for power of 2 and 3 [#12744](https://github.com/grafana/grafana/pull/12744), thx [@Worty](https://github.com/Worty) * **Units**: Polish złoty currency [#12691](https://github.com/grafana/grafana/pull/12691), thx [@mwegrzynek](https://github.com/mwegrzynek) * **Units**: Adds bitcoin axes unit. [#13125](https://github.com/grafana/grafana/pull/13125) -* **Graph**: Option to hide series from tooltip [#3341](https://github.com/grafana/grafana/issues/3341), thx [@mtanda](https://github.com/mtanda) -* **UI**: Fix iOS home screen "app" icon and Windows 10 app experience [#12752](https://github.com/grafana/grafana/issues/12752), thx [@andig](https://github.com/andig) -* **Datasource**: Fix UI issue with secret fields after updating datasource [#11270](https://github.com/grafana/grafana/issues/11270) -* **Plugins**: Convert URL-like text to links in plugins readme [#12843](https://github.com/grafana/grafana/pull/12843), thx [pgiraud](https://github.com/pgiraud) -* **Docker**: Make it possible to set a specific plugin url [#12861](https://github.com/grafana/grafana/pull/12861), thx [ClementGautier](https://github.com/ClementGautier) -* **Graphite**: Fix for quoting of int function parameters (when using variables) [#11927](https://github.com/grafana/grafana/pull/11927) -* **InfluxDB**: Support timeFilter in query templating for InfluxDB [#12598](https://github.com/grafana/grafana/pull/12598), thx [kichristensen](https://github.com/kichristensen) -* **Provisioning**: Should allow one default datasource per organisation [#12229](https://github.com/grafana/grafana/issues/12229) -* **Heatmap**: Fix broken tooltip and crosshair on Firefox [#12486](https://github.com/grafana/grafana/issues/12486) +* **Api**: Delete nonexistent datasource should return 404 [#12313](https://github.com/grafana/grafana/issues/12313), thx [@AustinWinstanley](https://github.com/AustinWinstanley) +* **Logging**: Reopen log files after receiving a SIGHUP signal [#13112](https://github.com/grafana/grafana/pull/13112), thx [@filewalkwithme](https://github.com/filewalkwithme) * **Login**: Show loading animation while waiting for authentication response on login [#12865](https://github.com/grafana/grafana/issues/12865) +* **UI**: Fix iOS home screen "app" icon and Windows 10 app experience [#12752](https://github.com/grafana/grafana/issues/12752), thx [@andig](https://github.com/andig) +* **Plugins**: Convert URL-like text to links in plugins readme [#12843](https://github.com/grafana/grafana/pull/12843), thx [pgiraud](https://github.com/pgiraud) ### Breaking changes From a186bc01e0c3c61ef9a44cbc2beb6d332e77d823 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 6 Sep 2018 15:36:22 +0300 Subject: [PATCH 29/36] tests for withScrollBar() wrapper --- .../__snapshots__/withScrollBar.test.tsx.snap | 86 +++++++++++++++++++ .../ScrollBar/withScrollBar.test.tsx | 23 +++++ 2 files changed, 109 insertions(+) create mode 100644 public/app/core/components/ScrollBar/__snapshots__/withScrollBar.test.tsx.snap create mode 100644 public/app/core/components/ScrollBar/withScrollBar.test.tsx diff --git a/public/app/core/components/ScrollBar/__snapshots__/withScrollBar.test.tsx.snap b/public/app/core/components/ScrollBar/__snapshots__/withScrollBar.test.tsx.snap new file mode 100644 index 00000000000..c6b9b5bb37d --- /dev/null +++ b/public/app/core/components/ScrollBar/__snapshots__/withScrollBar.test.tsx.snap @@ -0,0 +1,86 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`withScrollBar renders correctly 1`] = ` +
+
+
+
+
+
+
+
+
+
+
+`; diff --git a/public/app/core/components/ScrollBar/withScrollBar.test.tsx b/public/app/core/components/ScrollBar/withScrollBar.test.tsx new file mode 100644 index 00000000000..89a24a7db8e --- /dev/null +++ b/public/app/core/components/ScrollBar/withScrollBar.test.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import withScrollBar from './withScrollBar'; + +class TestComponent extends React.Component { + render() { + return
; + } +} + +describe('withScrollBar', () => { + it('renders correctly', () => { + const TestComponentWithScroll = withScrollBar(TestComponent); + const tree = renderer + .create( + +

Scrollable content

+
+ ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); +}); From 479e0734518f80ff56d125913632977252b4b2f3 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Thu, 6 Sep 2018 15:22:03 +0200 Subject: [PATCH 30/36] docs: what's new in v5.3 placeholder --- docs/sources/guides/whats-new-in-v5-3.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 docs/sources/guides/whats-new-in-v5-3.md diff --git a/docs/sources/guides/whats-new-in-v5-3.md b/docs/sources/guides/whats-new-in-v5-3.md new file mode 100644 index 00000000000..4a2674c9b39 --- /dev/null +++ b/docs/sources/guides/whats-new-in-v5-3.md @@ -0,0 +1,18 @@ ++++ +title = "What's New in Grafana v5.3" +description = "Feature & improvement highlights for Grafana v5.3" +keywords = ["grafana", "new", "documentation", "5.3"] +type = "docs" +[menu.docs] +name = "Version 5.3" +identifier = "v5.3" +parent = "whatsnew" +weight = -9 ++++ + +# What's New in Grafana v5.3 + +## Changelog + +Checkout the [CHANGELOG.md](https://github.com/grafana/grafana/blob/master/CHANGELOG.md) file for a complete list +of new features, changes, and bug fixes. From 44cd738dd9d2d7d7072df96928743684c637d91a Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Thu, 6 Sep 2018 17:03:43 +0200 Subject: [PATCH 31/36] changelog: typo [skip ci] --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08c51cf97e9..1555d28a91c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -81,7 +81,7 @@ ### New experimental features -These are new features that's still being worked on and are in an experimental phase. We incourage users to try these out and provide any feedback in related issue. +These are new features that's still being worked on and are in an experimental phase. We encourage users to try these out and provide any feedback in related issue. * **Dashboard**: Auto fit dashboard panels to optimize space used for current TV / Monitor [#12768](https://github.com/grafana/grafana/issues/12768) From b070784b8a21885620029602603b0a9b68775712 Mon Sep 17 00:00:00 2001 From: Carl Bergquist Date: Thu, 6 Sep 2018 21:03:09 +0200 Subject: [PATCH 32/36] adds usage stats for alert notifiers (#13173) --- pkg/metrics/metrics.go | 10 ++++++++++ pkg/metrics/metrics_test.go | 22 ++++++++++++++++++++++ pkg/models/stats.go | 9 +++++++++ pkg/services/sqlstore/stats.go | 8 ++++++++ pkg/services/sqlstore/stats_test.go | 6 ++++++ 5 files changed, 55 insertions(+) diff --git a/pkg/metrics/metrics.go b/pkg/metrics/metrics.go index a8d9f7308fa..dcdfbf124e1 100644 --- a/pkg/metrics/metrics.go +++ b/pkg/metrics/metrics.go @@ -440,6 +440,16 @@ func sendUsageStats() { metrics["stats.ds_access.other."+access+".count"] = count } + anStats := models.GetAlertNotifierUsageStatsQuery{} + if err := bus.Dispatch(&anStats); err != nil { + metricsLogger.Error("Failed to get alert notification stats", "error", err) + return + } + + for _, stats := range anStats.Result { + metrics["stats.alert_notifiers."+stats.Type+".count"] = stats.Count + } + out, _ := json.MarshalIndent(report, "", " ") data := bytes.NewBuffer(out) diff --git a/pkg/metrics/metrics_test.go b/pkg/metrics/metrics_test.go index 8d88e03d106..9fbfd0c26a2 100644 --- a/pkg/metrics/metrics_test.go +++ b/pkg/metrics/metrics_test.go @@ -115,6 +115,24 @@ func TestMetrics(t *testing.T) { return nil }) + var getAlertNotifierUsageStatsQuery *models.GetAlertNotifierUsageStatsQuery + bus.AddHandler("test", func(query *models.GetAlertNotifierUsageStatsQuery) error { + query.Result = []*models.NotifierUsageStats{ + { + Type: "slack", + Count: 1, + }, + { + Type: "webhook", + Count: 2, + }, + } + + getAlertNotifierUsageStatsQuery = query + + return nil + }) + var wg sync.WaitGroup var responseBuffer *bytes.Buffer var req *http.Request @@ -157,6 +175,7 @@ func TestMetrics(t *testing.T) { So(getSystemStatsQuery, ShouldNotBeNil) So(getDataSourceStatsQuery, ShouldNotBeNil) So(getDataSourceAccessStatsQuery, ShouldNotBeNil) + So(getAlertNotifierUsageStatsQuery, ShouldNotBeNil) So(req, ShouldNotBeNil) So(req.Method, ShouldEqual, http.MethodPost) So(req.Header.Get("Content-Type"), ShouldEqual, "application/json") @@ -198,6 +217,9 @@ func TestMetrics(t *testing.T) { So(metrics.Get("stats.ds_access."+models.DS_PROMETHEUS+".proxy.count").MustInt(), ShouldEqual, 3) So(metrics.Get("stats.ds_access.other.direct.count").MustInt(), ShouldEqual, 6+7) So(metrics.Get("stats.ds_access.other.proxy.count").MustInt(), ShouldEqual, 4+8) + + So(metrics.Get("stats.alert_notifiers.slack.count").MustInt(), ShouldEqual, 1) + So(metrics.Get("stats.alert_notifiers.webhook.count").MustInt(), ShouldEqual, 2) }) }) diff --git a/pkg/models/stats.go b/pkg/models/stats.go index 4cd50d37463..d3e145dedf4 100644 --- a/pkg/models/stats.go +++ b/pkg/models/stats.go @@ -40,6 +40,15 @@ type GetDataSourceAccessStatsQuery struct { Result []*DataSourceAccessStats } +type NotifierUsageStats struct { + Type string + Count int64 +} + +type GetAlertNotifierUsageStatsQuery struct { + Result []*NotifierUsageStats +} + type AdminStats struct { Users int `json:"users"` Orgs int `json:"orgs"` diff --git a/pkg/services/sqlstore/stats.go b/pkg/services/sqlstore/stats.go index 6db481bf06b..2cec86e7239 100644 --- a/pkg/services/sqlstore/stats.go +++ b/pkg/services/sqlstore/stats.go @@ -13,11 +13,19 @@ func init() { bus.AddHandler("sql", GetDataSourceStats) bus.AddHandler("sql", GetDataSourceAccessStats) bus.AddHandler("sql", GetAdminStats) + bus.AddHandlerCtx("sql", GetAlertNotifiersUsageStats) bus.AddHandlerCtx("sql", GetSystemUserCountStats) } var activeUserTimeLimit = time.Hour * 24 * 30 +func GetAlertNotifiersUsageStats(ctx context.Context, query *m.GetAlertNotifierUsageStatsQuery) error { + var rawSql = `SELECT COUNT(*) as count, type FROM alert_notification GROUP BY type` + query.Result = make([]*m.NotifierUsageStats, 0) + err := x.SQL(rawSql).Find(&query.Result) + return err +} + func GetDataSourceStats(query *m.GetDataSourceStatsQuery) error { var rawSql = `SELECT COUNT(*) as count, type FROM data_source GROUP BY type` query.Result = make([]*m.DataSourceStats, 0) diff --git a/pkg/services/sqlstore/stats_test.go b/pkg/services/sqlstore/stats_test.go index dae24952d17..6949a0dbda2 100644 --- a/pkg/services/sqlstore/stats_test.go +++ b/pkg/services/sqlstore/stats_test.go @@ -36,5 +36,11 @@ func TestStatsDataAccess(t *testing.T) { err := GetDataSourceAccessStats(&query) So(err, ShouldBeNil) }) + + Convey("Get alert notifier stats should not results in error", func() { + query := m.GetAlertNotifierUsageStatsQuery{} + err := GetAlertNotifiersUsageStats(context.Background(), &query) + So(err, ShouldBeNil) + }) }) } From 8fca79e87e6855e433004967146f340b1f7b9659 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Thu, 6 Sep 2018 22:52:14 +0300 Subject: [PATCH 33/36] scrollbar refactor: replace HOC by component with children --- .../ScrollBar/GrafanaScrollbar.test.tsx | 16 ++++++ .../components/ScrollBar/GrafanaScrollbar.tsx | 48 +++++++++++++++++ ...sx.snap => GrafanaScrollbar.test.tsx.snap} | 8 +-- .../ScrollBar/withScrollBar.test.tsx | 23 -------- .../components/ScrollBar/withScrollBar.tsx | 53 ------------------- 5 files changed, 68 insertions(+), 80 deletions(-) create mode 100644 public/app/core/components/ScrollBar/GrafanaScrollbar.test.tsx create mode 100644 public/app/core/components/ScrollBar/GrafanaScrollbar.tsx rename public/app/core/components/ScrollBar/__snapshots__/{withScrollBar.test.tsx.snap => GrafanaScrollbar.test.tsx.snap} (94%) delete mode 100644 public/app/core/components/ScrollBar/withScrollBar.test.tsx delete mode 100644 public/app/core/components/ScrollBar/withScrollBar.tsx diff --git a/public/app/core/components/ScrollBar/GrafanaScrollbar.test.tsx b/public/app/core/components/ScrollBar/GrafanaScrollbar.test.tsx new file mode 100644 index 00000000000..7e519acd29d --- /dev/null +++ b/public/app/core/components/ScrollBar/GrafanaScrollbar.test.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import renderer from 'react-test-renderer'; +import GrafanaScrollbar from './GrafanaScrollbar'; + +describe('GrafanaScrollbar', () => { + it('renders correctly', () => { + const tree = renderer + .create( + +

Scrollable content

+
+ ) + .toJSON(); + expect(tree).toMatchSnapshot(); + }); +}); diff --git a/public/app/core/components/ScrollBar/GrafanaScrollbar.tsx b/public/app/core/components/ScrollBar/GrafanaScrollbar.tsx new file mode 100644 index 00000000000..24e5b0d8828 --- /dev/null +++ b/public/app/core/components/ScrollBar/GrafanaScrollbar.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import Scrollbars from 'react-custom-scrollbars'; + +interface GrafanaScrollBarProps { + customClassName?: string; + autoHide?: boolean; + autoHideTimeout?: number; + autoHideDuration?: number; + hideTracksWhenNotNeeded?: boolean; +} + +const grafanaScrollBarDefaultProps: Partial = { + customClassName: 'custom-scrollbars', + autoHide: true, + autoHideTimeout: 200, + autoHideDuration: 200, + hideTracksWhenNotNeeded: false, +}; + +/** + * Wraps component into component from `react-custom-scrollbars` + */ +class GrafanaScrollbar extends React.Component { + static defaultProps = grafanaScrollBarDefaultProps; + + render() { + const { customClassName, children, ...scrollProps } = this.props; + + return ( +
} + renderTrackVertical={props =>
} + renderThumbHorizontal={props =>
} + renderThumbVertical={props =>
} + renderView={props =>
} + {...scrollProps} + > + {children} + + ); + } +} + +export default GrafanaScrollbar; diff --git a/public/app/core/components/ScrollBar/__snapshots__/withScrollBar.test.tsx.snap b/public/app/core/components/ScrollBar/__snapshots__/GrafanaScrollbar.test.tsx.snap similarity index 94% rename from public/app/core/components/ScrollBar/__snapshots__/withScrollBar.test.tsx.snap rename to public/app/core/components/ScrollBar/__snapshots__/GrafanaScrollbar.test.tsx.snap index c6b9b5bb37d..8e4f51e3587 100644 --- a/public/app/core/components/ScrollBar/__snapshots__/withScrollBar.test.tsx.snap +++ b/public/app/core/components/ScrollBar/__snapshots__/GrafanaScrollbar.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`withScrollBar renders correctly 1`] = ` +exports[`GrafanaScrollbar renders correctly 1`] = `
-
+

+ Scrollable content +

; - } -} - -describe('withScrollBar', () => { - it('renders correctly', () => { - const TestComponentWithScroll = withScrollBar(TestComponent); - const tree = renderer - .create( - -

Scrollable content

-
- ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); -}); diff --git a/public/app/core/components/ScrollBar/withScrollBar.tsx b/public/app/core/components/ScrollBar/withScrollBar.tsx deleted file mode 100644 index 9f8ad942167..00000000000 --- a/public/app/core/components/ScrollBar/withScrollBar.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React from 'react'; -import Scrollbars from 'react-custom-scrollbars'; - -interface WithScrollBarProps { - customClassName?: string; - autoHide?: boolean; - autoHideTimeout?: number; - autoHideDuration?: number; - hideTracksWhenNotNeeded?: boolean; -} - -const withScrollBarDefaultProps: Partial = { - customClassName: 'custom-scrollbars', - autoHide: true, - autoHideTimeout: 200, - autoHideDuration: 200, - hideTracksWhenNotNeeded: false, -}; - -/** - * Wraps component into component from `react-custom-scrollbars` - */ -export default function withScrollBar

(WrappedComponent: React.ComponentType

) { - return class extends React.Component

{ - static defaultProps = withScrollBarDefaultProps; - - render() { - // Use type casting here in order to get rest of the props working. See more - // https://github.com/Microsoft/TypeScript/issues/14409 - // https://github.com/Microsoft/TypeScript/pull/13288 - const { autoHide, autoHideTimeout, autoHideDuration, hideTracksWhenNotNeeded, customClassName, ...props } = this - .props as WithScrollBarProps; - const scrollProps = { autoHide, autoHideTimeout, autoHideDuration, hideTracksWhenNotNeeded }; - - return ( -

} - renderTrackVertical={props =>
} - renderThumbHorizontal={props =>
} - renderThumbVertical={props =>
} - renderView={props =>
} - {...scrollProps} - > - - - ); - } - }; -} From a1d1c4fb9a310ebb90d0b7bc9d49b935d5e12c90 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Fri, 7 Sep 2018 11:06:19 +0200 Subject: [PATCH 34/36] fix code formatting --- pkg/services/alerting/notifiers/teams.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/services/alerting/notifiers/teams.go b/pkg/services/alerting/notifiers/teams.go index 06fc8c1c5c2..7beb71e5c65 100644 --- a/pkg/services/alerting/notifiers/teams.go +++ b/pkg/services/alerting/notifiers/teams.go @@ -104,7 +104,7 @@ func (this *TeamsNotifier) Notify(evalContext *alerting.EvalContext) error { "@type": "OpenUri", "name": "View Rule", "targets": []map[string]interface{}{ - { + { "os": "default", "uri": ruleUrl, }, }, @@ -114,7 +114,7 @@ func (this *TeamsNotifier) Notify(evalContext *alerting.EvalContext) error { "@type": "OpenUri", "name": "View Graph", "targets": []map[string]interface{}{ - { + { "os": "default", "uri": evalContext.ImagePublicUrl, }, }, From 8f054e7c0813fb7907b5d93432603ad5ab72fc62 Mon Sep 17 00:00:00 2001 From: Marcus Efraimsson Date: Fri, 7 Sep 2018 11:30:18 +0200 Subject: [PATCH 35/36] changelog: add notes about closing #13121 [skip ci] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1555d28a91c..b89e925e826 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # 5.3.0 (unreleased) +### Minor + +* **Alerting**: Link to view full size image in Microsoft Teams alert notifier [#13121](https://github.com/grafana/grafana/issues/13121), thx [@holiiveira](https://github.com/holiiveira) + # 5.3.0-beta1 (2018-09-06) ### New Major Features From 35ef51dca91639295c171cc2f4337e2f537d00fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Fri, 7 Sep 2018 14:24:33 +0200 Subject: [PATCH 36/36] refactoring: custom scrollbars PR updated, #13175 --- .../CustomScrollbar.test.tsx} | 8 +++--- .../CustomScrollbar.tsx} | 25 +++++++++---------- .../CustomScrollbar.test.tsx.snap} | 2 +- yarn.lock | 6 +++++ 4 files changed, 23 insertions(+), 18 deletions(-) rename public/app/core/components/{ScrollBar/GrafanaScrollbar.test.tsx => CustomScrollbar/CustomScrollbar.test.tsx} (63%) rename public/app/core/components/{ScrollBar/GrafanaScrollbar.tsx => CustomScrollbar/CustomScrollbar.tsx} (70%) rename public/app/core/components/{ScrollBar/__snapshots__/GrafanaScrollbar.test.tsx.snap => CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap} (96%) diff --git a/public/app/core/components/ScrollBar/GrafanaScrollbar.test.tsx b/public/app/core/components/CustomScrollbar/CustomScrollbar.test.tsx similarity index 63% rename from public/app/core/components/ScrollBar/GrafanaScrollbar.test.tsx rename to public/app/core/components/CustomScrollbar/CustomScrollbar.test.tsx index 7e519acd29d..4edcf7313db 100644 --- a/public/app/core/components/ScrollBar/GrafanaScrollbar.test.tsx +++ b/public/app/core/components/CustomScrollbar/CustomScrollbar.test.tsx @@ -1,14 +1,14 @@ import React from 'react'; import renderer from 'react-test-renderer'; -import GrafanaScrollbar from './GrafanaScrollbar'; +import CustomScrollbar from './CustomScrollbar'; -describe('GrafanaScrollbar', () => { +describe('CustomScrollbar', () => { it('renders correctly', () => { const tree = renderer .create( - +

Scrollable content

-
+ ) .toJSON(); expect(tree).toMatchSnapshot(); diff --git a/public/app/core/components/ScrollBar/GrafanaScrollbar.tsx b/public/app/core/components/CustomScrollbar/CustomScrollbar.tsx similarity index 70% rename from public/app/core/components/ScrollBar/GrafanaScrollbar.tsx rename to public/app/core/components/CustomScrollbar/CustomScrollbar.tsx index 24e5b0d8828..8be65249808 100644 --- a/public/app/core/components/ScrollBar/GrafanaScrollbar.tsx +++ b/public/app/core/components/CustomScrollbar/CustomScrollbar.tsx @@ -1,7 +1,7 @@ -import React from 'react'; +import React, { PureComponent } from 'react'; import Scrollbars from 'react-custom-scrollbars'; -interface GrafanaScrollBarProps { +interface Props { customClassName?: string; autoHide?: boolean; autoHideTimeout?: number; @@ -9,19 +9,18 @@ interface GrafanaScrollBarProps { hideTracksWhenNotNeeded?: boolean; } -const grafanaScrollBarDefaultProps: Partial = { - customClassName: 'custom-scrollbars', - autoHide: true, - autoHideTimeout: 200, - autoHideDuration: 200, - hideTracksWhenNotNeeded: false, -}; - /** * Wraps component into component from `react-custom-scrollbars` */ -class GrafanaScrollbar extends React.Component { - static defaultProps = grafanaScrollBarDefaultProps; +class CustomScrollbar extends PureComponent { + + static defaultProps: Partial = { + customClassName: 'custom-scrollbars', + autoHide: true, + autoHideTimeout: 200, + autoHideDuration: 200, + hideTracksWhenNotNeeded: false, + }; render() { const { customClassName, children, ...scrollProps } = this.props; @@ -45,4 +44,4 @@ class GrafanaScrollbar extends React.Component { } } -export default GrafanaScrollbar; +export default CustomScrollbar; diff --git a/public/app/core/components/ScrollBar/__snapshots__/GrafanaScrollbar.test.tsx.snap b/public/app/core/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap similarity index 96% rename from public/app/core/components/ScrollBar/__snapshots__/GrafanaScrollbar.test.tsx.snap rename to public/app/core/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap index 8e4f51e3587..37d8cea45be 100644 --- a/public/app/core/components/ScrollBar/__snapshots__/GrafanaScrollbar.test.tsx.snap +++ b/public/app/core/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`GrafanaScrollbar renders correctly 1`] = ` +exports[`CustomScrollbar renders correctly 1`] = `