Browse Source

Worked on new deb & rpm packaging and init.d scripts

Torkel Ödegaard 10 years ago
parent
commit
96ee1c17a3

+ 15 - 39
build.go

@@ -73,7 +73,7 @@ func main() {
 
 
 		case "package":
 		case "package":
 			//verifyGitRepoIsClean()
 			//verifyGitRepoIsClean()
-			grunt("release", "--pkgVer="+version)
+			//grunt("release", "--pkgVer="+version)
 			createRpmAndDeb()
 			createRpmAndDeb()
 
 
 		case "latest":
 		case "latest":
@@ -114,32 +114,39 @@ func readVersionFromPackageJson() {
 
 
 func createRpmAndDeb() {
 func createRpmAndDeb() {
 	packageRoot, _ := ioutil.TempDir("", "grafana-linux-pack")
 	packageRoot, _ := ioutil.TempDir("", "grafana-linux-pack")
-	postInstallScriptPath, _ := ioutil.TempFile("", "postinstall")
+	afterInstallScript, _ := filepath.Abs("./packaging/deb/control/postinst")
+	initdscript, _ := filepath.Abs("./packaging/deb/init.d/grafana")
+	defaultScript, _ := filepath.Abs("./packaging/deb/default/grafana")
 
 
-	versionFolder := filepath.Join(packageRoot, installRoot, "versions", version)
+	packageInstallRoot := filepath.Join(packageRoot, installRoot)
 	configDir := filepath.Join(packageRoot, configRoot)
 	configDir := filepath.Join(packageRoot, configRoot)
 
 
-	runError("mkdir", "-p", versionFolder)
+	runError("mkdir", "-p", packageInstallRoot)
 	runError("mkdir", "-p", configDir)
 	runError("mkdir", "-p", configDir)
+	runError("mkdir", "-p", filepath.Join(packageRoot, "/etc/init.d"))
+	runError("mkdir", "-p", filepath.Join(packageRoot, "/etc/default"))
 
 
 	// copy sample ini file to /etc/opt/grafana
 	// copy sample ini file to /etc/opt/grafana
 	configFile := filepath.Join(configDir, "grafana.ini")
 	configFile := filepath.Join(configDir, "grafana.ini")
 	runError("cp", "conf/sample.ini", configFile)
 	runError("cp", "conf/sample.ini", configFile)
-	// copy release files
-	runError("cp", "-a", filepath.Join(workingDir, "tmp")+"/.", versionFolder)
 
 
-	GeneratePostInstallScript(postInstallScriptPath.Name())
+	// copy init.d script
+	runError("cp", "-p", initdscript, filepath.Join(packageRoot, "/etc/init.d/grafana"))
+	runError("cp", "-p", defaultScript, filepath.Join(packageRoot, "/etc/default/grafana"))
+	// copy release files
+	runError("cp", "-a", filepath.Join(workingDir, "tmp")+"/.", packageInstallRoot)
 
 
 	args := []string{
 	args := []string{
 		"-s", "dir",
 		"-s", "dir",
 		"--description", "Grafana",
 		"--description", "Grafana",
 		"-C", packageRoot,
 		"-C", packageRoot,
 		"--vendor", "Grafana",
 		"--vendor", "Grafana",
+		"--depends", "adduser",
 		"--url", "http://grafana.org",
 		"--url", "http://grafana.org",
 		"--license", "Apache 2.0",
 		"--license", "Apache 2.0",
 		"--maintainer", "contact@grafana.org",
 		"--maintainer", "contact@grafana.org",
 		"--config-files", filepath.Join(configRoot, "grafana.ini"),
 		"--config-files", filepath.Join(configRoot, "grafana.ini"),
-		"--after-install", postInstallScriptPath.Name(),
+		"--after-install", afterInstallScript,
 		"--name", "grafana",
 		"--name", "grafana",
 		"--version", version,
 		"--version", version,
 		"-p", "./dist",
 		"-p", "./dist",
@@ -153,37 +160,6 @@ func createRpmAndDeb() {
 	runPrint("fpm", append([]string{"-t", "rpm"}, args...)...)
 	runPrint("fpm", append([]string{"-t", "rpm"}, args...)...)
 }
 }
 
 
-func GeneratePostInstallScript(path string) {
-	content := `
-rm -f $INSTALL_ROOT_DIR/current
-ln -s $INSTALL_ROOT_DIR/versions/$VERSION/ $INSTALL_ROOT_DIR/current
-
-if [ ! -L /etc/init.d/grafana ]; then
-    ln -sfn $INSTALL_ROOT_DIR/current/scripts/init.sh /etc/init.d/grafana
-fi
-
-chmod +x /etc/init.d/grafana
-if which update-rc.d > /dev/null 2>&1 ; then
-   update-rc.d -f grafana remove
-   update-rc.d grafana defaults
-else
-   chkconfig --add grafana
-fi
-
-if ! id grafana >/dev/null 2>&1; then
-   useradd --system -U -M grafana
-fi
-chown -R -L grafana:grafana $INSTALL_ROOT_DIR
-chmod -R a+rX $INSTALL_ROOT_DIR
-mkdir -p $GRAFANA_LOG_DIR
-chown -R -L grafana:grafana $GRAFANA_LOG_DIR
-`
-	content = strings.Replace(content, "$INSTALL_ROOT_DIR", installRoot, -1)
-	content = strings.Replace(content, "$VERSION", version, -1)
-	content = strings.Replace(content, "$GRAFANA_LOG_DIR", grafanaLogDir, -1)
-	ioutil.WriteFile(path, []byte(content), 0644)
-}
-
 func verifyGitRepoIsClean() {
 func verifyGitRepoIsClean() {
 	rs, err := runError("git", "ls-files", "--modified")
 	rs, err := runError("git", "ls-files", "--modified")
 	if err != nil {
 	if err != nil {

+ 18 - 6
conf/defaults.ini

@@ -1,6 +1,14 @@
 app_name = Grafana
 app_name = Grafana
 app_mode = production
 app_mode = production
 
 
+; data_path
+; where rendered png images are temporarily stored
+; file based sessions are stored here (if file based session is configured below)
+; the database is stored here if sqlite3 database is used
+; can be overriden from command line --data-path
+; defaults to `data` path relative to working directory
+data_path =
+
 [server]
 [server]
 ; protocol (http or https)
 ; protocol (http or https)
 protocol = http
 protocol = http
@@ -39,18 +47,18 @@ user = root
 password =
 password =
 ; For "postgres" only, either "disable", "require" or "verify-full"
 ; For "postgres" only, either "disable", "require" or "verify-full"
 ssl_mode = disable
 ssl_mode = disable
-; For "sqlite3" only
-path = data/grafana.db
+; For "sqlite3" only, path relative to data_dir setting
+path = grafana.db
 
 
 [session]
 [session]
 ; Either "memory", "file", "redis", "mysql", default is "memory"
 ; Either "memory", "file", "redis", "mysql", default is "memory"
 provider = file
 provider = file
 ; Provider config options
 ; Provider config options
 ; memory: not have any config yet
 ; memory: not have any config yet
-; file: session file path, e.g. `data/sessions`
+; file: session dir path, is relative to grafana data_dir
 ; redis: config like redis server addr, poolSize, password, e.g. `127.0.0.1:6379,100,grafana`
 ; redis: config like redis server addr, poolSize, password, e.g. `127.0.0.1:6379,100,grafana`
 ; mysql: go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1)/database_name`
 ; mysql: go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1)/database_name`
-provider_config = data/sessions
+provider_config = sessions
 ; Session cookie name
 ; Session cookie name
 cookie_name = grafana_sess
 cookie_name = grafana_sess
 ; If you use session in https only, default is false
 ; If you use session in https only, default is false
@@ -109,10 +117,14 @@ token_url = https://accounts.google.com/o/oauth2/token
 ; allowed_domains = mycompany.com othercompany.com
 ; allowed_domains = mycompany.com othercompany.com
 
 
 [log]
 [log]
-root_path = data/log
+; root_path
+; for deb or rpm package installs this is specified via command line
+; change it in /etc/default/grafana, it defaults to /var/log/grafana
+; for non package installs (running manually) defaults to `log` dir under data_dir
+root_path =
 ; Either "console", "file", default is "console"
 ; Either "console", "file", default is "console"
 ; Use comma to separate multiple modes, e.g. "console, file"
 ; Use comma to separate multiple modes, e.g. "console, file"
-mode = console
+mode = console, file
 ; Buffer length of channel, keep it as it is if you don't know what it is.
 ; Buffer length of channel, keep it as it is if you don't know what it is.
 buffer_len = 10000
 buffer_len = 10000
 ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
 ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"

+ 13 - 5
conf/sample.ini

@@ -5,6 +5,11 @@
 
 
 app_mode = production
 app_mode = production
 
 
+; data_path (used for sqlite3 db (if that is used), temp png images, and sessions (if file based sessions are used)
+; this option is passed via command line args, override this option in /etc/default/grafana
+; defaults to /opt/grafana/data
+data_path =
+
 [server]
 [server]
 ; protocol (http or https)
 ; protocol (http or https)
 protocol = http
 protocol = http
@@ -42,18 +47,18 @@ user = root
 password =
 password =
 ; For "postgres" only, either "disable", "require" or "verify-full"
 ; For "postgres" only, either "disable", "require" or "verify-full"
 ssl_mode = disable
 ssl_mode = disable
-; For "sqlite3" only
-path = /opt/grafana/data/grafana.db
+; For "sqlite3" only, path is relative to data_dir
+path = grafana.db
 
 
 [session]
 [session]
 ; Either "memory", "file", "redis", "mysql", default is "memory"
 ; Either "memory", "file", "redis", "mysql", default is "memory"
 provider = file
 provider = file
 ; Provider config options
 ; Provider config options
 ; memory: not have any config yet
 ; memory: not have any config yet
-; file: session file path, e.g. `data/sessions`
+; file: session file path, e.g. `sessions`, relative to data_dir
 ; redis: config like redis server addr, poolSize, password, e.g. `127.0.0.1:6379,100,grafana`
 ; redis: config like redis server addr, poolSize, password, e.g. `127.0.0.1:6379,100,grafana`
 ; mysql: go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1)/database_name`
 ; mysql: go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1)/database_name`
-provider_config = /opt/grafana/data/sessions
+provider_config = sessions
 ; Session cookie name
 ; Session cookie name
 cookie_name = grafana_sess
 cookie_name = grafana_sess
 ; If you use session in https only, default is false
 ; If you use session in https only, default is false
@@ -95,5 +100,8 @@ org_role = Viewer
 ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
 ; Either "Trace", "Debug", "Info", "Warn", "Error", "Critical", default is "Trace"
 level = Info
 level = Info
 mode = console, file
 mode = console, file
-root_path = /var/log/grafana
+; root_path, this option is passed via command line args,
+; override this option in /etc/default/grafana
+; defaults to /var/log/grafana/
+root_path =
 
 

+ 1 - 1
docker/debtest/Dockerfile

@@ -1,4 +1,4 @@
-FROM debian
+FROM debian:jessie
 
 
 ADD *.deb /tmp/
 ADD *.deb /tmp/
 
 

+ 8 - 0
main.go

@@ -45,6 +45,14 @@ func main() {
 			Name:  "config",
 			Name:  "config",
 			Usage: "path to grafana.ini config file",
 			Usage: "path to grafana.ini config file",
 		},
 		},
+		cli.StringFlag{
+			Name:  "default-data-path",
+			Usage: "change default path to where grafana can store data",
+		},
+		cli.StringFlag{
+			Name:  "default-log-path",
+			Usage: "change default path to where grafana can log files",
+		},
 		cli.StringFlag{
 		cli.StringFlag{
 			Name:  "pidfile",
 			Name:  "pidfile",
 			Usage: "path to pidfile",
 			Usage: "path to pidfile",

+ 64 - 0
packaging/deb/control/postinst

@@ -0,0 +1,64 @@
+#!/bin/sh
+
+set -e
+
+[ -f /etc/default/grafana ] && . /etc/default/grafana
+
+startGrafana() {
+    if [ -x /bin/systemctl ] ; then
+        /bin/systemctl daemon-reload
+        /bin/systemctl start grafana.service
+	elif [ -x "/etc/init.d/grafana" ]; then
+		if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then
+			invoke-rc.d grafana start || true
+		else
+			/etc/init.d/grafana start || true
+		fi
+	fi
+}
+
+case "$1" in
+	configure)
+	[ -z "$GRAFANA_USER" ] && GRAFANA_USER="grafana"
+	[ -z "$GRAFANA_GROUP" ] && GRAFANA_GROUP="grafana"
+	if ! getent group "$GRAFANA_GROUP" > /dev/null 2>&1 ; then
+	    addgroup --system "$GRAFANA_GROUP" --quiet
+	fi
+	if ! id $GRAFANA_USER > /dev/null 2>&1 ; then
+	    adduser --system --home /usr/share/grafana --no-create-home \
+		--ingroup "$GRAFANA_GROUP" --disabled-password --shell /bin/false \
+		"$GRAFANA_USER"
+	fi
+
+	# Set user permissions on /var/log/grafana, /opt/grafana/data
+	mkdir -p /var/log/grafana /opt/grafana/data
+	chown -R $GRAFANA_USER:$GRAFANA_GROUP /var/log/grafana /opt/grafana/data
+	chmod 755 /var/log/grafana /opt/grafana/data
+
+	# configuration files should not be modifiable by elasticsearch user, as this can be a security issue
+	chown -Rh root:root /etc/grafana/*
+	chmod 755 /etc/grafana
+	find /etc/grafana -type f -exec chmod 644 {} ';'
+	find /etc/grafana -type d -exec chmod 755 {} ';'
+
+	# if $2 is set, this is an upgrade
+	if ( [ -n $2 ] && [ "$RESTART_ON_UPGRADE" = "true" ] ) ; then
+		startGrafana
+	# this is a fresh installation
+	elif [ -z $2 ] ; then
+        if [ -x /bin/systemctl ] ; then
+            echo "### NOT starting on installation, please execute the following statements to configure elasticsearch to start automatically using systemd"
+            echo " sudo /bin/systemctl daemon-reload"
+            echo " sudo /bin/systemctl enable grafana.service"
+            echo "### You can start grafana by executing"
+            echo " sudo /bin/systemctl start grafana.service"
+
+        elif [ -x /usr/sbin/update-rc.d ] ; then
+            echo "### NOT starting grafana by default on bootup, please execute"
+            echo " sudo update-rc.d grafana defaults 95 10"
+            echo "### In order to start grafana, execute"
+            echo " sudo /etc/init.d/grafana start"
+        fi
+	fi
+	;;
+esac

+ 15 - 0
packaging/deb/default/grafana

@@ -0,0 +1,15 @@
+
+#GRAFANA_USER=grafana
+
+#GRAFANA_GROUP=grafana
+
+#LOG_DIR=/var/log/grafana
+
+#GRAFANA_HOME=/opt/grafana
+#DATA_DIR=/opt/data/grafana
+#WORK_DIR=/opt/grafana
+
+#CONF_DIR=/etc/grafana
+#CONF_FILE=/etc/grafana/grafana.ini
+
+#RESTART_ON_UPGRADE=true

+ 140 - 0
packaging/deb/init.d/grafana

@@ -0,0 +1,140 @@
+#! /usr/bin/env bash
+
+# chkconfig: 2345 80 05
+# description: Grafana web server & backend
+# processname: grafana
+# config: /etc/grafana/grafana.ini
+# pidfile: /var/run/grafana.pid
+
+### BEGIN INIT INFO
+# Provides:          grafana
+# Required-Start:    $all
+# Required-Stop:     $remote_fs $syslog
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Start grafana at boot time
+### END INIT INFO
+
+#  tested on
+#  1. New lsb that define start-stop-daemon
+#  3. Centos with initscripts package installed
+
+PATH=/bin:/usr/bin:/sbin:/usr/sbin
+NAME=grafana
+DESC="Grafana Server"
+DEFAULT=/etc/default/$NAME
+
+if [ `id -u` -ne 0 ]; then
+	echo "You need root privileges to run this script"
+	exit 1
+fi
+
+. /lib/lsb/init-functions
+
+if [ -r /etc/default/rcS ]; then
+	. /etc/default/rcS
+fi
+
+GRAFANA_USER=grafana
+GRAFANA_GROUP=grafana
+GRAFANA_HOME=/opt/$NAME
+CONF_DIR=/etc/$NAME
+WORK_DIR=$GRAFANA_HOME
+DATA_DIR=$GRAFANA_HOME/data
+LOG_DIR=/var/log/$NAME
+CONF_FILE=$CONF_DIR/grafana.ini
+MAX_OPEN_FILES=65535
+
+# overwrite settings from default file
+if [ -f "$DEFAULT" ]; then
+	. "$DEFAULT"
+fi
+
+PID_FILE=/var/run/$NAME.pid
+DAEMON=$GRAFANA_HOME/bin/grafana
+DAEMON_OPTS="--pidfile=${PID_FILE} --config=${CONF_FILE} --default-data-path=${DATA_DIR} --default-log-path=${LOG_DIR} web"
+
+# Check DAEMON exists
+test -x $DAEMON || exit 0
+
+case "$1" in
+  start)
+
+	log_daemon_msg "Starting $DESC"
+
+	pid=`pidofproc -p $PID_FILE grafana`
+	if [ -n "$pid" ] ; then
+		log_begin_msg "Already running."
+		log_end_msg 0
+		exit 0
+	fi
+
+	# Prepare environment
+	mkdir -p "$LOG_DIR" "$DATA_DIR" "$WORK_DIR" && chown "$GRAFANA_USER":"$GRAFANA_GROUP" "$LOG_DIR" "$DATA_DIR" "$WORK_DIR"
+	touch "$PID_FILE" && chown "$GRAFANA_USER":"$GRAFANA_GROUP" "$PID_FILE"
+
+  if [ -n "$MAX_OPEN_FILES" ]; then
+		ulimit -n $MAX_OPEN_FILES
+	fi
+
+	# Start Daemon
+	start-stop-daemon --start -b --chdir "$WORK_DIR" --user "$GRAFANA_USER" -c "$GRAFANA_USER" --pidfile "$PID_FILE" --exec $DAEMON -- $DAEMON_OPTS
+	return=$?
+	if [ $return -eq 0 ]
+	then
+	  sleep 1
+
+    # check if pid file has been written two
+	  if ! [[ -s $PID_FILE ]]; then
+	    log_end_msg 1
+	  fi
+
+		i=0
+		timeout=10
+		# Wait for the process to be properly started before exiting
+		until { cat "$PID_FILE" | xargs kill -0; } >/dev/null 2>&1
+		do
+			sleep 1
+			i=$(($i + 1))
+			[ $i -gt $timeout ] && log_end_msg 1
+		done
+  fi
+  log_end_msg $return
+	;;
+  stop)
+	log_daemon_msg "Stopping $DESC"
+
+	if [ -f "$PID_FILE" ]; then
+		start-stop-daemon --stop --pidfile "$PID_FILE" \
+			--user "$GRAFANA_USER" \
+			--retry=TERM/20/KILL/5 >/dev/null
+		if [ $? -eq 1 ]; then
+			log_progress_msg "$DESC is not running but pid file exists, cleaning up"
+		elif [ $? -eq 3 ]; then
+			PID="`cat $PID_FILE`"
+			log_failure_msg "Failed to stop $DESC (pid $PID)"
+			exit 1
+		fi
+		rm -f "$PID_FILE"
+	else
+		log_progress_msg "(not running)"
+	fi
+	log_end_msg 0
+	;;
+  status)
+	status_of_proc -p $PID_FILE grafana grafana && exit 0 || exit $?
+    ;;
+  restart|force-reload)
+	if [ -f "$PID_FILE" ]; then
+		$0 stop
+		sleep 1
+	fi
+	$0 start
+	;;
+  *)
+	log_success_msg "Usage: $0 {start|stop|restart|force-reload|status}"
+	exit 1
+	;;
+esac
+
+exit 0

+ 26 - 0
packaging/deb/systemd/grafana.service

@@ -0,0 +1,26 @@
+[Unit]
+Description=Starts and stops a single grafana instance on this system
+Documentation=http://docs.grafana.org
+Wants=network-online.target
+After=network-online.target
+
+[Service]
+EnvironmentFile=/etc/default/elasticsearch
+User=elasticsearch
+Group=elasticsearch
+ExecStart=/usr/share/elasticsearch/bin/elasticsearch            \
+                            -Des.default.config=$CONF_FILE      \
+                            -Des.default.path.home=$ES_HOME     \
+                            -Des.default.path.logs=$LOG_DIR     \
+                            -Des.default.path.data=$DATA_DIR    \
+                            -Des.default.path.work=$WORK_DIR    \
+                            -Des.default.path.conf=$CONF_DIR
+# See MAX_OPEN_FILES in sysconfig
+LimitNOFILE=65535
+# See MAX_LOCKED_MEMORY in sysconfig, use "infinity" when MAX_LOCKED_MEMORY=unlimited and using bootstrap.mlockall: true
+#LimitMEMLOCK=infinity
+# Shutdown delay in seconds, before process is tried to be killed with KILL (if configured)
+TimeoutStopSec=20
+
+[Install]
+WantedBy=multi-user.target

+ 11 - 1
pkg/cmd/common.go

@@ -10,12 +10,22 @@ import (
 )
 )
 
 
 func initRuntime(c *cli.Context) {
 func initRuntime(c *cli.Context) {
-	setting.NewConfigContext(c.GlobalString("config"))
+	var args = &setting.CommandLineArgs{
+		Config:          c.GlobalString("config"),
+		DefaultDataPath: c.GlobalString("default-data-path"),
+		DefaultLogPath:  c.GlobalString("default-log-path"),
+	}
+
+	setting.NewConfigContext(args)
 
 
 	log.Info("Starting Grafana")
 	log.Info("Starting Grafana")
 	log.Info("Version: %v, Commit: %v, Build date: %v", setting.BuildVersion, setting.BuildCommit, time.Unix(setting.BuildStamp, 0))
 	log.Info("Version: %v, Commit: %v, Build date: %v", setting.BuildVersion, setting.BuildCommit, time.Unix(setting.BuildStamp, 0))
 	setting.LogLoadedConfigFiles()
 	setting.LogLoadedConfigFiles()
 
 
+	log.Info("Working Path: %s", setting.WorkPath)
+	log.Info("Data Path: %s", setting.DataPath)
+	log.Info("Log Path: %s", setting.LogRootPath)
+
 	sqlstore.NewEngine()
 	sqlstore.NewEngine()
 	sqlstore.EnsureAdminUser()
 	sqlstore.EnsureAdminUser()
 }
 }

+ 4 - 0
pkg/services/sqlstore/sqlstore.go

@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"fmt"
 	"os"
 	"os"
 	"path"
 	"path"
+	"path/filepath"
 	"strings"
 	"strings"
 
 
 	"github.com/grafana/grafana/pkg/bus"
 	"github.com/grafana/grafana/pkg/bus"
@@ -126,6 +127,9 @@ func getEngine() (*xorm.Engine, error) {
 		cnnstr = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s",
 		cnnstr = fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=%s",
 			DbCfg.User, DbCfg.Pwd, host, port, DbCfg.Name, DbCfg.SslMode)
 			DbCfg.User, DbCfg.Pwd, host, port, DbCfg.Name, DbCfg.SslMode)
 	case "sqlite3":
 	case "sqlite3":
+		if !filepath.IsAbs(DbCfg.Path) {
+			DbCfg.Path = filepath.Join(setting.DataPath, DbCfg.Path)
+		}
 		os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm)
 		os.MkdirAll(path.Dir(DbCfg.Path), os.ModePerm)
 		cnnstr = "file:" + DbCfg.Path + "?cache=shared&mode=rwc&_loc=Local"
 		cnnstr = "file:" + DbCfg.Path + "?cache=shared&mode=rwc&_loc=Local"
 	default:
 	default:

+ 41 - 14
pkg/setting/setting.go

@@ -83,12 +83,10 @@ var (
 	SessionOptions session.Options
 	SessionOptions session.Options
 
 
 	// Global setting objects.
 	// Global setting objects.
-	WorkDir      string
+	DataPath     string
+	WorkPath     string
 	Cfg          *ini.File
 	Cfg          *ini.File
 	ConfRootPath string
 	ConfRootPath string
-	CustomPath   string // Custom directory path.
-	ProdMode     bool
-	RunUser      string
 	IsWindows    bool
 	IsWindows    bool
 
 
 	// PhantomJs Rendering
 	// PhantomJs Rendering
@@ -101,14 +99,20 @@ var (
 	GoogleAnalyticsId string
 	GoogleAnalyticsId string
 )
 )
 
 
+type CommandLineArgs struct {
+	DefaultDataPath string
+	DefaultLogPath  string
+	Config          string
+}
+
 func init() {
 func init() {
 	IsWindows = runtime.GOOS == "windows"
 	IsWindows = runtime.GOOS == "windows"
 	log.NewLogger(0, "console", `{"level": 0}`)
 	log.NewLogger(0, "console", `{"level": 0}`)
-	WorkDir, _ = filepath.Abs(".")
+	WorkPath, _ = filepath.Abs(".")
 }
 }
 
 
 func findConfigFiles(customConfigFile string) {
 func findConfigFiles(customConfigFile string) {
-	ConfRootPath = path.Join(WorkDir, "conf")
+	ConfRootPath = path.Join(WorkPath, "conf")
 	configFiles = make([]string, 0)
 	configFiles = make([]string, 0)
 
 
 	configFile := path.Join(ConfRootPath, "defaults.ini")
 	configFile := path.Join(ConfRootPath, "defaults.ini")
@@ -171,8 +175,8 @@ func loadEnvVariableOverrides() {
 	}
 	}
 }
 }
 
 
-func NewConfigContext(config string) {
-	findConfigFiles(config)
+func NewConfigContext(args *CommandLineArgs) {
+	findConfigFiles(args.Config)
 
 
 	var err error
 	var err error
 
 
@@ -190,7 +194,19 @@ func NewConfigContext(config string) {
 	}
 	}
 
 
 	loadEnvVariableOverrides()
 	loadEnvVariableOverrides()
-	initLogging()
+
+	DataPath = Cfg.Section("").Key("data_path").String()
+	// if no data path in config, use command line, otherwise default to
+	// data folder relative to working dir
+	if DataPath == "" {
+		if args.DefaultDataPath != "" {
+			DataPath = args.DefaultDataPath
+		} else {
+			DataPath = filepath.Join(WorkPath, "data")
+		}
+	}
+
+	initLogging(args)
 
 
 	AppName = Cfg.Section("").Key("app_name").MustString("Grafana")
 	AppName = Cfg.Section("").Key("app_name").MustString("Grafana")
 	Env = Cfg.Section("").Key("app_mode").MustString("development")
 	Env = Cfg.Section("").Key("app_mode").MustString("development")
@@ -209,7 +225,7 @@ func NewConfigContext(config string) {
 	HttpAddr = server.Key("http_addr").MustString("0.0.0.0")
 	HttpAddr = server.Key("http_addr").MustString("0.0.0.0")
 	HttpPort = server.Key("http_port").MustString("3000")
 	HttpPort = server.Key("http_port").MustString("3000")
 
 
-	StaticRootPath = server.Key("static_root_path").MustString(path.Join(WorkDir, "webapp"))
+	StaticRootPath = server.Key("static_root_path").MustString(path.Join(WorkPath, "public"))
 	RouterLogging = server.Key("router_logging").MustBool(false)
 	RouterLogging = server.Key("router_logging").MustBool(false)
 	EnableGzip = server.Key("enable_gzip").MustBool(false)
 	EnableGzip = server.Key("enable_gzip").MustBool(false)
 
 
@@ -234,8 +250,8 @@ func NewConfigContext(config string) {
 	AnonymousOrgRole = Cfg.Section("auth.anonymous").Key("org_role").String()
 	AnonymousOrgRole = Cfg.Section("auth.anonymous").Key("org_role").String()
 
 
 	// PhantomJS rendering
 	// PhantomJS rendering
-	ImagesDir = "data/png"
-	PhantomDir = "vendor/phantomjs"
+	ImagesDir = filepath.Join(DataPath, "png")
+	PhantomDir = filepath.Join(WorkPath, "vendor/phantomjs")
 
 
 	analytics := Cfg.Section("analytics")
 	analytics := Cfg.Section("analytics")
 	ReportingEnabled = analytics.Key("reporting_enabled").MustBool(true)
 	ReportingEnabled = analytics.Key("reporting_enabled").MustBool(true)
@@ -257,6 +273,9 @@ func readSessionConfig() {
 	SessionOptions.IDLength = 16
 	SessionOptions.IDLength = 16
 
 
 	if SessionOptions.Provider == "file" {
 	if SessionOptions.Provider == "file" {
+		if !filepath.IsAbs(SessionOptions.ProviderConfig) {
+			SessionOptions.ProviderConfig = filepath.Join(DataPath, SessionOptions.ProviderConfig)
+		}
 		os.MkdirAll(path.Dir(SessionOptions.ProviderConfig), os.ModePerm)
 		os.MkdirAll(path.Dir(SessionOptions.ProviderConfig), os.ModePerm)
 	}
 	}
 
 
@@ -274,10 +293,18 @@ var logLevels = map[string]string{
 	"Critical": "5",
 	"Critical": "5",
 }
 }
 
 
-func initLogging() {
+func initLogging(args *CommandLineArgs) {
 	// Get and check log mode.
 	// Get and check log mode.
 	LogModes = strings.Split(Cfg.Section("log").Key("mode").MustString("console"), ",")
 	LogModes = strings.Split(Cfg.Section("log").Key("mode").MustString("console"), ",")
-	LogRootPath = Cfg.Section("log").Key("root_path").MustString(path.Join(WorkDir, "/data/log"))
+	LogRootPath = Cfg.Section("log").Key("root_path").String()
+	if LogRootPath == "" {
+		if args.DefaultLogPath != "" {
+			LogRootPath = args.DefaultLogPath
+		} else {
+			LogRootPath = filepath.Join(DataPath, "log")
+		}
+	}
+
 	LogConfigs = make([]string, len(LogModes))
 	LogConfigs = make([]string, len(LogModes))
 	for i, mode := range LogModes {
 	for i, mode := range LogModes {
 		mode = strings.TrimSpace(mode)
 		mode = strings.TrimSpace(mode)

+ 0 - 174
scripts/init.sh

@@ -1,174 +0,0 @@
-#! /usr/bin/env bash
-
-# chkconfig: 2345 80 05
-# description: Grafana web server & backend
-# processname: grafana
-# config: /etc/grafana/grafana.ini
-# pidfile: /var/run/grafana.pid
-
-### BEGIN INIT INFO
-# Provides:          grafana
-# Required-Start:    $all
-# Required-Stop:     $remote_fs $syslog
-# Default-Start:     2 3 4 5
-# Default-Stop:      0 1 6
-# Short-Description: Start grafana at boot time
-### END INIT INFO
-
-#  tested on
-#  1. New lsb that define start-stop-daemon
-#  3. Centos with initscripts package installed
-
-if [ -r /lib/lsb/init-functions ]; then
-    source /lib/lsb/init-functions
-fi
-
-DAEMON_NAME="grafana"
-DAEMON_USER="grafana"
-DAEMON_PATH="/opt/grafana/current/grafana"
-DAEMON_OPTS="--config=/etc/grafana/grafana.ini web"
-DAEMON_PWD="/opt/grafana/current"
-DAEMON_PID="/var/run/${DAEMON_NAME}.pid"
-DAEMON_NICE=0
-DAEMON_LOG='/var/log/grafana/grafana.log'
-
-# If the daemon is not there, then exit.
-[ -x $DAEMON_PATH ] || exit 5
-
-if [ "x$STDOUT" == "x" ]; then
-    STDOUT=/tmp/grafana.log
-fi
-
-function pidofproc() {
-    if [ $# -ne 3 ]; then
-        echo "Expected three arguments, e.g. $0 -p pidfile daemon-name"
-    fi
-
-    pid=`pgrep -f $3`
-    local pidfile=`cat $2`
-
-    if [ "x$pidfile" == "x" ]; then
-        return 1
-    fi
-
-    if [ "x$pid" != "x" -a "$pidfile" == "$pid" ]; then
-        return 0
-    fi
-
-    return 1
-}
-
-function killproc() {
-    if [ $# -ne 3 ]; then
-        echo "Expected three arguments, e.g. $0 -p pidfile signal"
-    fi
-
-    pid=`cat $2`
-
-    kill -s $3 $pid
-}
-
-function log_failure_msg() {
-    echo "$@" "[ FAILED ]"
-}
-
-function log_success_msg() {
-    echo "$@" "[ OK ]"
-}
-
-do_start() {
-  cd $DAEMON_PWD
-
-  # Checked the PID file exists and check the actual status of process
-  if [ -e $DAEMON_PID ]; then
-    pidofproc -p $DAEMON_PID $DAEMON_PATH > /dev/null 2>&1 && status="0" || status="$?"
-    # If the status is SUCCESS then don't need to start again.
-    if [ "x$status" = "x0" ]; then
-      log_failure_msg "$DAEMON_NAME process is running"
-      exit 1 # Exit
-    fi
-  fi
-  # Start the daemon.
-  log_success_msg "Starting the process" "$DAEMON_NAME"
-
-  # Start the daemon with the help of start-stop-daemon
-  # Log the message appropriately
-  if which start-stop-daemon > /dev/null 2>&1; then
-    start-stop-daemon \
-      --start --quiet --oknodo --background \
-      --nicelevel $DAEMON_NICE \
-      --chdir "${DAEMON_PWD}" \
-      --pidfile "${DAEMON_PID}" --make-pidfile \
-      --chuid "${DAEMON_USER}" \
-      --exec  "${DAEMON_PATH}" -- $DAEMON_OPTS
-    result=$?
-  else
-    touch ${DAEMON_PID}
-    chown $DAEMON_USER "${DAEMON_PID}"
-    #daemon --user $DAEMON_USER --pidfile $DAEMON_PID nohup $DAEMON_PATH $DAEMON_OPTS
-    su -s /bin/sh -c "nohup ${DAEMON_PATH} --pidfile=${DAEMON_PID} ${DAEMON_OPTS} >> $STDOUT 3>&1 &" $DAEMON_USER
-  fi
-
-  log_success_msg "$DAEMON_NAME process was started"
-}
-
-do_stop() {
-  local result
-
-  pidofproc -p "${DAEMON_PID}" "${DAEMON_PATH}" > /dev/null
-  if [ $? -ne 0 ]; then
-    log_failure_msg "${DAEMON_NAME} is not started"
-    result=0
-  else
-    log_success_msg "Stopping ${DAEMON_NAME}"
-    killproc -p "${DAEMON_PID}" SIGTERM
-    result=$?
-    if [ $result = 0 ]; then
-      log_success_msg "Stopped ${DAEMON_NAME}"
-      rm "${DAEMON_PID}"
-    fi
-  fi
-
-  return $result
-}
-
-do_restart() {
-  local result
-  do_stop
-  result=$?
-  sleep 2
-  if [ $result = 0 ]; then
-    do_start
-    result=$?
-  fi
-  return $result
-}
-
-do_status() {
-  if [ -e $DEAMON_PID ]; then
-    pidofproc -p "${DAEMON_PID}" "${DAEMON_PATH}" > /dev/null
-    if [ $? -ne 0 ]; then
-      log_failure_msg "$DAEMON_NAME Process is not running"
-      exit 1
-    else
-      log_success_msg "$DAEMON_NAME Process is running"
-      exit 0
-    fi
-  else
-    log_failure_msg "$DAEMON_NAME Process is not running"
-    exit 3
-  fi
-}
-
-do_usage() {
-  echo $"Usage: $0 {start | stop | restart | status}"
-  exit 1
-}
-
-case "$1" in
-  start)   do_start;   exit $? ;;
-  stop)    do_stop;    exit $? ;;
-  restart) do_restart; exit $? ;;
-  status)  do_status;  exit $? ;;
-  *)       do_usage;   exit  1 ;;
-esac

+ 1 - 1
tasks/build_task.js

@@ -57,7 +57,7 @@ module.exports = function(grunt) {
       expand: true,
       expand: true,
       src: ['grafana'],
       src: ['grafana'],
       options: { mode: true},
       options: { mode: true},
-      dest: '<%= tempDir %>'
+      dest: '<%= tempDir %>/bin/'
     });
     });
     grunt.config('copy.backend_files', {
     grunt.config('copy.backend_files', {
       expand: true,
       expand: true,