Browse Source

Add simple sync mode

Brendan Abolivier 1 year ago
parent
commit
f9feb263c5
Signed by: Brendan Abolivier <contact@brendanabolivier.com> GPG key ID: 8EF1500759F70623
6 changed files with 117 additions and 37 deletions
  1. 17
    1
      config.example.yaml
  2. 21
    4
      src/config/config.go
  3. 2
    2
      src/git/git.go
  4. 12
    0
      src/puller/main.go
  5. 59
    30
      src/puller/puller.go
  6. 6
    0
      src/pusher/main.go

+ 17
- 1
config.example.yaml View File

@@ -10,6 +10,7 @@ grafana:
10 10
     # case-insensitive and optional.
11 11
     ignore_prefix: test
12 12
 
13
+
13 14
 # Settings to interact with the Git repository. Currently only SSH repos are
14 15
 # supported.
15 16
 git:
@@ -33,7 +34,22 @@ git:
33 34
         # Author's email.
34 35
         email: grafana-dashboard-manager@company.tld
35 36
 
36
-# Configuration for the Git -> Grafana pusher.
37
+# An alternative to Git synchronisation is the "simple sync" mode. This will
38
+# only back up your dashboards on the disk and won't do anything else.
39
+# Here is an example of the synchronisation for the simple sync mode:
40
+#
41
+#   simple_sync:
42
+#       sync_path: /etc/grafana-dashboards
43
+#
44
+# Note that if Git settings are supplied, the settings there will be used even
45
+# if there are settings for the "simple sync" mode. In this case, if settings for
46
+# the "simple sync" mode are supplied, they will be ignored by the configuration.
47
+# Note also that the "simple sync" mode doesn't work with the pusher, which needs
48
+# Git settings to work.
49
+
50
+
51
+# Configuration for the Git -> Grafana pusher. Optional (only required if you
52
+# try to run the pusher).
37 53
 pusher:
38 54
     # Mode which will define how the pusher will sync with the Git remote.
39 55
     # Currently, only two modes are supported:

+ 21
- 4
src/config/config.go View File

@@ -13,14 +13,16 @@ import (
13 13
 var (
14 14
 	ErrPusherInvalidSyncMode   = errors.New("Invalid sync mode in the pusher settings")
15 15
 	ErrPusherConfigNotMatching = errors.New("The pusher config doesn't match with the one expected from the pusher sync mode")
16
+	ErrNoSyncSettings          = errors.New("At least one of the simple_sync or the git settings must be set")
16 17
 )
17 18
 
18 19
 // Config is the Go representation of the configuration file. It is filled when
19 20
 // parsing the said file.
20 21
 type Config struct {
21
-	Grafana GrafanaSettings `yaml:"grafana"`
22
-	Git     GitSettings     `yaml:"git"`
23
-	Pusher  PusherSettings  `yaml:"pusher"`
22
+	Grafana    GrafanaSettings     `yaml:"grafana"`
23
+	SimpleSync *SimpleSyncSettings `yaml:"simple_sync,omitempty"`
24
+	Git        *GitSettings        `yaml:"git,omitempty"`
25
+	Pusher     *PusherSettings     `yaml:"pusher,omitempty"`
24 26
 }
25 27
 
26 28
 // GrafanaSettings contains the data required to talk to the Grafana HTTP API.
@@ -30,6 +32,14 @@ type GrafanaSettings struct {
30 32
 	IgnorePrefix string `yaml:"ignore_prefix,omitempty"`
31 33
 }
32 34
 
35
+// SimpleSyncSettings contains minimal data on the synchronisation process. It is
36
+// expected to be found if there is no Git settings.
37
+// If both simple sync settings and Git settings are found, the Git settings
38
+// will be used.
39
+type SimpleSyncSettings struct {
40
+	SyncPath string `yaml:"sync_path"`
41
+}
42
+
33 43
 // GitSettings contains the data required to interact with the Git repository.
34 44
 type GitSettings struct {
35 45
 	URL            string              `yaml:"url"`
@@ -82,6 +92,13 @@ func Load(filename string) (cfg *Config, err error) {
82 92
 	if err = yaml.Unmarshal(rawCfg, cfg); err != nil {
83 93
 		return
84 94
 	}
95
+
96
+	// Check if at least one settings group exists for synchronisation settings.
97
+	if cfg.Git == nil && cfg.SimpleSync == nil {
98
+		err = ErrNoSyncSettings
99
+		return
100
+	}
101
+
85 102
 	// Since we always compare the prefix against a slug, we need to make sure
86 103
 	// the prefix is a slug itself.
87 104
 	cfg.Grafana.IgnorePrefix = slug.Make(cfg.Grafana.IgnorePrefix)
@@ -95,7 +112,7 @@ func Load(filename string) (cfg *Config, err error) {
95 112
 // Returns an error if the sync mode isn't in the allowed modes, or if at least
96 113
 // one of the fields expected to hold a non-zero-value holds the zero-value for
97 114
 // its type.
98
-func validatePusherSettings(cfg PusherSettings) error {
115
+func validatePusherSettings(cfg *PusherSettings) error {
99 116
 	config := cfg.Config
100 117
 	var configValid bool
101 118
 	switch cfg.Mode {

+ 2
- 2
src/git/git.go View File

@@ -22,7 +22,7 @@ import (
22 22
 // authentication data needed to talk to the Git remote.
23 23
 type Repository struct {
24 24
 	Repo *gogit.Repository
25
-	cfg  config.GitSettings
25
+	cfg  *config.GitSettings
26 26
 	auth *gitssh.PublicKeys
27 27
 }
28 28
 
@@ -32,7 +32,7 @@ type Repository struct {
32 32
 // and needs the repository to be cloned from remote before it is usable.
33 33
 // Returns an error if there was an issue opening the clone path or loading
34 34
 // authentication data.
35
-func NewRepository(cfg config.GitSettings) (r *Repository, invalidRepo bool, err error) {
35
+func NewRepository(cfg *config.GitSettings) (r *Repository, invalidRepo bool, err error) {
36 36
 	// Load the repository.
37 37
 	repo, err := gogit.PlainOpen(cfg.ClonePath)
38 38
 	if err != nil {

+ 12
- 0
src/puller/main.go View File

@@ -25,6 +25,18 @@ func main() {
25 25
 		logrus.Panic(err)
26 26
 	}
27 27
 
28
+	// Tell the user which sync mode we use.
29
+	var syncMode string
30
+	if cfg.Git != nil {
31
+		syncMode = "git"
32
+	} else {
33
+		syncMode = "simple"
34
+	}
35
+
36
+	logrus.WithFields(logrus.Fields{
37
+		"sync_mode": syncMode,
38
+	}).Info("Sync mode set")
39
+
28 40
 	// Initialise the Grafana API client.
29 41
 	client := grafana.NewClient(cfg.Grafana.BaseURL, cfg.Grafana.APIKey)
30 42
 	// Run the puller.

+ 59
- 30
src/puller/puller.go View File

@@ -25,20 +25,33 @@ type diffVersion struct {
25 25
 // which name starts with "test", then commits each of them to Git except for
26 26
 // those that have a newer or equal version number already versionned in the
27 27
 // repo.
28
-func PullGrafanaAndCommit(client *grafana.Client, cfg *config.Config) error {
29
-	// Clone or pull the repo
30
-	repo, _, err := git.NewRepository(cfg.Git)
31
-	if err != nil {
32
-		return err
33
-	}
28
+func PullGrafanaAndCommit(client *grafana.Client, cfg *config.Config) (err error) {
29
+	var repo *git.Repository
30
+	var w *gogit.Worktree
31
+	var syncPath string
32
+
33
+	// Only do Git stuff if there's a configuration for that. On "simple sync"
34
+	// mode, we don't need do do any versioning.
35
+	// We need to set syncPath accordingly, though, because we use it later.
36
+	if cfg.Git != nil {
37
+		syncPath = cfg.Git.ClonePath
38
+
39
+		// Clone or pull the repo
40
+		repo, _, err = git.NewRepository(cfg.Git)
41
+		if err != nil {
42
+			return err
43
+		}
34 44
 
35
-	if err = repo.Sync(false); err != nil {
36
-		return err
37
-	}
45
+		if err = repo.Sync(false); err != nil {
46
+			return err
47
+		}
38 48
 
39
-	w, err := repo.Repo.Worktree()
40
-	if err != nil {
41
-		return err
49
+		w, err = repo.Repo.Worktree()
50
+		if err != nil {
51
+			return err
52
+		}
53
+	} else {
54
+		syncPath = cfg.SimpleSync.SyncPath
42 55
 	}
43 56
 
44 57
 	// Get URIs for all known dashboards
@@ -52,7 +65,7 @@ func PullGrafanaAndCommit(client *grafana.Client, cfg *config.Config) error {
52 65
 
53 66
 	// Load versions
54 67
 	logrus.Info("Getting local dashboard versions")
55
-	dbVersions, err := getDashboardsVersions(cfg.Git.ClonePath)
68
+	dbVersions, err := getDashboardsVersions(syncPath)
56 69
 	if err != nil {
57 70
 		return err
58 71
 	}
@@ -96,7 +109,7 @@ func PullGrafanaAndCommit(client *grafana.Client, cfg *config.Config) error {
96 109
 			}).Info("Grafana has a newer version, updating")
97 110
 
98 111
 			if err = addDashboardChangesToRepo(
99
-				dashboard, cfg.Git.ClonePath, w,
112
+				dashboard, syncPath, w,
100 113
 			); err != nil {
101 114
 				return err
102 115
 			}
@@ -112,24 +125,36 @@ func PullGrafanaAndCommit(client *grafana.Client, cfg *config.Config) error {
112 125
 		}
113 126
 	}
114 127
 
115
-	status, err := w.Status()
116
-	if err != nil {
117
-		return err
118
-	}
128
+	// Only do Git stuff if there's a configuration for that. On "simple sync"
129
+	// mode, we don't need do do any versioning.
130
+	if cfg.Git != nil {
131
+		var status gogit.Status
132
+		status, err = w.Status()
133
+		if err != nil {
134
+			return err
135
+		}
119 136
 
120
-	// Check if there's uncommited changes, and if that's the case, commit them.
121
-	if !status.IsClean() {
122
-		logrus.Info("Comitting changes")
137
+		// Check if there's uncommited changes, and if that's the case, commit
138
+		// them.
139
+		if !status.IsClean() {
140
+			logrus.Info("Comitting changes")
123 141
 
124
-		if err = commitNewVersions(dbVersions, dv, w, cfg); err != nil {
125
-			return err
142
+			if err = commitNewVersions(dbVersions, dv, w, cfg); err != nil {
143
+				return err
144
+			}
126 145
 		}
127
-	}
128 146
 
129
-	// Push the changes (we don't do it in the if clause above in case there are
130
-	// pending commits in the local repo that haven't been pushed yet).
131
-	if err = repo.Push(); err != nil {
132
-		return err
147
+		// Push the changes (we don't do it in the if clause above in case there
148
+		// are pending commits in the local repo that haven't been pushed yet).
149
+		if err = repo.Push(); err != nil {
150
+			return err
151
+		}
152
+	} else {
153
+		// If we're on simple sync mode, write versions and don't do anything
154
+		// else.
155
+		if err = writeVersions(dbVersions, dv, syncPath); err != nil {
156
+			return err
157
+		}
133 158
 	}
134 159
 
135 160
 	return nil
@@ -146,8 +171,12 @@ func addDashboardChangesToRepo(
146 171
 		return err
147 172
 	}
148 173
 
149
-	if _, err := worktree.Add(slugExt); err != nil {
150
-		return err
174
+	// If worktree is nil, it means that it hasn't been initialised, which means
175
+	// the sync mode is "simple sync" and not Git.
176
+	if worktree != nil {
177
+		if _, err := worktree.Add(slugExt); err != nil {
178
+			return err
179
+		}
151 180
 	}
152 181
 
153 182
 	return nil

+ 6
- 0
src/pusher/main.go View File

@@ -2,6 +2,7 @@ package main
2 2
 
3 3
 import (
4 4
 	"flag"
5
+	"os"
5 6
 
6 7
 	"config"
7 8
 	"grafana"
@@ -33,6 +34,11 @@ func main() {
33 34
 		logrus.Panic(err)
34 35
 	}
35 36
 
37
+	if cfg.Git == nil || cfg.Pusher == nil {
38
+		logrus.Info("The git configuration or the pusher configuration (or both) is not defined in the configuration file. The pusher cannot start unless both are defined.")
39
+		os.Exit(0)
40
+	}
41
+
36 42
 	// Initialise the Grafana API client.
37 43
 	grafanaClient := grafana.NewClient(cfg.Grafana.BaseURL, cfg.Grafana.APIKey)
38 44