dashfolders: merge conflict

This commit is contained in:
Daniel Lee
2018-01-25 14:54:50 +01:00
1824 changed files with 262501 additions and 173759 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ func init() {
OptionsTemplate: `
<h3 class="page-heading">Email addresses</h3>
<div class="gf-form">
<textarea rows="7" class="gf-form-input width-25" required ng-model="ctrl.model.settings.addresses"></textarea>
<textarea rows="7" class="gf-form-input width-27" required ng-model="ctrl.model.settings.addresses"></textarea>
</div>
<div class="gf-form">
<span>You can enter multiple email addresses using a ";" separator</span>
+12 -2
View File
@@ -23,6 +23,10 @@ func init() {
<span class="gf-form-label width-14">API Key</span>
<input type="text" required class="gf-form-input max-width-22" ng-model="ctrl.model.settings.apiKey" placeholder="OpsGenie API Key"></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-14">Alert API Url</span>
<input type="text" required class="gf-form-input max-width-22" ng-model="ctrl.model.settings.apiUrl" placeholder="https://api.opsgenie.com/v2/alerts"></input>
</div>
<div class="gf-form">
<gf-form-switch
class="gf-form"
@@ -43,13 +47,18 @@ var (
func NewOpsGenieNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
autoClose := model.Settings.Get("autoClose").MustBool(true)
apiKey := model.Settings.Get("apiKey").MustString()
apiUrl := model.Settings.Get("apiUrl").MustString()
if apiKey == "" {
return nil, alerting.ValidationError{Reason: "Could not find api key property in settings"}
}
if apiUrl == "" {
apiUrl = opsgenieAlertURL
}
return &OpsGenieNotifier{
NotifierBase: NewNotifierBase(model.Id, model.IsDefault, model.Name, model.Type, model.Settings),
ApiKey: apiKey,
ApiUrl: apiUrl,
AutoClose: autoClose,
log: log.New("alerting.notifier.opsgenie"),
}, nil
@@ -58,6 +67,7 @@ func NewOpsGenieNotifier(model *m.AlertNotification) (alerting.Notifier, error)
type OpsGenieNotifier struct {
NotifierBase
ApiKey string
ApiUrl string
AutoClose bool
log log.Logger
}
@@ -105,7 +115,7 @@ func (this *OpsGenieNotifier) createAlert(evalContext *alerting.EvalContext) err
body, _ := bodyJSON.MarshalJSON()
cmd := &m.SendWebhookSync{
Url: opsgenieAlertURL,
Url: this.ApiUrl,
Body: string(body),
HttpMethod: "POST",
HttpHeader: map[string]string{
@@ -129,7 +139,7 @@ func (this *OpsGenieNotifier) closeAlert(evalContext *alerting.EvalContext) erro
body, _ := bodyJSON.MarshalJSON()
cmd := &m.SendWebhookSync{
Url: fmt.Sprintf("%s/alertId-%d/close?identifierType=alias", opsgenieAlertURL, evalContext.Rule.Id),
Url: fmt.Sprintf("%s/alertId-%d/close?identifierType=alias", this.ApiUrl, evalContext.Rule.Id),
Body: string(body),
HttpMethod: "POST",
HttpHeader: map[string]string{
@@ -5,20 +5,25 @@ import (
"path/filepath"
"strings"
"github.com/grafana/grafana/pkg/log"
yaml "gopkg.in/yaml.v2"
)
type configReader struct {
path string
log log.Logger
}
func (cr *configReader) readConfig() ([]*DashboardsAsConfig, error) {
var dashboards []*DashboardsAsConfig
files, err := ioutil.ReadDir(cr.path)
if err != nil {
return nil, err
cr.log.Error("cant read dashboard provisioning files from directory", "path", cr.path)
return dashboards, nil
}
var dashboards []*DashboardsAsConfig
for _, file := range files {
if !strings.HasSuffix(file.Name(), ".yaml") && !strings.HasSuffix(file.Name(), ".yml") {
continue
@@ -30,13 +35,13 @@ func (cr *configReader) readConfig() ([]*DashboardsAsConfig, error) {
return nil, err
}
var datasource []*DashboardsAsConfig
err = yaml.Unmarshal(yamlFile, &datasource)
var dashCfg []*DashboardsAsConfig
err = yaml.Unmarshal(yamlFile, &dashCfg)
if err != nil {
return nil, err
}
dashboards = append(dashboards, datasource...)
dashboards = append(dashboards, dashCfg...)
}
for i := range dashboards {
@@ -3,6 +3,7 @@ package dashboards
import (
"testing"
"github.com/grafana/grafana/pkg/log"
. "github.com/smartystreets/goconvey/convey"
)
@@ -16,8 +17,8 @@ func TestDashboardsAsConfig(t *testing.T) {
Convey("Can read config file", func() {
cfgProvifer := configReader{path: simpleDashboardConfig}
cfg, err := cfgProvifer.readConfig()
cfgProvider := configReader{path: simpleDashboardConfig, log: log.New("test-logger")}
cfg, err := cfgProvider.readConfig()
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
@@ -33,7 +34,7 @@ func TestDashboardsAsConfig(t *testing.T) {
So(ds.Editable, ShouldBeTrue)
So(len(ds.Options), ShouldEqual, 1)
So(ds.Options["folder"], ShouldEqual, "/var/lib/grafana/dashboards")
So(ds.Options["path"], ShouldEqual, "/var/lib/grafana/dashboards")
ds2 := cfg[1]
@@ -44,19 +45,29 @@ func TestDashboardsAsConfig(t *testing.T) {
So(ds2.Editable, ShouldBeFalse)
So(len(ds2.Options), ShouldEqual, 1)
So(ds2.Options["folder"], ShouldEqual, "/var/lib/grafana/dashboards")
So(ds2.Options["path"], ShouldEqual, "/var/lib/grafana/dashboards")
})
Convey("Should skip broken config files", func() {
Convey("Should skip invalid path", func() {
cfgProvifer := configReader{path: brokenConfigs}
cfg, err := cfgProvifer.readConfig()
cfgProvider := configReader{path: "/invalid-directory", log: log.New("test-logger")}
cfg, err := cfgProvider.readConfig()
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
So(len(cfg), ShouldEqual, 0)
})
Convey("Should skip broken config files", func() {
cfgProvider := configReader{path: brokenConfigs, log: log.New("test-logger")}
cfg, err := cfgProvider.readConfig()
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
So(len(cfg), ShouldEqual, 0)
})
})
}
@@ -14,9 +14,10 @@ type DashboardProvisioner struct {
}
func Provision(ctx context.Context, configDirectory string) (*DashboardProvisioner, error) {
log := log.New("provisioning.dashboard")
d := &DashboardProvisioner{
cfgReader: &configReader{path: configDirectory},
log: log.New("provisioning.dashboard"),
cfgReader: &configReader{path: configDirectory, log: log},
log: log,
ctx: ctx,
}
@@ -34,9 +34,15 @@ type fileReader struct {
}
func NewDashboardFileReader(cfg *DashboardsAsConfig, log log.Logger) (*fileReader, error) {
path, ok := cfg.Options["folder"].(string)
var path string
path, ok := cfg.Options["path"].(string)
if !ok {
return nil, fmt.Errorf("Failed to load dashboards. folder param is not a string")
path, ok = cfg.Options["folder"].(string)
if !ok {
return nil, fmt.Errorf("Failed to load dashboards. path param is not a string")
}
log.Warn("[Deprecated] The folder property is deprecated. Please use path instead.")
}
if _, err := os.Stat(path); os.IsNotExist(err) {
@@ -145,6 +151,17 @@ func createWalkFn(fr *fileReader, folderId int64) filepath.WalkFunc {
return nil
}
checkFilepath, err := filepath.EvalSymlinks(path)
if path != checkFilepath {
path = checkFilepath
fi, err := os.Lstat(checkFilepath)
if err != nil {
return err
}
fileInfo = fi
}
cachedDashboard, exist := fr.cache.getCache(path)
if exist && cachedDashboard.UpdatedAt == fileInfo.ModTime() {
return nil
@@ -42,7 +42,7 @@ func TestDashboardFileReader(t *testing.T) {
}
Convey("Can read default dashboard", func() {
cfg.Options["folder"] = defaultDashboards
cfg.Options["path"] = defaultDashboards
cfg.Folder = "Team A"
reader, err := NewDashboardFileReader(cfg, logger)
@@ -67,7 +67,7 @@ func TestDashboardFileReader(t *testing.T) {
})
Convey("Should not update dashboards when db is newer", func() {
cfg.Options["folder"] = oneDashboard
cfg.Options["path"] = oneDashboard
fakeRepo.getDashboard = append(fakeRepo.getDashboard, &models.Dashboard{
Updated: time.Now().Add(time.Hour),
@@ -84,7 +84,7 @@ func TestDashboardFileReader(t *testing.T) {
})
Convey("Can read default dashboard and replace old version in database", func() {
cfg.Options["folder"] = oneDashboard
cfg.Options["path"] = oneDashboard
stat, _ := os.Stat(oneDashboard + "/dashboard1.json")
@@ -115,7 +115,7 @@ func TestDashboardFileReader(t *testing.T) {
})
Convey("Broken dashboards should not cause error", func() {
cfg.Options["folder"] = brokenDashboards
cfg.Options["path"] = brokenDashboards
_, err := NewDashboardFileReader(cfg, logger)
So(err, ShouldBeNil)
@@ -167,7 +167,7 @@ func TestDashboardFileReader(t *testing.T) {
OrgId: 1,
Folder: "",
Options: map[string]interface{}{
"folder": defaultDashboards,
"path": defaultDashboards,
},
}
@@ -184,6 +184,30 @@ func TestDashboardFileReader(t *testing.T) {
So(shouldSkip, ShouldBeNil)
})
})
Convey("Can use bpth path and folder as dashboard path", func() {
cfg := &DashboardsAsConfig{
Name: "Default",
Type: "file",
OrgId: 1,
Folder: "",
Options: map[string]interface{}{},
}
Convey("using path parameter", func() {
cfg.Options["path"] = defaultDashboards
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"))
So(err, ShouldBeNil)
So(reader.Path, ShouldEqual, defaultDashboards)
})
Convey("using folder as options", func() {
cfg.Options["folder"] = defaultDashboards
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"))
So(err, ShouldBeNil)
So(reader.Path, ShouldEqual, defaultDashboards)
})
})
})
}
@@ -4,9 +4,9 @@
editable: true
type: file
options:
folder: /var/lib/grafana/dashboards
path: /var/lib/grafana/dashboards
- name: 'default'
type: file
options:
folder: /var/lib/grafana/dashboards
path: /var/lib/grafana/dashboards
@@ -25,13 +25,13 @@ func Provision(configDirectory string) error {
type DatasourceProvisioner struct {
log log.Logger
cfgProvider configReader
cfgProvider *configReader
}
func newDatasourceProvisioner(log log.Logger) DatasourceProvisioner {
return DatasourceProvisioner{
log: log,
cfgProvider: configReader{},
cfgProvider: &configReader{log: log},
}
}
@@ -95,15 +95,19 @@ func (dc *DatasourceProvisioner) deleteDatasources(dsToDelete []*DeleteDatasourc
return nil
}
type configReader struct{}
type configReader struct {
log log.Logger
}
func (cr *configReader) readConfig(path string) ([]*DatasourcesAsConfig, error) {
var datasources []*DatasourcesAsConfig
func (configReader) readConfig(path string) ([]*DatasourcesAsConfig, error) {
files, err := ioutil.ReadDir(path)
if err != nil {
return nil, err
cr.log.Error("cant read datasource provisioning files from directory", "path", path)
return datasources, nil
}
var datasources []*DatasourcesAsConfig
for _, file := range files {
if strings.HasSuffix(file.Name(), ".yaml") || strings.HasSuffix(file.Name(), ".yml") {
filename, _ := filepath.Abs(filepath.Join(path, file.Name()))
@@ -11,7 +11,7 @@ import (
)
var (
logger log.Logger = log.New("fake.logger")
logger log.Logger = log.New("fake.log")
oneDatasourcesConfig string = ""
twoDatasourcesConfig string = "./test-configs/two-datasources"
twoDatasourcesConfigPurgeOthers string = "./test-configs/insert-two-delete-two"
@@ -115,12 +115,23 @@ func TestDatasourceAsConfig(t *testing.T) {
})
Convey("broken yaml should return error", func() {
_, err := configReader{}.readConfig(brokenYaml)
reader := &configReader{}
_, err := reader.readConfig(brokenYaml)
So(err, ShouldNotBeNil)
})
Convey("skip invalid directory", func() {
cfgProvifer := &configReader{log: log.New("test logger")}
cfg, err := cfgProvifer.readConfig("./invalid-directory")
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
So(len(cfg), ShouldEqual, 0)
})
Convey("can read all properties", func() {
cfgProvifer := configReader{}
cfgProvifer := &configReader{log: log.New("test logger")}
cfg, err := cfgProvifer.readConfig(allProperties)
if err != nil {
t.Fatalf("readConfig return an error %v", err)
+4 -4
View File
@@ -24,7 +24,7 @@ func init() {
func GetAlertById(query *m.GetAlertByIdQuery) error {
alert := m.Alert{}
has, err := x.Id(query.Id).Get(&alert)
has, err := x.ID(query.Id).Get(&alert)
if !has {
return fmt.Errorf("could not find alert")
}
@@ -113,7 +113,7 @@ func HandleAlertsQuery(query *m.GetAlertsQuery) error {
}
alerts := make([]*m.Alert, 0)
if err := x.Sql(sql.String(), params...).Find(&alerts); err != nil {
if err := x.SQL(sql.String(), params...).Find(&alerts); err != nil {
return err
}
@@ -260,7 +260,7 @@ func SetAlertState(cmd *m.SetAlertStateCommand) error {
alert.ExecutionError = cmd.Error
}
sess.Id(alert.Id).Update(&alert)
sess.ID(alert.Id).Update(&alert)
return nil
})
}
@@ -324,7 +324,7 @@ func GetAlertStatesForDashboard(query *m.GetAlertStatesForDashboardQuery) error
WHERE org_id = ? AND dashboard_id = ?`
query.Result = make([]*m.AlertStateInfoDTO, 0)
err := x.Sql(rawSql, query.OrgId, query.DashboardId).Find(&query.Result)
err := x.SQL(rawSql, query.OrgId, query.DashboardId).Find(&query.Result)
return err
}
+3 -3
View File
@@ -76,7 +76,7 @@ func GetAlertNotificationsToSend(query *m.GetAlertNotificationsToSendQuery) erro
sql.WriteString(`)`)
results := make([]*m.AlertNotification, 0)
if err := x.Sql(sql.String(), params...).Find(&results); err != nil {
if err := x.SQL(sql.String(), params...).Find(&results); err != nil {
return err
}
@@ -165,7 +165,7 @@ func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error {
return inTransaction(func(sess *DBSession) (err error) {
current := m.AlertNotification{}
if _, err = sess.Id(cmd.Id).Get(&current); err != nil {
if _, err = sess.ID(cmd.Id).Get(&current); err != nil {
return err
}
@@ -187,7 +187,7 @@ func UpdateAlertNotification(cmd *m.UpdateAlertNotificationCommand) error {
sess.UseBool("is_default")
if affected, err := sess.Id(cmd.Id).Update(current); err != nil {
if affected, err := sess.ID(cmd.Id).Update(current); err != nil {
return err
} else if affected == 0 {
return fmt.Errorf("Could not find alert notification")
+1
View File
@@ -176,6 +176,7 @@ func GetDashboardAclInfoList(query *m.GetDashboardAclInfoListQuery) error {
folder.has_acl = ` + dialect.BooleanStr(false) + `
) AND
da.dashboard_id = -1
ORDER BY 1 ASC
`
query.Result = make([]*m.DashboardAclInfoDTO, 0)
+3 -6
View File
@@ -17,15 +17,13 @@ func init() {
}
func CreatePlaylist(cmd *m.CreatePlaylistCommand) error {
var err error
playlist := m.Playlist{
Name: cmd.Name,
Interval: cmd.Interval,
OrgId: cmd.OrgId,
}
_, err = x.Insert(&playlist)
_, err := x.Insert(&playlist)
fmt.Printf("%v", playlist.Id)
@@ -47,7 +45,6 @@ func CreatePlaylist(cmd *m.CreatePlaylistCommand) error {
}
func UpdatePlaylist(cmd *m.UpdatePlaylistCommand) error {
var err error
playlist := m.Playlist{
Id: cmd.Id,
OrgId: cmd.OrgId,
@@ -68,7 +65,7 @@ func UpdatePlaylist(cmd *m.UpdatePlaylistCommand) error {
Interval: playlist.Interval,
}
_, err = x.Id(cmd.Id).Cols("id", "name", "interval").Update(&playlist)
_, err := x.ID(cmd.Id).Cols("id", "name", "interval").Update(&playlist)
if err != nil {
return err
@@ -104,7 +101,7 @@ func GetPlaylist(query *m.GetPlaylistByIdQuery) error {
}
playlist := m.Playlist{}
_, err := x.Id(query.Id).Get(&playlist)
_, err := x.ID(query.Id).Get(&playlist)
query.Result = &playlist
+64 -61
View File
@@ -18,7 +18,7 @@ var activeUserTimeLimit time.Duration = time.Hour * 24 * 30
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)
err := x.Sql(rawSql).Find(&query.Result)
err := x.SQL(rawSql).Find(&query.Result)
if err != nil {
return err
}
@@ -30,36 +30,39 @@ func GetSystemStats(query *m.GetSystemStatsQuery) error {
var rawSql = `SELECT
(
SELECT COUNT(*)
FROM ` + dialect.Quote("user") + `
) AS users,
FROM ` + dialect.Quote("user") + `
) AS users,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("org") + `
) AS orgs,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("dashboard") + `
) AS dashboards,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("data_source") + `
) AS datasources,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("playlist") + `
) AS playlists,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("alert") + `
) AS alerts,
FROM ` + dialect.Quote("org") + `
) AS orgs,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("dashboard") + `
) AS dashboards,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("data_source") + `
) AS datasources,
(
SELECT COUNT(*) FROM ` + dialect.Quote("star") + `
) AS stars,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("playlist") + `
) AS playlists,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("alert") + `
) AS alerts,
(
SELECT COUNT(*) FROM ` + dialect.Quote("user") + ` where last_seen_at > ?
) as active_users
) as active_users
`
activeUserDeadlineDate := time.Now().Add(-activeUserTimeLimit)
var stats m.SystemStats
_, err := x.Sql(rawSql, activeUserDeadlineDate).Get(&stats)
_, err := x.SQL(rawSql, activeUserDeadlineDate).Get(&stats)
if err != nil {
return err
}
@@ -70,51 +73,51 @@ func GetSystemStats(query *m.GetSystemStatsQuery) error {
func GetAdminStats(query *m.GetAdminStatsQuery) error {
var rawSql = `SELECT
(
SELECT COUNT(*)
FROM ` + dialect.Quote("user") + `
) AS users,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("org") + `
) AS orgs,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("dashboard") + `
) AS dashboards,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("dashboard_snapshot") + `
) AS snapshots,
(
SELECT COUNT( DISTINCT ( ` + dialect.Quote("term") + ` ))
FROM ` + dialect.Quote("dashboard_tag") + `
) AS tags,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("data_source") + `
) AS datasources,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("playlist") + `
) AS playlists,
(
SELECT COUNT(*) FROM ` + dialect.Quote("star") + `
) AS stars,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("alert") + `
) AS alerts,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("user") + `
) AS users,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("org") + `
) AS orgs,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("dashboard") + `
) AS dashboards,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("dashboard_snapshot") + `
) AS snapshots,
(
SELECT COUNT( DISTINCT ( ` + dialect.Quote("term") + ` ))
FROM ` + dialect.Quote("dashboard_tag") + `
) AS tags,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("data_source") + `
) AS datasources,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("playlist") + `
) AS playlists,
(
SELECT COUNT(*) FROM ` + dialect.Quote("star") + `
) AS stars,
(
SELECT COUNT(*)
FROM ` + dialect.Quote("alert") + `
) AS alerts,
(
SELECT COUNT(*)
from ` + dialect.Quote("user") + ` where last_seen_at > ?
from ` + dialect.Quote("user") + ` where last_seen_at > ?
) as active_users
`
`
activeUserDeadlineDate := time.Now().Add(-activeUserTimeLimit)
var stats m.AdminStats
_, err := x.Sql(rawSql, activeUserDeadlineDate).Get(&stats)
_, err := x.SQL(rawSql, activeUserDeadlineDate).Get(&stats)
if err != nil {
return err
}