瀏覽代碼

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 年之前
父節點
當前提交
2fb45eeec8

+ 35 - 18
build.go

@@ -43,7 +43,9 @@ var (
 	workingDir            string
 	includeBuildId        bool     = true
 	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
 	enterprise            bool     = false
 	skipRpmGen            bool     = false
@@ -230,6 +232,7 @@ type linuxPackageOptions struct {
 	packageType            string
 	packageArch            string
 	homeDir                string
+	homeBinDir             string
 	binPath                string
 	serverBinPath          string
 	cliBinPath             string
@@ -240,10 +243,11 @@ type linuxPackageOptions struct {
 	initdScriptFilePath    string
 	systemdServiceFilePath string
 
-	postinstSrc    string
-	initdScriptSrc string
-	defaultFileSrc string
-	systemdFileSrc string
+	postinstSrc         string
+	initdScriptSrc      string
+	defaultFileSrc      string
+	systemdFileSrc      string
+	cliBinaryWrapperSrc string
 
 	depends []string
 }
@@ -258,6 +262,7 @@ func createDebPackages() {
 		packageType:            "deb",
 		packageArch:            debPkgArch,
 		homeDir:                "/usr/share/grafana",
+		homeBinDir:             "/usr/share/grafana/bin",
 		binPath:                "/usr/sbin",
 		configDir:              "/etc/grafana",
 		etcDefaultPath:         "/etc/default",
@@ -265,10 +270,11 @@ func createDebPackages() {
 		initdScriptFilePath:    "/etc/init.d/grafana-server",
 		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"},
 	})
@@ -286,6 +292,7 @@ func createRpmPackages() {
 		packageType:            "rpm",
 		packageArch:            rpmPkgArch,
 		homeDir:                "/usr/share/grafana",
+		homeBinDir:             "/usr/share/grafana/bin",
 		binPath:                "/usr/sbin",
 		configDir:              "/etc/grafana",
 		etcDefaultPath:         "/etc/sysconfig",
@@ -293,10 +300,11 @@ func createRpmPackages() {
 		initdScriptFilePath:    "/etc/init.d/grafana-server",
 		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"},
 	})
@@ -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/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
 	runPrint("cp", "-p", options.initdScriptSrc, filepath.Join(packageRoot, options.initdScriptFilePath))
 	// copy environment var file
@@ -338,6 +348,13 @@ func createPackage(options linuxPackageOptions) {
 	// remove bin path
 	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{
 		"-s", "dir",
 		"--description", "Grafana",
@@ -391,7 +408,7 @@ func createPackage(options linuxPackageOptions) {
 		args = append(args, "--iteration", linuxPackageIteration)
 	}
 
-	// add dependenciesj
+	// add dependencies
 	for _, dep := range options.depends {
 		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.
 
-`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:
 

+ 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 (
 	"os"
+	"strings"
 
 	"github.com/codegangsta/cli"
 	"github.com/fatih/color"
@@ -16,16 +17,20 @@ import (
 func runDbCommand(command func(commandLine utils.CommandLine, sqlStore *sqlstore.SqlStore) error) func(context *cli.Context) {
 	return func(context *cli.Context) {
 		cmd := &utils.ContextCommandLine{Context: context}
+		debug := cmd.GlobalBool("debug")
 
 		cfg := setting.NewCfg()
 
+		configOptions := strings.Split(cmd.GlobalString("configOverrides"), " ")
 		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.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{
 	{
 		Name:   "reset-admin-password",
 		Usage:  "reset-admin-password <new password>",
 		Action: runDbCommand(resetPasswordCommand),
-		Flags:  dbCommandFlags,
 	},
 	{
 		Name:  "data-migration",
@@ -121,7 +114,6 @@ var adminCommands = []cli.Command{
 				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.",
 				Action: runDbCommand(datamigrations.EncryptDatasourcePaswords),
-				Flags:  dbCommandFlags,
 			},
 		},
 	},

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

@@ -51,6 +51,18 @@ func main() {
 			Name:  "debug, d",
 			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 {

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

@@ -38,6 +38,10 @@ func (c *ContextCommandLine) Application() *cli.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 {
 	return c.GlobalString("pluginsDir")
 }
@@ -49,3 +53,7 @@ func (c *ContextCommandLine) RepoDirectory() string {
 func (c *ContextCommandLine) PluginURL() string {
 	return c.GlobalString("pluginUrl")
 }
+
+func (c *ContextCommandLine) OptionsString() string {
+	return c.GlobalString("configOverrides")
+}