Browse Source

Grafana-CLI: Wrapper for `grafana-cli` within RPM/DEB packages and config/homepath are now global flags (#17695)

* Feature: Introduce a grafana-cli wrapper

When our users install the *nix packed version of grafana, tendency is to use the services and scripts installed as part of the package for grafana-server. These leverage the default configuration options by specifying the several default paths.

This introduces a similar approach for the grafana-cli binary. We exposed it through a wrapper to ensure a proper configuration is in place. To enable that, we add the .real suffix to the original binary (grafana-cli.real) and then use a bash script named grafana-cli as the wrapper.

* Make the config and homepath flags global

* Introduce `configOverrides` as a global flag

This flag allows us to pass configuration overrides as a string.

The string follows the convention of configuration arguments separated by a space e.g. "cfg:default.paths.data=/dev/nullX cfg:default.paths.logs=/dev/nullX"

Also, it is backwards compatible with similar the previous configuration method through tailing arguments. Tailing arguments take presedence over the configuration options string.

* Only log configuration information in debug mode

* Move the grafana-cli binary to $GRAFANA_HOME/bin

As part of the package install process, we copy all the release files and
directories into the grafana home directory. This includes the /bin folder
from where we copied the binaries into their respective destinations.
After that, the /bin folder gets deleted as we don't want to keep
duplicates of the binaries around.

As part of this commit, we moved the re-creation of /bin within
grafana-home and the copy of the original binary (again) after the
folder gets deleted.
gotjosh 6 years ago
parent
commit
2fb45eeec8

+ 35 - 18
build.go

@@ -43,7 +43,9 @@ var (
 	workingDir            string
 	workingDir            string
 	includeBuildId        bool     = true
 	includeBuildId        bool     = true
 	buildId               string   = "0"
 	buildId               string   = "0"
-	binaries              []string = []string{"grafana-server", "grafana-cli"}
+	serverBinary          string   = "grafana-server"
+	cliBinary             string   = "grafana-cli"
+	binaries              []string = []string{serverBinary, cliBinary}
 	isDev                 bool     = false
 	isDev                 bool     = false
 	enterprise            bool     = false
 	enterprise            bool     = false
 	skipRpmGen            bool     = false
 	skipRpmGen            bool     = false
@@ -230,6 +232,7 @@ type linuxPackageOptions struct {
 	packageType            string
 	packageType            string
 	packageArch            string
 	packageArch            string
 	homeDir                string
 	homeDir                string
+	homeBinDir             string
 	binPath                string
 	binPath                string
 	serverBinPath          string
 	serverBinPath          string
 	cliBinPath             string
 	cliBinPath             string
@@ -240,10 +243,11 @@ type linuxPackageOptions struct {
 	initdScriptFilePath    string
 	initdScriptFilePath    string
 	systemdServiceFilePath string
 	systemdServiceFilePath string
 
 
-	postinstSrc    string
-	initdScriptSrc string
-	defaultFileSrc string
-	systemdFileSrc string
+	postinstSrc         string
+	initdScriptSrc      string
+	defaultFileSrc      string
+	systemdFileSrc      string
+	cliBinaryWrapperSrc string
 
 
 	depends []string
 	depends []string
 }
 }
@@ -258,6 +262,7 @@ func createDebPackages() {
 		packageType:            "deb",
 		packageType:            "deb",
 		packageArch:            debPkgArch,
 		packageArch:            debPkgArch,
 		homeDir:                "/usr/share/grafana",
 		homeDir:                "/usr/share/grafana",
+		homeBinDir:             "/usr/share/grafana/bin",
 		binPath:                "/usr/sbin",
 		binPath:                "/usr/sbin",
 		configDir:              "/etc/grafana",
 		configDir:              "/etc/grafana",
 		etcDefaultPath:         "/etc/default",
 		etcDefaultPath:         "/etc/default",
@@ -265,10 +270,11 @@ func createDebPackages() {
 		initdScriptFilePath:    "/etc/init.d/grafana-server",
 		initdScriptFilePath:    "/etc/init.d/grafana-server",
 		systemdServiceFilePath: "/usr/lib/systemd/system/grafana-server.service",
 		systemdServiceFilePath: "/usr/lib/systemd/system/grafana-server.service",
 
 
-		postinstSrc:    "packaging/deb/control/postinst",
-		initdScriptSrc: "packaging/deb/init.d/grafana-server",
-		defaultFileSrc: "packaging/deb/default/grafana-server",
-		systemdFileSrc: "packaging/deb/systemd/grafana-server.service",
+		postinstSrc:         "packaging/deb/control/postinst",
+		initdScriptSrc:      "packaging/deb/init.d/grafana-server",
+		defaultFileSrc:      "packaging/deb/default/grafana-server",
+		systemdFileSrc:      "packaging/deb/systemd/grafana-server.service",
+		cliBinaryWrapperSrc: "packaging/wrappers/grafana-cli",
 
 
 		depends: []string{"adduser", "libfontconfig1"},
 		depends: []string{"adduser", "libfontconfig1"},
 	})
 	})
@@ -286,6 +292,7 @@ func createRpmPackages() {
 		packageType:            "rpm",
 		packageType:            "rpm",
 		packageArch:            rpmPkgArch,
 		packageArch:            rpmPkgArch,
 		homeDir:                "/usr/share/grafana",
 		homeDir:                "/usr/share/grafana",
+		homeBinDir:             "/usr/share/grafana/bin",
 		binPath:                "/usr/sbin",
 		binPath:                "/usr/sbin",
 		configDir:              "/etc/grafana",
 		configDir:              "/etc/grafana",
 		etcDefaultPath:         "/etc/sysconfig",
 		etcDefaultPath:         "/etc/sysconfig",
@@ -293,10 +300,11 @@ func createRpmPackages() {
 		initdScriptFilePath:    "/etc/init.d/grafana-server",
 		initdScriptFilePath:    "/etc/init.d/grafana-server",
 		systemdServiceFilePath: "/usr/lib/systemd/system/grafana-server.service",
 		systemdServiceFilePath: "/usr/lib/systemd/system/grafana-server.service",
 
 
-		postinstSrc:    "packaging/rpm/control/postinst",
-		initdScriptSrc: "packaging/rpm/init.d/grafana-server",
-		defaultFileSrc: "packaging/rpm/sysconfig/grafana-server",
-		systemdFileSrc: "packaging/rpm/systemd/grafana-server.service",
+		postinstSrc:         "packaging/rpm/control/postinst",
+		initdScriptSrc:      "packaging/rpm/init.d/grafana-server",
+		defaultFileSrc:      "packaging/rpm/sysconfig/grafana-server",
+		systemdFileSrc:      "packaging/rpm/systemd/grafana-server.service",
+		cliBinaryWrapperSrc: "packaging/wrappers/grafana-cli",
 
 
 		depends: []string{"/sbin/service", "fontconfig", "freetype", "urw-fonts"},
 		depends: []string{"/sbin/service", "fontconfig", "freetype", "urw-fonts"},
 	})
 	})
@@ -323,10 +331,12 @@ func createPackage(options linuxPackageOptions) {
 	runPrint("mkdir", "-p", filepath.Join(packageRoot, "/usr/lib/systemd/system"))
 	runPrint("mkdir", "-p", filepath.Join(packageRoot, "/usr/lib/systemd/system"))
 	runPrint("mkdir", "-p", filepath.Join(packageRoot, "/usr/sbin"))
 	runPrint("mkdir", "-p", filepath.Join(packageRoot, "/usr/sbin"))
 
 
-	// copy binary
-	for _, binary := range binaries {
-		runPrint("cp", "-p", filepath.Join(workingDir, "tmp/bin/"+binary), filepath.Join(packageRoot, "/usr/sbin/"+binary))
-	}
+	// copy grafana-cli wrapper
+	runPrint("cp", "-p", options.cliBinaryWrapperSrc, filepath.Join(packageRoot, "/usr/sbin/"+cliBinary))
+
+	// copy grafana-server binary
+	runPrint("cp", "-p", filepath.Join(workingDir, "tmp/bin/"+serverBinary), filepath.Join(packageRoot, "/usr/sbin/"+serverBinary))
+
 	// copy init.d script
 	// copy init.d script
 	runPrint("cp", "-p", options.initdScriptSrc, filepath.Join(packageRoot, options.initdScriptFilePath))
 	runPrint("cp", "-p", options.initdScriptSrc, filepath.Join(packageRoot, options.initdScriptFilePath))
 	// copy environment var file
 	// copy environment var file
@@ -338,6 +348,13 @@ func createPackage(options linuxPackageOptions) {
 	// remove bin path
 	// remove bin path
 	runPrint("rm", "-rf", filepath.Join(packageRoot, options.homeDir, "bin"))
 	runPrint("rm", "-rf", filepath.Join(packageRoot, options.homeDir, "bin"))
 
 
+	// create /bin within home
+	runPrint("mkdir", "-p", filepath.Join(packageRoot, options.homeBinDir))
+	// The grafana-cli binary is exposed through a wrapper to ensure a proper
+	// configuration is in place. To enable that, we need to store the original
+	// binary in a separate location to avoid conflicts.
+	runPrint("cp", "-p", filepath.Join(workingDir, "tmp/bin/"+cliBinary), filepath.Join(packageRoot, options.homeBinDir, cliBinary))
+
 	args := []string{
 	args := []string{
 		"-s", "dir",
 		"-s", "dir",
 		"--description", "Grafana",
 		"--description", "Grafana",
@@ -391,7 +408,7 @@ func createPackage(options linuxPackageOptions) {
 		args = append(args, "--iteration", linuxPackageIteration)
 		args = append(args, "--iteration", linuxPackageIteration)
 	}
 	}
 
 
-	// add dependenciesj
+	// add dependencies
 	for _, dep := range options.depends {
 	for _, dep := range options.depends {
 		args = append(args, "--depends", dep)
 		args = append(args, "--depends", dep)
 	}
 	}

+ 1 - 1
docs/sources/administration/cli.md

@@ -37,7 +37,7 @@ If running the command returns this error:
 
 
 then there are two flags that can be used to set homepath and the config file path.
 then there are two flags that can be used to set homepath and the config file path.
 
 
-`grafana-cli admin reset-admin-password --homepath "/usr/share/grafana" newpass`
+`grafana-cli --homepath "/usr/share/grafana" admin reset-admin-password newpass`
 
 
 If you have not lost the admin password then it is better to set in the Grafana UI. If you need to set the password in a script then the [Grafana API](http://docs.grafana.org/http_api/user/#change-password) can be used. Here is an example using curl with basic auth:
 If you have not lost the admin password then it is better to set in the Grafana UI. If you need to set the password in a script then the [Grafana API](http://docs.grafana.org/http_api/user/#change-password) can be used. Here is an example using curl with basic auth:
 
 

+ 39 - 0
packaging/wrappers/grafana-cli

@@ -0,0 +1,39 @@
+#! /usr/bin/env bash
+
+# Wrapper for the grafana-cli binary
+# This file serves as a wrapper for the grafana-cli binary. It ensures we set
+# the system-wide Grafana configuration that was bundled with the package as we
+# use the binary.
+
+DEFAULT=/etc/default/grafana
+
+GRAFANA_HOME=/usr/share/grafana
+CONF_DIR=/etc/grafana
+DATA_DIR=/var/lib/grafana
+PLUGINS_DIR=/var/lib/grafana/plugins
+LOG_DIR=/var/log/grafana
+
+CONF_FILE=$CONF_DIR/grafana.ini
+PROVISIONING_CFG_DIR=$CONF_DIR/provisioning
+
+EXECUTABLE=$GRAFANA_HOME/bin/grafana-cli
+
+if [ ! -x $EXECUTABLE ]; then
+ echo "Program not installed or not executable"
+ exit 5
+fi
+
+# overwrite settings from default file
+if [ -f "$DEFAULT" ]; then
+  . "$DEFAULT"
+fi
+
+OPTS="--homepath=${GRAFANA_HOME} \
+      --config=${CONF_FILE} \
+      --pluginsDir=${PLUGINS_DIR} \
+      --configOverrides='cfg:default.paths.provisioning=$PROVISIONING_CFG_DIR \
+                        cfg:default.paths.data=${DATA_DIR} \
+                        cfg:default.paths.logs=${LOG_DIR} \
+                        cfg:default.paths.plugins=${PLUGINS_DIR}'"
+
+eval $EXECUTABLE "$OPTS" "$@"

+ 9 - 17
pkg/cmd/grafana-cli/commands/commands.go

@@ -2,6 +2,7 @@ package commands
 
 
 import (
 import (
 	"os"
 	"os"
+	"strings"
 
 
 	"github.com/codegangsta/cli"
 	"github.com/codegangsta/cli"
 	"github.com/fatih/color"
 	"github.com/fatih/color"
@@ -16,16 +17,20 @@ import (
 func runDbCommand(command func(commandLine utils.CommandLine, sqlStore *sqlstore.SqlStore) error) func(context *cli.Context) {
 func runDbCommand(command func(commandLine utils.CommandLine, sqlStore *sqlstore.SqlStore) error) func(context *cli.Context) {
 	return func(context *cli.Context) {
 	return func(context *cli.Context) {
 		cmd := &utils.ContextCommandLine{Context: context}
 		cmd := &utils.ContextCommandLine{Context: context}
+		debug := cmd.GlobalBool("debug")
 
 
 		cfg := setting.NewCfg()
 		cfg := setting.NewCfg()
 
 
+		configOptions := strings.Split(cmd.GlobalString("configOverrides"), " ")
 		cfg.Load(&setting.CommandLineArgs{
 		cfg.Load(&setting.CommandLineArgs{
-			Config:   cmd.String("config"),
-			HomePath: cmd.String("homepath"),
-			Args:     context.Args(),
+			Config:   cmd.ConfigFile(),
+			HomePath: cmd.HomePath(),
+			Args:     append(configOptions, cmd.Args()...), // tailing arguments have precedence over the options string
 		})
 		})
 
 
-		cfg.LogConfigSources()
+		if debug {
+			cfg.LogConfigSources()
+		}
 
 
 		engine := &sqlstore.SqlStore{}
 		engine := &sqlstore.SqlStore{}
 		engine.Cfg = cfg
 		engine.Cfg = cfg
@@ -95,23 +100,11 @@ var pluginCommands = []cli.Command{
 	},
 	},
 }
 }
 
 
-var dbCommandFlags = []cli.Flag{
-	cli.StringFlag{
-		Name:  "homepath",
-		Usage: "path to grafana install/home path, defaults to working directory",
-	},
-	cli.StringFlag{
-		Name:  "config",
-		Usage: "path to config file",
-	},
-}
-
 var adminCommands = []cli.Command{
 var adminCommands = []cli.Command{
 	{
 	{
 		Name:   "reset-admin-password",
 		Name:   "reset-admin-password",
 		Usage:  "reset-admin-password <new password>",
 		Usage:  "reset-admin-password <new password>",
 		Action: runDbCommand(resetPasswordCommand),
 		Action: runDbCommand(resetPasswordCommand),
-		Flags:  dbCommandFlags,
 	},
 	},
 	{
 	{
 		Name:  "data-migration",
 		Name:  "data-migration",
@@ -121,7 +114,6 @@ var adminCommands = []cli.Command{
 				Name:   "encrypt-datasource-passwords",
 				Name:   "encrypt-datasource-passwords",
 				Usage:  "Migrates passwords from unsecured fields to secure_json_data field. Return ok unless there is an error. Safe to execute multiple times.",
 				Usage:  "Migrates passwords from unsecured fields to secure_json_data field. Return ok unless there is an error. Safe to execute multiple times.",
 				Action: runDbCommand(datamigrations.EncryptDatasourcePaswords),
 				Action: runDbCommand(datamigrations.EncryptDatasourcePaswords),
-				Flags:  dbCommandFlags,
 			},
 			},
 		},
 		},
 	},
 	},

+ 12 - 0
pkg/cmd/grafana-cli/main.go

@@ -51,6 +51,18 @@ func main() {
 			Name:  "debug, d",
 			Name:  "debug, d",
 			Usage: "enable debug logging",
 			Usage: "enable debug logging",
 		},
 		},
+		cli.StringFlag{
+			Name:  "configOverrides",
+			Usage: "configuration options to override defaults as a string. e.g. cfg:default.paths.log=/dev/null",
+		},
+		cli.StringFlag{
+			Name:  "homepath",
+			Usage: "path to grafana install/home path, defaults to working directory",
+		},
+		cli.StringFlag{
+			Name:  "config",
+			Usage: "path to config file",
+		},
 	}
 	}
 
 
 	app.Before = func(c *cli.Context) error {
 	app.Before = func(c *cli.Context) error {

+ 8 - 0
pkg/cmd/grafana-cli/utils/command_line.go

@@ -38,6 +38,10 @@ func (c *ContextCommandLine) Application() *cli.App {
 	return c.App
 	return c.App
 }
 }
 
 
+func (c *ContextCommandLine) HomePath() string { return c.GlobalString("homepath") }
+
+func (c *ContextCommandLine) ConfigFile() string { return c.GlobalString("config") }
+
 func (c *ContextCommandLine) PluginDirectory() string {
 func (c *ContextCommandLine) PluginDirectory() string {
 	return c.GlobalString("pluginsDir")
 	return c.GlobalString("pluginsDir")
 }
 }
@@ -49,3 +53,7 @@ func (c *ContextCommandLine) RepoDirectory() string {
 func (c *ContextCommandLine) PluginURL() string {
 func (c *ContextCommandLine) PluginURL() string {
 	return c.GlobalString("pluginUrl")
 	return c.GlobalString("pluginUrl")
 }
 }
+
+func (c *ContextCommandLine) OptionsString() string {
+	return c.GlobalString("configOverrides")
+}