Compare commits

..

17 Commits

Author SHA1 Message Date
Leonard Gram 57a57932af release 6.3.0-beta4 2019-08-02 14:24:40 +02:00
Torkel Ödegaard 62a226b1c3 Navigation: Fixed double settings menus (#18349)
(cherry picked from commit f3fb178efa)
2019-08-02 14:24:40 +02:00
Oleg Gaidarenko a38dcc3ac7 Build: allow bash to expand the wildcard (#18354)
If wildcards are in the quotes they not going to be expanded

(cherry picked from commit 89a4f30eab)
2019-08-02 14:24:40 +02:00
Torkel Ödegaard c39b0e246b Gauges: Fixes error when mappings array was undefined (#18353)
(cherry picked from commit 142c7eb0e6)
2019-08-02 14:24:40 +02:00
gotjosh f8f1f506ed Auth Proxy: Include additional headers as part of the cache key (#18298)
* Auth Proxy: Include additional headers as part of the cache key

Auth proxy has support to send additional user attributes as part of the
authentication flow. These attributes (e.g. Groups) need to be monitored
as part of the process in case of change.

This commit changes the way we compute the cache key to include all of the
attributes sent as part of the authentication request. That way, if we
change any user attributes we'll upsert the user information.

(cherry picked from commit ed8aeb2999)
2019-08-02 14:24:40 +02:00
Ryan McKinley 9d57a1f192 Plugins: avoid app importDashboards() NPE (#18128)
* tables display

* add missing file

* adding toolbar option

* adding toolbar option

* add items to index

* use root import path

* merge master

* show tables info

* add importDashboards code

* remove table changes

* remove table changes

* use deprecation warning

(cherry picked from commit 06b43f6d4b)
2019-08-02 14:24:40 +02:00
Leonard Gram ba4a870632 release 6.3.0-beta3 2019-08-02 11:47:05 +02:00
kay delaney ef9ec32c32 QueryEditors: Fixes flakey text edit mode toggle (#18335)
Closes #18037

(cherry picked from commit 9b5890cc62)
2019-08-02 11:47:05 +02:00
Oleg Gaidarenko 17235e4bd1 Auth: consistently return same basic auth errors (#18310)
* Auth: consistently return same basic auth errors

* Put repeated errors in consts and return only those consts as error strings

* Add tests for errors basic auth cases and moves tests to separate test-case.
  Also names test cases consistently

* Add more error logs and makes their messages consistent

* A bit of code style

* Add additional test helper

* Auth: do not expose even incorrect password

* Auth: address review comments

Use `Debug` for the cases when it's an user error

(cherry picked from commit 82661b9f69)
2019-08-02 11:47:05 +02:00
Leonard Gram eb82b77782 cli: fix for recognizing when in dev mode. (#18334)
(cherry picked from commit c675449aa2)
2019-08-02 11:47:05 +02:00
Sofia Papagiannaki 3af8aa5c4f Fix failing end to end tests job for release (#18323)
Create and push the expected tag to grafana-dev repository
and use this instead for running the end to end tests
for the release.

(cherry picked from commit c9f7e3059f)
2019-08-02 11:47:05 +02:00
Sofia Papagiannaki 5b588af73c Fix OAuth error due to SameSite cookie policy (#18332)
The `oauth_state` cookie used to be created with the SameSite value set
according to the `cookie_samesite` configuration.
However, due to a Safari bug SameSite=None or SameSite=invalid are treated
as Strict which results in "missing saved state" OAuth login failures
because the cookie is not sent with the redirect requests to the OAuth
provider.
This commit always creates the `oauth_state` cookie with SameSite=Lax
to compensate for this.

(cherry picked from commit 69b7b8bb46)
2019-08-02 11:47:05 +02:00
kay delaney 5ec6eccfac [Shortcuts] Fixes shortcuts for moving time range backwards and forwards (#18305)
Closes #18159

(cherry picked from commit bcf28cb7a2)
2019-08-02 11:47:05 +02:00
Oleg Gaidarenko 237e0e8631 Build: fix use of env vars in parentheses execs (#18249)
* Build: fix use of env vars in parentheses execs

* Build: disable shellcheck rule SC2086 for a file

Follow up for 4b16cd6cc8

(cherry picked from commit f9a6414b92)
2019-08-02 11:47:05 +02:00
Oleg Gaidarenko 7a165febf3 Build: correct verify script (#18236)
Follow-up for 4b16cd6cc8

(cherry picked from commit ba46cf40e4)
2019-08-02 11:47:05 +02:00
Oleg Gaidarenko fd7c38c62f Build: Introduce shellcheck (#18081)
* Build: introduce shellcheck

Fixes #16198

(cherry picked from commit 4b16cd6cc8)
2019-08-02 11:47:05 +02:00
Oleg Gaidarenko 00519f1105 Build: change definition of the vars in makefile (#18151)
Prompted by the @slim-bean talk (thanks!). With that definition
`GO_FILES` var can be dynamically changed, that will be very helpful
in grafana enterprise repo

(cherry picked from commit 8202fa2fde)
2019-08-02 11:47:05 +02:00
46 changed files with 440 additions and 378 deletions
+28 -1
View File
@@ -101,7 +101,7 @@ jobs:
end-to-end-test-release:
docker:
- image: circleci/node:10-browsers
- image: grafana/grafana:$CIRCLE_TAG
- image: grafana/grafana-dev:$CIRCLE_TAG
steps:
- run: dockerize -wait tcp://127.0.0.1:3000 -timeout 120s
- checkout
@@ -155,6 +155,15 @@ jobs:
name: Lint Go
command: 'make lint-go'
shellcheck:
machine: true
working_directory: ~/go/src/github.com/grafana/grafana
steps:
- checkout
- run:
name: ShellCheck
command: 'make shellcheck'
test-frontend:
docker:
- image: circleci/node:10
@@ -663,6 +672,8 @@ workflows:
filters: *filter-only-master
- lint-go:
filters: *filter-only-master
- shellcheck:
filters: *filter-only-master
- test-frontend:
filters: *filter-only-master
- test-backend:
@@ -678,6 +689,7 @@ workflows:
- test-frontend
- codespell
- lint-go
- shellcheck
- mysql-integration-test
- postgres-integration-test
- build-oss-msi
@@ -690,6 +702,7 @@ workflows:
- test-frontend
- codespell
- lint-go
- shellcheck
- mysql-integration-test
- postgres-integration-test
filters: *filter-only-master
@@ -700,6 +713,7 @@ workflows:
- test-frontend
- codespell
- lint-go
- shellcheck
- mysql-integration-test
- postgres-integration-test
- build-all-enterprise
@@ -711,6 +725,7 @@ workflows:
- test-frontend
- codespell
- lint-go
- shellcheck
- mysql-integration-test
- postgres-integration-test
filters: *filter-only-master
@@ -732,6 +747,8 @@ workflows:
filters: *filter-only-release
- lint-go:
filters: *filter-only-release
- shellcheck:
filters: *filter-only-release
- test-frontend:
filters: *filter-only-release
- test-backend:
@@ -747,6 +764,7 @@ workflows:
- test-frontend
- codespell
- lint-go
- shellcheck
- mysql-integration-test
- postgres-integration-test
- build-oss-msi
@@ -759,6 +777,7 @@ workflows:
- test-frontend
- codespell
- lint-go
- shellcheck
- mysql-integration-test
- postgres-integration-test
filters: *filter-only-release
@@ -770,6 +789,7 @@ workflows:
- test-frontend
- codespell
- lint-go
- shellcheck
- mysql-integration-test
- postgres-integration-test
filters: *filter-only-release
@@ -780,6 +800,7 @@ workflows:
- test-frontend
- codespell
- lint-go
- shellcheck
- mysql-integration-test
- postgres-integration-test
filters: *filter-only-release
@@ -803,6 +824,10 @@ workflows:
filters: *filter-not-release-or-master
- lint-go:
filters: *filter-not-release-or-master
- lint-go:
filters: *filter-not-release-or-master
- shellcheck:
filters: *filter-not-release-or-master
- test-frontend:
filters: *filter-not-release-or-master
- test-backend:
@@ -820,6 +845,7 @@ workflows:
- test-frontend
- codespell
- lint-go
- shellcheck
- mysql-integration-test
- postgres-integration-test
- cache-server-test
@@ -831,6 +857,7 @@ workflows:
- test-frontend
- codespell
- lint-go
- shellcheck
- mysql-integration-test
- postgres-integration-test
- cache-server-test
+8 -2
View File
@@ -2,8 +2,9 @@
.PHONY: all deps-go deps-js deps build-go build-server build-cli build-js build build-docker-dev build-docker-full lint-go gosec revive golangci-lint go-vet test-go test-js test run clean devenv devenv-down revive-alerting
GO := GO111MODULE=on go
GO_FILES := ./pkg/...
GO = GO111MODULE=on go
GO_FILES ?= ./pkg/...
SH_FILES ?= $(shell find ./scripts -name *.sh)
all: deps build
@@ -111,6 +112,11 @@ go-vet:
lint-go: go-vet golangci-lint revive revive-alerting gosec
# with disabled SC1071 we are ignored some TCL,Expect `/usr/bin/env expect` scripts
shellcheck: $(SH_FILES)
@docker run --rm -v "$$PWD:/mnt" koalaman/shellcheck:stable \
$(SH_FILES) -e SC1071
run: scripts/go/bin/bra
@scripts/go/bin/bra run
+4 -8
View File
@@ -37,15 +37,11 @@ export class ConfigCtrl {
postUpdate() {
if (!this.appModel.enabled) {
return this.$q.resolve();
return;
}
return this.appEditCtrl.importDashboards().then(() => {
this.enabled = true;
return {
url: "plugins/raintank-kubernetes-app/page/clusters",
message: "Kubernetes App enabled!"
};
});
// TODO, whatever you want
console.log('Post Update:', this);
}
}
ConfigCtrl.templateUrl = 'components/config/config.html';
+1 -1
View File
@@ -5,7 +5,7 @@
"company": "Grafana Labs"
},
"name": "grafana",
"version": "6.3.0-beta2",
"version": "6.3.0-beta4",
"repository": {
"type": "git",
"url": "http://github.com/grafana/grafana.git"
@@ -1,4 +1,7 @@
export const deprecationWarning = (file: string, oldName: string, newName: string) => {
const message = `[Deprecation warning] ${file}: ${oldName} is deprecated. Use ${newName} instead`;
export const deprecationWarning = (file: string, oldName: string, newName?: string) => {
let message = `[Deprecation warning] ${file}: ${oldName} is deprecated`;
if (newName) {
message += `. Use ${newName} instead`;
}
console.warn(message);
};
+2
View File
@@ -67,6 +67,8 @@ fi
# Tag as 'latest' for official release; otherwise tag as grafana/grafana:master
if echo "$_grafana_tag" | grep -q "^v"; then
docker_tag_all "${_docker_repo}" "latest"
# Create the expected tag for running the end to end tests successfully
docker tag "${_docker_repo}:${_grafana_version}" "grafana/grafana-dev:${_grafana_tag}"
else
docker_tag_all "${_docker_repo}" "master"
docker tag "${_docker_repo}:${_grafana_version}" "grafana/grafana-dev:${_grafana_version}"
+6
View File
@@ -38,8 +38,14 @@ if echo "$_grafana_tag" | grep -q "^v" && echo "$_grafana_tag" | grep -vq "beta"
echo "pushing ${_docker_repo}:latest"
docker_push_all "${_docker_repo}" "latest"
docker_push_all "${_docker_repo}" "${_grafana_version}"
# Push to the grafana-dev repository with the expected tag
# for running the end to end tests successfully
docker push "grafana/grafana-dev:${_grafana_tag}"
elif echo "$_grafana_tag" | grep -q "^v" && echo "$_grafana_tag" | grep -q "beta"; then
docker_push_all "${_docker_repo}" "${_grafana_version}"
# Push to the grafana-dev repository with the expected tag
# for running the end to end tests successfully
docker push "grafana/grafana-dev:${_grafana_tag}"
elif echo "$_grafana_tag" | grep -q "master"; then
docker_push_all "${_docker_repo}" "master"
docker push "grafana/grafana-dev:${_grafana_version}"
+60 -105
View File
@@ -242,93 +242,69 @@ func (hs *HTTPServer) setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, er
}
}
if c.IsGrafanaAdmin || c.OrgRole == m.ROLE_ADMIN {
cfgNode := &dtos.NavLink{
Id: "cfg",
Text: "Configuration",
SubTitle: "Organization: " + c.OrgName,
Icon: "gicon gicon-cog",
Url: setting.AppSubUrl + "/datasources",
Children: []*dtos.NavLink{
{
Text: "Data Sources",
Icon: "gicon gicon-datasources",
Description: "Add and configure data sources",
Id: "datasources",
Url: setting.AppSubUrl + "/datasources",
},
{
Text: "Users",
Id: "users",
Description: "Manage org members",
Icon: "gicon gicon-user",
Url: setting.AppSubUrl + "/org/users",
},
{
Text: "Teams",
Id: "teams",
Description: "Manage org groups",
Icon: "gicon gicon-team",
Url: setting.AppSubUrl + "/org/teams",
},
{
Text: "Plugins",
Id: "plugins",
Description: "View and configure plugins",
Icon: "gicon gicon-plugins",
Url: setting.AppSubUrl + "/plugins",
},
{
Text: "Preferences",
Id: "org-settings",
Description: "Organization preferences",
Icon: "gicon gicon-preferences",
Url: setting.AppSubUrl + "/org",
},
configNodes := []*dtos.NavLink{}
{
Text: "API Keys",
Id: "apikeys",
Description: "Create & manage API keys",
Icon: "gicon gicon-apikeys",
Url: setting.AppSubUrl + "/org/apikeys",
},
},
}
if c.OrgRole != m.ROLE_ADMIN {
cfgNode = &dtos.NavLink{
Id: "cfg",
Text: "Configuration",
SubTitle: "Organization: " + c.OrgName,
Icon: "gicon gicon-cog",
Url: setting.AppSubUrl + "/admin/users",
Children: make([]*dtos.NavLink, 0),
}
}
data.NavTree = append(data.NavTree, cfgNode)
} else {
cfgNode := &dtos.NavLink{
Id: "cfg",
Text: "Configuration",
SubTitle: "Organization: " + c.OrgName,
Icon: "gicon gicon-cog",
Url: setting.AppSubUrl + "/plugins",
Children: []*dtos.NavLink{
{
Text: "Plugins",
Id: "plugins",
Description: "View and configure plugins",
Icon: "gicon gicon-plugins",
Url: setting.AppSubUrl + "/plugins",
},
},
}
data.NavTree = append(data.NavTree, cfgNode)
if c.OrgRole == m.ROLE_ADMIN {
configNodes = append(configNodes, &dtos.NavLink{
Text: "Data Sources",
Icon: "gicon gicon-datasources",
Description: "Add and configure data sources",
Id: "datasources",
Url: setting.AppSubUrl + "/datasources",
})
configNodes = append(configNodes, &dtos.NavLink{
Text: "Users",
Id: "users",
Description: "Manage org members",
Icon: "gicon gicon-user",
Url: setting.AppSubUrl + "/org/users",
})
}
if c.OrgRole == m.ROLE_ADMIN || hs.Cfg.EditorsCanAdmin {
configNodes = append(configNodes, &dtos.NavLink{
Text: "Teams",
Id: "teams",
Description: "Manage org groups",
Icon: "gicon gicon-team",
Url: setting.AppSubUrl + "/org/teams",
})
}
configNodes = append(configNodes, &dtos.NavLink{
Text: "Plugins",
Id: "plugins",
Description: "View and configure plugins",
Icon: "gicon gicon-plugins",
Url: setting.AppSubUrl + "/plugins",
})
if c.OrgRole == m.ROLE_ADMIN {
configNodes = append(configNodes, &dtos.NavLink{
Text: "Preferences",
Id: "org-settings",
Description: "Organization preferences",
Icon: "gicon gicon-preferences",
Url: setting.AppSubUrl + "/org",
})
configNodes = append(configNodes, &dtos.NavLink{
Text: "API Keys",
Id: "apikeys",
Description: "Create & manage API keys",
Icon: "gicon gicon-apikeys",
Url: setting.AppSubUrl + "/org/apikeys",
})
}
data.NavTree = append(data.NavTree, &dtos.NavLink{
Id: "cfg",
Text: "Configuration",
SubTitle: "Organization: " + c.OrgName,
Icon: "gicon gicon-cog",
Url: configNodes[0].Url,
Children: configNodes,
})
if c.IsGrafanaAdmin {
data.NavTree = append(data.NavTree, &dtos.NavLink{
Text: "Server Admin",
@@ -346,27 +322,6 @@ func (hs *HTTPServer) setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, er
})
}
if (c.OrgRole == m.ROLE_EDITOR || c.OrgRole == m.ROLE_VIEWER) && hs.Cfg.EditorsCanAdmin {
cfgNode := &dtos.NavLink{
Id: "cfg",
Text: "Configuration",
SubTitle: "Organization: " + c.OrgName,
Icon: "gicon gicon-cog",
Url: setting.AppSubUrl + "/org/teams",
Children: []*dtos.NavLink{
{
Text: "Teams",
Id: "teams",
Description: "Manage org groups",
Icon: "gicon gicon-team",
Url: setting.AppSubUrl + "/org/teams",
},
},
}
data.NavTree = append(data.NavTree, cfgNode)
}
data.NavTree = append(data.NavTree, &dtos.NavLink{
Text: "Help",
SubTitle: fmt.Sprintf(`%s v%s (%s)`, setting.ApplicationName, setting.BuildVersion, setting.BuildCommit),
+6 -6
View File
@@ -60,7 +60,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *m.ReqContext) {
if code == "" {
state := GenStateString()
hashedState := hashStatecode(state, setting.OAuthService.OAuthInfos[name].ClientSecret)
hs.writeCookie(ctx.Resp, OauthStateCookieName, hashedState, 60)
hs.writeCookie(ctx.Resp, OauthStateCookieName, hashedState, 60, http.SameSiteLaxMode)
if setting.OAuthService.OAuthInfos[name].HostedDomain == "" {
ctx.Redirect(connect.AuthCodeURL(state, oauth2.AccessTypeOnline))
} else {
@@ -73,7 +73,7 @@ func (hs *HTTPServer) OAuthLogin(ctx *m.ReqContext) {
// delete cookie
ctx.Resp.Header().Del("Set-Cookie")
hs.deleteCookie(ctx.Resp, OauthStateCookieName)
hs.deleteCookie(ctx.Resp, OauthStateCookieName, http.SameSiteLaxMode)
if cookieState == "" {
ctx.Handle(500, "login.OAuthLogin(missing saved state)", nil)
@@ -213,11 +213,11 @@ func (hs *HTTPServer) OAuthLogin(ctx *m.ReqContext) {
ctx.Redirect(setting.AppSubUrl + "/")
}
func (hs *HTTPServer) deleteCookie(w http.ResponseWriter, name string) {
hs.writeCookie(w, name, "", -1)
func (hs *HTTPServer) deleteCookie(w http.ResponseWriter, name string, sameSite http.SameSite) {
hs.writeCookie(w, name, "", -1, sameSite)
}
func (hs *HTTPServer) writeCookie(w http.ResponseWriter, name string, value string, maxAge int) {
func (hs *HTTPServer) writeCookie(w http.ResponseWriter, name string, value string, maxAge int, sameSite http.SameSite) {
http.SetCookie(w, &http.Cookie{
Name: name,
MaxAge: maxAge,
@@ -225,7 +225,7 @@ func (hs *HTTPServer) writeCookie(w http.ResponseWriter, name string, value stri
HttpOnly: true,
Path: setting.AppSubUrl + "/",
Secure: hs.Cfg.CookieSecure,
SameSite: hs.Cfg.CookieSameSite,
SameSite: sameSite,
})
}
+29 -13
View File
@@ -6,37 +6,53 @@ import (
"path/filepath"
"github.com/grafana/grafana/pkg/cmd/grafana-cli/logger"
"golang.org/x/xerrors"
)
func GetGrafanaPluginDir(currentOS string) string {
if isDevEnvironment() {
return "../data/plugins"
if rootPath, ok := tryGetRootForDevEnvironment(); ok {
return filepath.Join(rootPath, "data/plugins")
}
return returnOsDefault(currentOS)
}
func isDevEnvironment() bool {
// if ../conf/defaults.ini exists, grafana is not installed as package
// that its in development environment.
// getGrafanaRoot tries to get root of directory when developing grafana ie repo root. It is not perfect it just
// checks what is the binary path and tries to guess based on that but if it is not running in dev env you get a bogus
// path back.
func getGrafanaRoot() (string, error) {
ex, err := os.Executable()
if err != nil {
logger.Error("Could not get executable path. Assuming non dev environment.")
return false
return "", xerrors.New("Failed to get executable path")
}
exPath := filepath.Dir(ex)
_, last := path.Split(exPath)
if last == "bin" {
// In dev env the executable for current platform is created in 'bin/' dir
defaultsPath := filepath.Join(exPath, "../conf/defaults.ini")
_, err = os.Stat(defaultsPath)
return err == nil
return filepath.Join(exPath, ".."), nil
}
// But at the same time there are per platform directories that contain the binaries and can also be used.
defaultsPath := filepath.Join(exPath, "../../conf/defaults.ini")
_, err = os.Stat(defaultsPath)
return err == nil
return filepath.Join(exPath, "../.."), nil
}
// tryGetRootForDevEnvironment returns root path if we are in dev environment. It checks if conf/defaults.ini exists
// which should only exist in dev. Second param is false if we are not in dev or if it wasn't possible to determine it.
func tryGetRootForDevEnvironment() (string, bool) {
rootPath, err := getGrafanaRoot()
if err != nil {
logger.Error("Could not get executable path. Assuming non dev environment.", err)
return "", false
}
devenvPath := filepath.Join(rootPath, "devenv")
_, err = os.Stat(devenvPath)
if err != nil {
return "", false
}
return rootPath, true
}
func returnOsDefault(currentOs string) string {
+43 -19
View File
@@ -1,6 +1,7 @@
package authproxy
import (
"encoding/base32"
"fmt"
"net"
"net/mail"
@@ -32,6 +33,9 @@ var isLDAPEnabled = ldap.IsEnabled
// newLDAP creates multiple LDAP instance
var newLDAP = multildap.New
// supportedHeaders states the supported headers configuration fields
var supportedHeaderFields = []string{"Name", "Email", "Login", "Groups"}
// AuthProxy struct
type AuthProxy struct {
store *remotecache.RemoteCache
@@ -142,9 +146,18 @@ func (auth *AuthProxy) IsAllowedIP() (bool, *Error) {
return false, newError("Proxy authentication required", err)
}
// getKey forms a key for the cache
// getKey forms a key for the cache based on the headers received as part of the authentication flow.
// Our configuration supports multiple headers. The main header contains the email or username.
// And the additional ones that allow us to specify extra attributes: Name, Email or Groups.
func (auth *AuthProxy) getKey() string {
return fmt.Sprintf(CachePrefix, auth.header)
key := strings.TrimSpace(auth.header) // start the key with the main header
auth.headersIterator(func(_, header string) {
key = strings.Join([]string{key, header}, "-") // compose the key with any additional headers
})
hashedKey := base32.StdEncoding.EncodeToString([]byte(key))
return fmt.Sprintf(CachePrefix, hashedKey)
}
// Login logs in user id with whatever means possible
@@ -232,40 +245,36 @@ func (auth *AuthProxy) LoginViaHeader() (int64, error) {
AuthId: auth.header,
}
if auth.headerType == "username" {
switch auth.headerType {
case "username":
extUser.Login = auth.header
// only set Email if it can be parsed as an email address
emailAddr, emailErr := mail.ParseAddress(auth.header)
emailAddr, emailErr := mail.ParseAddress(auth.header) // only set Email if it can be parsed as an email address
if emailErr == nil {
extUser.Email = emailAddr.Address
}
} else if auth.headerType == "email" {
case "email":
extUser.Email = auth.header
extUser.Login = auth.header
} else {
default:
return 0, newError("Auth proxy header property invalid", nil)
}
for _, field := range []string{"Name", "Email", "Login", "Groups"} {
if auth.headers[field] == "" {
continue
auth.headersIterator(func(field string, header string) {
if field == "Groups" {
extUser.Groups = util.SplitString(header)
} else {
reflect.ValueOf(extUser).Elem().FieldByName(field).SetString(header)
}
if val := auth.ctx.Req.Header.Get(auth.headers[field]); val != "" {
if field == "Groups" {
extUser.Groups = util.SplitString(val)
} else {
reflect.ValueOf(extUser).Elem().FieldByName(field).SetString(val)
}
}
}
})
upsert := &models.UpsertUserCommand{
ReqContext: auth.ctx,
SignupAllowed: setting.AuthProxyAutoSignUp,
ExternalUser: extUser,
}
err := bus.Dispatch(upsert)
if err != nil {
return 0, err
@@ -274,6 +283,21 @@ func (auth *AuthProxy) LoginViaHeader() (int64, error) {
return upsert.Result.Id, nil
}
// headersIterator iterates over all non-empty supported additional headers
func (auth *AuthProxy) headersIterator(fn func(field string, header string)) {
for _, field := range supportedHeaderFields {
h := auth.headers[field]
if h == "" {
continue
}
if value := auth.ctx.Req.Header.Get(h); value != "" {
fn(field, strings.TrimSpace(value))
}
}
}
// GetSignedUser get full signed user info
func (auth *AuthProxy) GetSignedUser(userID int64) (*models.SignedInUser, *Error) {
query := &models.GetSignedInUserQuery{
+58 -34
View File
@@ -1,20 +1,20 @@
package authproxy
import (
"encoding/base32"
"errors"
"fmt"
"net/http"
"testing"
. "github.com/smartystreets/goconvey/convey"
"gopkg.in/macaron.v1"
"github.com/grafana/grafana/pkg/bus"
"github.com/grafana/grafana/pkg/infra/remotecache"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/ldap"
"github.com/grafana/grafana/pkg/services/multildap"
"github.com/grafana/grafana/pkg/setting"
. "github.com/smartystreets/goconvey/convey"
"gopkg.in/macaron.v1"
)
type TestMultiLDAP struct {
@@ -45,37 +45,70 @@ func (stub *TestMultiLDAP) User(login string) (
return result, nil
}
func prepareMiddleware(t *testing.T, req *http.Request, store *remotecache.RemoteCache) *AuthProxy {
t.Helper()
ctx := &models.ReqContext{
Context: &macaron.Context{
Req: macaron.Request{
Request: req,
},
},
}
auth := New(&Options{
Store: store,
Ctx: ctx,
OrgID: 4,
})
return auth
}
func TestMiddlewareContext(t *testing.T) {
Convey("auth_proxy helper", t, func() {
req, _ := http.NewRequest("POST", "http://example.com", nil)
setting.AuthProxyHeaderName = "X-Killa"
name := "markelog"
store := remotecache.NewFakeStore(t)
name := "markelog"
req.Header.Add(setting.AuthProxyHeaderName, name)
ctx := &models.ReqContext{
Context: &macaron.Context{
Req: macaron.Request{
Request: req,
},
},
}
Convey("when the cache only contains the main header", func() {
Convey("logs in user from the cache", func() {
store := remotecache.NewFakeStore(t)
key := fmt.Sprintf(CachePrefix, name)
store.Set(key, int64(33), 0)
Convey("with a simple cache key", func() {
// Set cache key
key := fmt.Sprintf(CachePrefix, base32.StdEncoding.EncodeToString([]byte(name)))
store.Set(key, int64(33), 0)
auth := New(&Options{
Store: store,
Ctx: ctx,
OrgID: 4,
// Set up the middleware
auth := prepareMiddleware(t, req, store)
id, err := auth.Login()
So(auth.getKey(), ShouldEqual, "auth-proxy-sync-ttl:NVQXE23FNRXWO===")
So(err, ShouldBeNil)
So(id, ShouldEqual, 33)
})
id, err := auth.Login()
Convey("when the cache key contains additional headers", func() {
setting.AuthProxyHeaders = map[string]string{"Groups": "X-WEBAUTH-GROUPS"}
group := "grafana-core-team"
req.Header.Add("X-WEBAUTH-GROUPS", group)
So(err, ShouldBeNil)
So(id, ShouldEqual, 33)
key := fmt.Sprintf(CachePrefix, base32.StdEncoding.EncodeToString([]byte(name+"-"+group)))
store.Set(key, int64(33), 0)
auth := prepareMiddleware(t, req, store)
id, err := auth.Login()
So(auth.getKey(), ShouldEqual, "auth-proxy-sync-ttl:NVQXE23FNRXWOLLHOJQWMYLOMEWWG33SMUWXIZLBNU======")
So(err, ShouldBeNil)
So(id, ShouldEqual, 33)
})
Convey("when the does not exist", func() {
})
})
Convey("LDAP", func() {
@@ -119,13 +152,9 @@ func TestMiddlewareContext(t *testing.T) {
store := remotecache.NewFakeStore(t)
server := New(&Options{
Store: store,
Ctx: ctx,
OrgID: 4,
})
auth := prepareMiddleware(t, req, store)
id, err := server.Login()
id, err := auth.Login()
So(err, ShouldBeNil)
So(id, ShouldEqual, 42)
@@ -149,11 +178,7 @@ func TestMiddlewareContext(t *testing.T) {
store := remotecache.NewFakeStore(t)
auth := New(&Options{
Store: store,
Ctx: ctx,
OrgID: 4,
})
auth := prepareMiddleware(t, req, store)
stub := &TestMultiLDAP{
ID: 42,
@@ -170,7 +195,6 @@ func TestMiddlewareContext(t *testing.T) {
So(id, ShouldNotEqual, 42)
So(stub.loginCalled, ShouldEqual, false)
})
})
})
}
+42 -17
View File
@@ -21,11 +21,19 @@ import (
var getTime = time.Now
const (
errStringInvalidUsernamePassword = "Invalid username or password"
errStringInvalidAPIKey = "Invalid API key"
)
var (
ReqGrafanaAdmin = Auth(&AuthOptions{ReqSignedIn: true, ReqGrafanaAdmin: true})
ReqSignedIn = Auth(&AuthOptions{ReqSignedIn: true})
ReqEditorRole = RoleAuth(models.ROLE_EDITOR, models.ROLE_ADMIN)
ReqOrgAdmin = RoleAuth(models.ROLE_ADMIN)
ReqGrafanaAdmin = Auth(&AuthOptions{
ReqSignedIn: true,
ReqGrafanaAdmin: true,
})
ReqSignedIn = Auth(&AuthOptions{ReqSignedIn: true})
ReqEditorRole = RoleAuth(models.ROLE_EDITOR, models.ROLE_ADMIN)
ReqOrgAdmin = RoleAuth(models.ROLE_ADMIN)
)
func GetContextHandler(
@@ -106,14 +114,14 @@ func initContextWithApiKey(ctx *models.ReqContext) bool {
// base64 decode key
decoded, err := apikeygen.Decode(keyString)
if err != nil {
ctx.JsonApiErr(401, "Invalid API key", err)
ctx.JsonApiErr(401, errStringInvalidAPIKey, err)
return true
}
// fetch key
keyQuery := models.GetApiKeyByNameQuery{KeyName: decoded.Name, OrgId: decoded.OrgId}
if err := bus.Dispatch(&keyQuery); err != nil {
ctx.JsonApiErr(401, "Invalid API key", err)
ctx.JsonApiErr(401, errStringInvalidAPIKey, err)
return true
}
@@ -121,7 +129,7 @@ func initContextWithApiKey(ctx *models.ReqContext) bool {
// validate api key
if !apikeygen.IsValid(decoded, apikey.Key) {
ctx.JsonApiErr(401, "Invalid API key", err)
ctx.JsonApiErr(401, errStringInvalidAPIKey, err)
return true
}
@@ -140,7 +148,6 @@ func initContextWithApiKey(ctx *models.ReqContext) bool {
}
func initContextWithBasicAuth(ctx *models.ReqContext, orgId int64) bool {
if !setting.BasicAuthEnabled {
return false
}
@@ -158,21 +165,39 @@ func initContextWithBasicAuth(ctx *models.ReqContext, orgId int64) bool {
loginQuery := models.GetUserByLoginQuery{LoginOrEmail: username}
if err := bus.Dispatch(&loginQuery); err != nil {
ctx.JsonApiErr(401, "Basic auth failed", err)
ctx.Logger.Debug(
"Failed to look up the username",
"username", username,
)
ctx.JsonApiErr(401, errStringInvalidUsernamePassword, err)
return true
}
user := loginQuery.Result
loginUserQuery := models.LoginUserQuery{Username: username, Password: password, User: user}
loginUserQuery := models.LoginUserQuery{
Username: username,
Password: password,
User: user,
}
if err := bus.Dispatch(&loginUserQuery); err != nil {
ctx.JsonApiErr(401, "Invalid username or password", err)
ctx.Logger.Debug(
"Failed to authorize the user",
"username", username,
)
ctx.JsonApiErr(401, errStringInvalidUsernamePassword, err)
return true
}
query := models.GetSignedInUserQuery{UserId: user.Id, OrgId: orgId}
if err := bus.Dispatch(&query); err != nil {
ctx.JsonApiErr(401, "Authentication error", err)
ctx.Logger.Error(
"Failed at user signed in",
"id", user.Id,
"org", orgId,
)
ctx.JsonApiErr(401, errStringInvalidUsernamePassword, err)
return true
}
@@ -193,14 +218,14 @@ func initContextWithToken(authTokenService models.UserTokenService, ctx *models.
token, err := authTokenService.LookupToken(ctx.Req.Context(), rawToken)
if err != nil {
ctx.Logger.Error("failed to look up user based on cookie", "error", err)
ctx.Logger.Error("Failed to look up user based on cookie", "error", err)
WriteSessionCookie(ctx, "", -1)
return false
}
query := models.GetSignedInUserQuery{UserId: token.UserId, OrgId: orgID}
if err := bus.Dispatch(&query); err != nil {
ctx.Logger.Error("failed to get user with id", "userId", token.UserId, "error", err)
ctx.Logger.Error("Failed to get user with id", "userId", token.UserId, "error", err)
return false
}
@@ -210,7 +235,7 @@ func initContextWithToken(authTokenService models.UserTokenService, ctx *models.
rotated, err := authTokenService.TryRotateToken(ctx.Req.Context(), token, ctx.RemoteAddr(), ctx.Req.UserAgent())
if err != nil {
ctx.Logger.Error("failed to rotate token", "error", err)
ctx.Logger.Error("Failed to rotate token", "error", err)
return true
}
@@ -223,7 +248,7 @@ func initContextWithToken(authTokenService models.UserTokenService, ctx *models.
func WriteSessionCookie(ctx *models.ReqContext, value string, maxLifetimeDays int) {
if setting.Env == setting.DEV {
ctx.Logger.Info("new token", "unhashed token", value)
ctx.Logger.Info("New token", "unhashed token", value)
}
var maxAge int
+6 -2
View File
@@ -2,6 +2,7 @@ package middleware
import (
"context"
"encoding/base32"
"encoding/json"
"fmt"
"net/http"
@@ -11,6 +12,7 @@ import (
"time"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/assert"
"gopkg.in/macaron.v1"
"github.com/grafana/grafana/pkg/api/dtos"
@@ -21,7 +23,6 @@ import (
"github.com/grafana/grafana/pkg/services/login"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
"github.com/stretchr/testify/assert"
)
const errorTemplate = "error-template"
@@ -377,7 +378,9 @@ func TestMiddlewareContext(t *testing.T) {
setting.LDAPEnabled = true
setting.AuthProxyHeaderName = "X-WEBAUTH-USER"
setting.AuthProxyHeaderProperty = "username"
setting.AuthProxyHeaders = map[string]string{"Groups": "X-WEBAUTH-GROUPS"}
name := "markelog"
group := "grafana-core-team"
middlewareScenario(t, "should not sync the user if it's in the cache", func(sc *scenarioContext) {
bus.AddHandler("test", func(query *models.GetSignedInUserQuery) error {
@@ -385,11 +388,12 @@ func TestMiddlewareContext(t *testing.T) {
return nil
})
key := fmt.Sprintf(cachePrefix, name)
key := fmt.Sprintf(cachePrefix, base32.StdEncoding.EncodeToString([]byte(name+"-"+group)))
sc.remoteCacheService.Set(key, int64(33), 0)
sc.fakeReq("GET", "/")
sc.req.Header.Add(setting.AuthProxyHeaderName, name)
sc.req.Header.Add("X-WEBAUTH-GROUPS", group)
sc.exec()
Convey("Should init user via cache", func() {
+2 -2
View File
@@ -160,11 +160,11 @@ export class KeybindingSrv {
});
this.bind('t left', () => {
scope.appEvent('shift-time-backward');
scope.appEvent('shift-time', -1);
});
this.bind('t right', () => {
scope.appEvent('shift-time-forward');
scope.appEvent('shift-time', 1);
});
// edit panel
@@ -1,6 +1,6 @@
// Libaries
import React, { Component } from 'react';
import { toUtc, dateMath } from '@grafana/data';
import { dateMath } from '@grafana/data';
// Types
import { DashboardModel } from '../../state';
@@ -16,7 +16,6 @@ import { TimePicker, RefreshPicker } from '@grafana/ui';
// Utils & Services
import { getTimeSrv, TimeSrv } from 'app/features/dashboard/services/TimeSrv';
import { defaultSelectOptions } from '@grafana/ui/src/components/TimePicker/TimePicker';
import { getShiftedTimeRange } from 'app/core/utils/timePicker';
export interface Props {
$injector: any;
@@ -43,18 +42,12 @@ export class DashNavTimeControls extends Component<Props> {
return Promise.resolve();
};
onMoveTimePicker = (direction: number) => {
const range = this.timeSrv.timeRange();
const { from, to } = getShiftedTimeRange(direction, range);
this.timeSrv.setTime({
from: toUtc(from),
to: toUtc(to),
});
onMoveBack = () => {
this.$rootScope.appEvent('shift-time', -1);
};
onMoveForward = () => {
this.$rootScope.appEvent('shift-time', 1);
};
onMoveForward = () => this.onMoveTimePicker(1);
onMoveBack = () => this.onMoveTimePicker(-1);
onChangeTimePicker = (timeRange: TimeRange) => {
const { dashboard } = this.props;
@@ -83,7 +83,7 @@ export class QueryEditorRow extends PureComponent<Props, State> {
this.setState({
datasource,
loadedDataSourceValue: this.props.dataSourceValue,
hasTextEditMode: false,
hasTextEditMode: _.has(datasource, 'components.QueryCtrl.prototype.toggleEditorMode'),
});
}
@@ -122,14 +122,8 @@ export class QueryEditorRow extends PureComponent<Props, State> {
const loader = getAngularLoader();
const template = '<plugin-component type="query-ctrl" />';
const scopeProps = { ctrl: this.getAngularQueryComponentScope() };
this.angularQueryEditor = loader.load(this.element, scopeProps, template);
this.angularScope = scopeProps.ctrl;
// give angular time to compile
setTimeout(() => {
this.setState({ hasTextEditMode: !!this.angularScope.toggleEditorMode });
}, 100);
}
onToggleCollapse = () => {
@@ -12,7 +12,7 @@ import { ITimeoutService, ILocationService } from 'angular';
import { ContextSrv } from 'app/core/services/context_srv';
import { DashboardModel } from '../state/DashboardModel';
import { toUtc, dateTime, isDateTime } from '@grafana/data';
import { getZoomedTimeRange } from 'app/core/utils/timePicker';
import { getZoomedTimeRange, getShiftedTimeRange } from 'app/core/utils/timePicker';
export class TimeSrv {
time: any;
@@ -35,6 +35,7 @@ export class TimeSrv {
this.time = { from: '6h', to: 'now' };
$rootScope.$on('zoom-out', this.zoomOut.bind(this));
$rootScope.$on('shift-time', this.shiftTime.bind(this));
$rootScope.$on('$routeUpdate', this.routeUpdated.bind(this));
document.addEventListener('visibilitychange', () => {
@@ -243,6 +244,16 @@ export class TimeSrv {
this.setTime({ from: toUtc(from), to: toUtc(to) });
}
shiftTime(e: any, direction: number) {
const range = this.timeRange();
const { from, to } = getShiftedTimeRange(direction, range);
this.setTime({
from: toUtc(from),
to: toUtc(to),
});
}
}
let singleton: TimeSrv;
@@ -3,7 +3,7 @@ import React, { PureComponent } from 'react';
import cloneDeep from 'lodash/cloneDeep';
import extend from 'lodash/extend';
import { PluginMeta, AppPlugin, Button } from '@grafana/ui';
import { PluginMeta, AppPlugin, Button, deprecationWarning } from '@grafana/ui';
import { AngularComponent, getAngularLoader } from '@grafana/runtime';
import { getBackendSrv } from 'app/core/services/backend_srv';
@@ -124,6 +124,12 @@ export class AppConfigCtrlWrapper extends PureComponent<Props, State> {
this.postUpdateHook = callback;
};
// Stub to avoid unknown function in legacy code
importDashboards = (): Promise<void> => {
deprecationWarning('AppConfig', 'importDashboards()');
return Promise.resolve();
};
enable = () => {
this.model.enabled = true;
this.model.pinned = true;
-4
View File
@@ -9,10 +9,6 @@ export interface GaugeOptions extends SingleStatBaseOptions {
export const standardGaugeFieldOptions: FieldDisplayOptions = {
...standardFieldDisplayOptions,
defaults: {
min: 0,
max: 100,
},
};
export const defaults: GaugeOptions = {
@@ -13,12 +13,10 @@ export interface SingleStatOptions extends SingleStatBaseOptions {
prefixFontSize?: string;
valueFontSize?: string;
postfixFontSize?: string;
colorBackground?: boolean;
colorValue?: boolean;
colorPrefix?: boolean;
colorPostfix?: boolean;
sparkline: SparklineOptions;
}
@@ -32,6 +30,7 @@ export const standardFieldDisplayOptions: FieldDisplayOptions = {
{ value: -Infinity, color: 'green' },
{ value: 80, color: 'red' }, // 80%
],
mappings: [],
},
override: {},
};
+4 -3
View File
@@ -1,11 +1,14 @@
#!/bin/bash
# shellcheck disable=SC2086
#
# This script is executed from within the container.
#
set -e
# shellcheck disable=SC2124
EXTRA_OPTS="$@"
CCARMV6=/opt/rpi-tools/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc
@@ -15,9 +18,6 @@ CCOSX64=/tmp/osxcross/target/bin/o64-clang
CCWIN64=x86_64-w64-mingw32-gcc
CCX64=/tmp/x86_64-centos6-linux-gnu/bin/x86_64-centos6-linux-gnu-gcc
GOPATH=/go
REPO_PATH=$GOPATH/src/github.com/grafana/grafana
cd /go/src/github.com/grafana/grafana
echo "current dir: $(pwd)"
@@ -63,6 +63,7 @@ mkdir dist
go run build.go -gen-version ${OPT} > dist/grafana.version
# Load ruby, needed for packing with fpm
# shellcheck disable=SC1091
source /etc/profile.d/rvm.sh
echo "Packaging"
+12 -15
View File
@@ -9,10 +9,6 @@ CCARMV6=/opt/rpi-tools/arm-bcm2708/arm-linux-gnueabihf/bin/arm-linux-gnueabihf-g
CCARMV7=arm-linux-gnueabihf-gcc
CCARM64=aarch64-linux-gnu-gcc
CCX64=/tmp/x86_64-centos6-linux-gnu/bin/x86_64-centos6-linux-gnu-gcc
##########
GOPATH=/go
REPO_PATH=$GOPATH/src/github.com/grafana/grafana
##########
BUILD_FAST=0
BUILD_BACKEND=1
@@ -51,9 +47,9 @@ while [ "$1" != "" ]; do
esac
done
# shellcheck disable=SC2124
EXTRA_OPTS="$@"
cd /go/src/github.com/grafana/grafana
echo "current dir: $(pwd)"
@@ -73,7 +69,7 @@ function build_backend_linux_amd64() {
if [ ! -d "dist" ]; then
mkdir dist
fi
CC=${CCX64} go run build.go ${OPT} build
CC=${CCX64} go run build.go "${OPT}" build
}
function build_backend() {
@@ -81,9 +77,9 @@ function build_backend() {
mkdir dist
fi
go run build.go -goarch armv6 -cc ${CCARMV6} ${OPT} build
go run build.go -goarch armv7 -cc ${CCARMV7} ${OPT} build
go run build.go -goarch arm64 -cc ${CCARM64} ${OPT} build
go run build.go -goarch armv6 -cc ${CCARMV6} "${OPT}" build
go run build.go -goarch armv7 -cc ${CCARMV7} "${OPT}" build
go run build.go -goarch arm64 -cc ${CCARM64} "${OPT}" build
build_backend_linux_amd64
}
@@ -93,22 +89,22 @@ function build_frontend() {
fi
yarn install --pure-lockfile --no-progress
echo "Building frontend"
go run build.go ${OPT} build-frontend
go run build.go "${OPT}" build-frontend
echo "FRONTEND: finished"
}
function package_linux_amd64() {
echo "Packaging Linux AMD64"
go run build.go -goos linux -pkg-arch amd64 ${OPT} package-only
go run build.go -goos linux -pkg-arch amd64 "${OPT}" package-only
go run build.go latest
echo "PACKAGE LINUX AMD64: finished"
}
function package_all() {
echo "Packaging ALL"
go run build.go -goos linux -pkg-arch armv6 ${OPT} -skipRpm package-only
go run build.go -goos linux -pkg-arch armv7 ${OPT} package-only
go run build.go -goos linux -pkg-arch arm64 ${OPT} package-only
go run build.go -goos linux -pkg-arch armv6 "${OPT}" -skipRpm package-only
go run build.go -goos linux -pkg-arch armv7 "${OPT}" package-only
go run build.go -goos linux -pkg-arch arm64 "${OPT}" package-only
package_linux_amd64
echo "PACKAGE ALL: finished"
}
@@ -119,8 +115,9 @@ function package_setup() {
rm -rf dist
fi
mkdir dist
go run build.go -gen-version ${OPT} > dist/grafana.version
go run build.go -gen-version "${OPT}" > dist/grafana.version
# Load ruby, needed for packing with fpm
# shellcheck disable=SC1091
source /etc/profile.d/rvm.sh
}
+1 -1
View File
@@ -1,5 +1,5 @@
#!/bin/bash
cd /tmp
cd /tmp || exit 1
tar xfJ x86_64-centos6-linux-gnu.tar.xz
tar xfJ osxcross.tar.xz
@@ -1,6 +1,6 @@
#!/bin/bash
set -e
WORKING_DIRECTORY=`pwd`
WORKING_DIRECTORY=$(pwd)
# copy zip file to /tmp/dist
mkdir -p /tmp/dist
cp ./dist/*.zip /tmp/dist
@@ -23,12 +23,12 @@ echo "Building MSI"
python3 generator/build.py "$@"
chmod a+x /tmp/scratch/*.msi
echo "MSI: Copy to $WORKING_DIRECTORY/dist"
cp /tmp/scratch/*.msi $WORKING_DIRECTORY/dist
cp /tmp/scratch/*.msi "$WORKING_DIRECTORY/dist"
echo "MSI: Generate SHA256"
MSI_FILE=`ls $WORKING_DIRECTORY/dist/*.msi`
SHA256SUM=`sha256sum $MSI_FILE | cut -f1 -d' '`
echo $SHA256SUM > $MSI_FILE.sha256
MSI_FILE=$(ls "$WORKING_DIRECTORY"/dist/*.msi)
SHA256SUM=$(sha256sum "$MSI_FILE" | cut -f1 -d' ')
echo "$SHA256SUM" > "$MSI_FILE.sha256"
echo "MSI: SHA256 file content:"
cat $MSI_FILE.sha256
cat "$MSI_FILE.sha256"
echo "MSI: contents of $WORKING_DIRECTORY/dist"
ls -al $WORKING_DIRECTORY/dist
ls -al "$WORKING_DIRECTORY/dist"
+1 -1
View File
@@ -21,7 +21,7 @@ ls -al /home/xclient/wix/light.exe.config
cat /home/xclient/wix/light.exe.config
cp /master/light.exe.config /home/xclient/wix/light.exe.config
cat /home/xclient/wix/light.exe.config
cd /master
cd /master || exit 1
echo "Building MSI"
python3 generator/build.py "$@"
#
+1 -1
View File
@@ -1,3 +1,3 @@
#!/bin/bash
cd /oss
cd /oss || exit 1
make
+1 -2
View File
@@ -2,7 +2,6 @@
cd ..
if [ -z "$CIRCLE_TAG" ]; then
_target="master"
else
@@ -11,5 +10,5 @@ fi
git clone -b "$_target" --single-branch git@github.com:grafana/grafana-enterprise.git --depth 1
cd grafana-enterprise
cd grafana-enterprise || exit
./build.sh
+6 -4
View File
@@ -2,6 +2,8 @@
# no relation to publish.go
# shellcheck disable=SC2124
EXTRA_OPTS="$@"
# Right now we hack this in into the publish script.
@@ -10,7 +12,7 @@ _releaseNoteUrl="https://community.grafana.com/t/release-notes-v6-3-x/19202"
_whatsNewUrl="https://grafana.com/docs/guides/whats-new-in-v6-3/"
./scripts/build/release_publisher/release_publisher \
--wn ${_whatsNewUrl} \
--rn ${_releaseNoteUrl} \
--version ${CIRCLE_TAG} \
--apikey ${GRAFANA_COM_API_KEY} ${EXTRA_OPTS}
--wn "${_whatsNewUrl}" \
--rn "${_releaseNoteUrl}" \
--version "${CIRCLE_TAG}" \
--apikey "${GRAFANA_COM_API_KEY}" "${EXTRA_OPTS}"
+1 -1
View File
@@ -8,5 +8,5 @@ cp ./scripts/build/rpmmacros ~/.rpmmacros
for package in dist/*.rpm; do
[ -e "$package" ] || continue
./scripts/build/sign_expect $GPG_KEY_PASSWORD $package
./scripts/build/sign_expect "$GPG_KEY_PASSWORD" "$package"
done
+3 -3
View File
@@ -9,7 +9,7 @@ GCP_REPO_BUCKET="${6:-grafana-repo}"
REPO="grafana"
if [ -z "$RELEASE_TYPE" -o -z "$GPG_PASS" -o -z "$DIST_PATH" ]; then
if [ -z "$RELEASE_TYPE" ] || [ -z "$GPG_PASS" ] || [ -z "$DIST_PATH" ]; then
echo "Both RELEASE_TYPE (arg 1), GPG_PASS (arg 2) and DIST_PATH (arg 4) has to be set"
exit 1
fi
@@ -36,7 +36,7 @@ mkdir -p /deb-repo/db \
gsutil -m rsync -r -d "gs://$GCP_DB_BUCKET/$RELEASE_TYPE" /deb-repo/db
# Add the new release to the repo
cp $DIST_PATH/*.deb /deb-repo/tmp
cp "$DIST_PATH"/*.deb /deb-repo/tmp
rm /deb-repo/tmp/grafana_latest*.deb || true
aptly repo add "$REPO" /deb-repo/tmp #adds too many packages in enterprise
@@ -64,5 +64,5 @@ gsutil -m rsync -r /deb-repo/repo/grafana/pool "gs://$GCP_REPO_BUCKET/$RELEASE_T
gsutil -m rsync -r -d /deb-repo/repo/grafana "gs://$GCP_REPO_BUCKET/$RELEASE_TYPE/deb"
# usage:
#
#
# deb https://packages.grafana.com/oss/deb stable main
+2 -2
View File
@@ -8,7 +8,7 @@ GCP_REPO_BUCKET="${5:-grafana-repo}"
REPO="rpm"
if [ -z "$RELEASE_TYPE" -o -z "$GPG_PASS" -o -z "$DIST_PATH" ]; then
if [ -z "$RELEASE_TYPE" ] || [ -z "$GPG_PASS" ] || [ -z "$DIST_PATH" ]; then
echo "Both RELEASE_TYPE (arg 1), GPG_PASS (arg 2) and DIST_PATH (arg 4) has to be set"
exit 1
fi
@@ -33,7 +33,7 @@ mkdir -p /rpm-repo
gsutil -m rsync -r "$BUCKET" /rpm-repo
# Add the new release to the repo
cp $DIST_PATH/*.rpm /rpm-repo # adds to many files for enterprise
cp "$DIST_PATH"/*.rpm /rpm-repo # adds to many files for enterprise
rm /rpm-repo/grafana-latest-1*.rpm || true
createrepo /rpm-repo
+5 -6
View File
@@ -1,17 +1,16 @@
#!/bin/bash
_files=$*
ALL_SIGNED=0
for file in $_files; do
rpm -K "$file" | grep "pgp.*OK" -q
if [[ $? != 0 ]]; then
ALL_SIGNED=1
echo $file NOT SIGNED
if rpm -K "$file" | grep "pgp.*OK" -q ; then
echo "$file" OK
else
echo $file OK
ALL_SIGNED=1
echo "$file" NOT SIGNED
fi
done
exit $ALL_SIGNED
+9 -9
View File
@@ -11,19 +11,19 @@ ERROR_COUNT="$(./node_modules/.bin/tsc --project tsconfig.json --noEmit --noImpl
DIRECTIVES="$(grep -r -o directive public/app/**/* | wc -l)"
CONTROLLERS="$(grep -r -oP 'class .*Ctrl' public/app/**/* | wc -l)"
if [ $ERROR_COUNT -gt $ERROR_COUNT_LIMIT ]; then
if [ "$ERROR_COUNT" -gt $ERROR_COUNT_LIMIT ]; then
echo -e "Typescript errors $ERROR_COUNT exceeded $ERROR_COUNT_LIMIT so failing build"
exit -1
exit 1
fi
if [ $DIRECTIVES -gt $DIRECTIVES_LIMIT ]; then
if [ "$DIRECTIVES" -gt $DIRECTIVES_LIMIT ]; then
echo -e "Directive count $DIRECTIVES exceeded $DIRECTIVES_LIMIT so failing build"
exit -1
exit 1
fi
if [ $CONTROLLERS -gt $CONTROLLERS_LIMIT ]; then
if [ "$CONTROLLERS" -gt $CONTROLLERS_LIMIT ]; then
echo -e "Controllers count $CONTROLLERS exceeded $CONTROLLERS_LIMIT so failing build"
exit -1
exit 1
fi
echo -e "Typescript errors: $ERROR_COUNT"
@@ -32,7 +32,7 @@ echo -e "Controllers: $CONTROLLERS"
if [ "${CIRCLE_BRANCH}" == "master" ]; then
./scripts/ci-metrics-publisher.sh \
grafana.ci-code.noImplicitAny=$ERROR_COUNT \
grafana.ci-code.directives=$DIRECTIVES \
grafana.ci-code.controllers=$CONTROLLERS
grafana.ci-code.noImplicitAny="$ERROR_COUNT" \
grafana.ci-code.directives="$DIRECTIVES" \
grafana.ci-code.controllers="$CONTROLLERS"
fi
+1 -1
View File
@@ -13,6 +13,6 @@ for ((i = 1; i <= $#; i++ )); do
data=''$data'{"name": "'${first}'", "value": '${remainder}', "interval": 60, "mtype": "gauge", "time": '$(date +%s)'}'
done
curl https://6371:$GRAFANA_MISC_STATS_API_KEY@graphite-us-central1.grafana.net/metrics \
curl "https://6371:$GRAFANA_MISC_STATS_API_KEY@graphite-us-central1.grafana.net/metrics" \
-H 'Content-type: application/json' \
-d "[$data]"
+4 -11
View File
@@ -1,14 +1,7 @@
#!/bin/bash
function exit_if_fail {
command=$@
echo "Executing '$command'"
eval $command
rc=$?
if [ $rc -ne 0 ]; then
echo "'$command' returned $rc."
exit $rc
fi
}
# shellcheck source=./scripts/helpers/exit-if-fail.sh
source "$(dirname "$0")/helpers/exit-if-fail.sh"
echo "building backend with install to cache pkgs"
exit_if_fail time go install ./pkg/cmd/grafana-server
@@ -16,5 +9,5 @@ exit_if_fail time go install ./pkg/cmd/grafana-server
echo "running go test"
set -e
time for d in $(go list ./pkg/...); do
exit_if_fail go test -tags=integration -covermode=atomic $d
exit_if_fail go test -tags=integration -covermode=atomic "$d"
done
+3 -10
View File
@@ -1,14 +1,7 @@
#!/bin/bash
function exit_if_fail {
command=$@
echo "Executing '$command'"
eval $command
rc=$?
if [ $rc -ne 0 ]; then
echo "'$command' returned $rc."
exit $rc
fi
}
# shellcheck source=./scripts/helpers/exit-if-fail.sh
source "$(dirname "$0")/helpers/exit-if-fail.sh"
echo "running redis and memcache tests"
+2 -10
View File
@@ -1,15 +1,7 @@
#!/bin/bash
function exit_if_fail {
command=$@
echo "Executing '$command'"
eval $command
rc=$?
if [ $rc -ne 0 ]; then
echo "'$command' returned $rc."
exit $rc
fi
}
# shellcheck source=./scripts/helpers/exit-if-fail.sh
source "$(dirname "$0")/helpers/exit-if-fail.sh"
start=$(date +%s)
+5 -12
View File
@@ -1,17 +1,10 @@
#!/bin/bash
function exit_if_fail {
command=$@
echo "Executing '$command'"
eval $command
rc=$?
if [ $rc -ne 0 ]; then
echo "'$command' returned $rc."
exit $rc
fi
}
# shellcheck source=./scripts/helpers/exit-if-fail.sh
source "$(dirname "$0")/helpers/exit-if-fail.sh"
export GRAFANA_TEST_DB=mysql
time for d in $(go list ./pkg/...); do
exit_if_fail go test -tags=integration $d
done
exit_if_fail go test -tags=integration "$d"
done
+5 -12
View File
@@ -1,17 +1,10 @@
#!/bin/bash
function exit_if_fail {
command=$@
echo "Executing '$command'"
eval $command
rc=$?
if [ $rc -ne 0 ]; then
echo "'$command' returned $rc."
exit $rc
fi
}
# shellcheck source=./scripts/helpers/exit-if-fail.sh
source "$(dirname "$0")/helpers/exit-if-fail.sh"
export GRAFANA_TEST_DB=postgres
time for d in $(go list ./pkg/...); do
exit_if_fail go test -tags=integration $d
done
exit_if_fail go test -tags=integration "$d"
done
+13
View File
@@ -0,0 +1,13 @@
#!/bin/bash
function exit_if_fail {
# shellcheck disable=SC2124
command=$@
echo "Executing '$command'"
eval "$command"
rc=$?
if [ $rc -ne 0 ]; then
echo "'$command' returned $rc."
exit $rc
fi
}
+5 -5
View File
@@ -6,12 +6,12 @@ set -e
_tag=$1
_branch="$(git rev-parse --abbrev-ref HEAD)"
if [ "${_tag}" == "" ]; then
if [ "${_tag}" == "" ]; then
echo "Missing version param. ex './scripts/tag_release.sh v5.1.1'"
exit 1
fi
if [ "${_branch}" == "master" ]; then
if [ "${_branch}" == "master" ]; then
echo "you cannot tag releases from the master branch"
echo "please checkout the release branch"
echo "ex 'git checkout v5.1.x'"
@@ -20,9 +20,9 @@ fi
# always make sure to pull latest changes from origin
echo "pulling latest changes from ${_branch}"
git pull origin ${_branch}
git pull origin "${_branch}"
# create signed tag for latest commit
# create signed tag for latest commit
git tag -s "${_tag}" -m "release ${_tag}"
# verify the signed tag
@@ -31,7 +31,7 @@ git tag -v "${_tag}"
echo "Make sure the tag is signed as expected"
echo "press [y] to push the tags"
read -n 1 confirm
read -n -r 1 confirm
if [ "${confirm}" == "y" ]; then
git push origin "${_branch}" --tags
+4 -4
View File
@@ -1,9 +1,9 @@
#!/bin/bash
#!/bin/bash
_circle_token=$1
_grafana_version=$2
trigger_build_url=https://circleci.com/api/v1/project/grafana/grafana-docker/tree/master?circle-token=${_circle_token}
trigger_build_url="https://circleci.com/api/v1/project/grafana/grafana-docker/tree/master?circle-token=${_circle_token}"
post_data=$(cat <<EOF
{
@@ -14,10 +14,10 @@ post_data=$(cat <<EOF
EOF
)
echo ${post_data}
echo "${post_data}"
curl \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--data "${post_data}" \
--request POST ${trigger_build_url}
--request POST "${trigger_build_url}"
+2 -2
View File
@@ -2,9 +2,9 @@
_circle_token=$1
trigger_build_url=https://circleci.com/api/v1/project/grafana/grafana-packer/tree/master?circle-token=${_circle_token}
trigger_build_url="https://circleci.com/api/v1/project/grafana/grafana-packer/tree/master?circle-token=${_circle_token}"
curl \
--header "Accept: application/json" \
--header "Content-Type: application/json" \
--request POST ${trigger_build_url}
--request POST "${trigger_build_url}"
+1 -1
View File
@@ -17,7 +17,7 @@ post_data=$(cat <<EOF
EOF
)
echo ${post_data}
echo "${post_data}"
curl \
--header "Accept: application/json" \
+15 -15
View File
@@ -6,49 +6,49 @@ docker_build () {
package=$3
tag=$4
docker build -f $dockerfile \
docker build -f "$dockerfile" \
--build-arg "REPO_CONFIG=$repo_file" \
--build-arg "PACKAGE=$package" \
--tag $tag \
--tag "$tag" \
--no-cache \
.
retval=$(docker run --rm $tag cat /usr/share/grafana/VERSION)
retval=$(docker run --rm "$tag" cat /usr/share/grafana/VERSION)
}
CHECK_BETA=$1
if [[ $CHECK_BETA == "beta" ]]; then
# Testing deb repos
docker_build "Dockerfile.deb" "deb-oss-beta.list" "grafana" "gf-oss-deb-repo-test"
_oss_deb_v=$retval
_oss_deb_v="$retval"
docker_build "Dockerfile.deb" "deb-ee-beta.list" "grafana-enterprise" "gf-ee-deb-repo-test"
_ee_deb_v=$retval
_ee_deb_v="$retval"
# Testing rpm repos
docker_build "Dockerfile.rpm" "rpm-oss-beta.list" "grafana" "gf-oss-rpm-repo-test"
_oss_rpm_v=$retval
_oss_rpm_v="$retval"
docker_build "Dockerfile.rpm" "rpm-ee-beta.list" "grafana-enterprise" "gf-ee-rpm-repo-test"
_ee_rpm_v=$retval
_ee_rpm_v="$retval"
else
# Testing deb repos
docker_build "Dockerfile.deb" "deb-oss-stable.list" "grafana" "gf-oss-deb-repo-test"
_oss_deb_v=$retval
_oss_deb_v="$retval"
docker_build "Dockerfile.deb" "deb-ee-stable.list" "grafana-enterprise" "gf-ee-deb-repo-test"
_ee_deb_v=$retval
_ee_deb_v="$retval"
# Testing rpm repos
docker_build "Dockerfile.rpm" "rpm-oss-stable.list" "grafana" "gf-oss-rpm-repo-test"
_oss_rpm_v=$retval
_oss_rpm_v="$retval"
docker_build "Dockerfile.rpm" "rpm-ee-stable.list" "grafana-enterprise" "gf-ee-rpm-repo-test"
_ee_rpm_v=$retval
_ee_rpm_v="$retval"
fi
echo Versions:
echo OSS deb = ${_oss_deb_v}
echo OSS rpm = ${_oss_rpm_v}
echo EE deb = ${_ee_deb_v}
echo EE rpm = ${_ee_rpm_v}
echo OSS deb = "${_oss_deb_v}"
echo OSS rpm = "${_oss_rpm_v}"
echo EE deb = "${_ee_deb_v}"
echo EE rpm = "${_ee_rpm_v}"