浏览代码

Began work on deb and rpm packaging, #1476

Torkel Ödegaard 10 年之前
父节点
当前提交
ad2065afc7

+ 102 - 18
build.go

@@ -8,10 +8,10 @@ import (
 	"flag"
 	"flag"
 	"fmt"
 	"fmt"
 	"io"
 	"io"
+	"io/ioutil"
 	"log"
 	"log"
 	"os"
 	"os"
 	"os/exec"
 	"os/exec"
-	"path"
 	"path/filepath"
 	"path/filepath"
 	"regexp"
 	"regexp"
 	"runtime"
 	"runtime"
@@ -27,6 +27,10 @@ var (
 	version    string = "2.0.0-alpha"
 	version    string = "2.0.0-alpha"
 	race       bool
 	race       bool
 	workingDir string
 	workingDir string
+
+	installRoot   = "/opt/grafana"
+	configRoot    = "/etc/grafana"
+	grafanaLogDir = "/var/log/grafana"
 )
 )
 
 
 const minGoVersion = 1.3
 const minGoVersion = 1.3
@@ -35,15 +39,7 @@ func main() {
 	log.SetOutput(os.Stdout)
 	log.SetOutput(os.Stdout)
 	log.SetFlags(0)
 	log.SetFlags(0)
 
 
-	if os.Getenv("GOPATH") == "" {
-		cwd, err := os.Getwd()
-		if err != nil {
-			log.Fatal(err)
-		}
-		gopath := filepath.Clean(filepath.Join(cwd, "../../../../"))
-		log.Println("GOPATH is", gopath)
-		os.Setenv("GOPATH", gopath)
-	}
+	ensureGoPath()
 
 
 	//os.Setenv("PATH", fmt.Sprintf("%s%cbin%c%s", os.Getenv("GOPATH"), os.PathSeparator, os.PathListSeparator, os.Getenv("PATH")))
 	//os.Setenv("PATH", fmt.Sprintf("%s%cbin%c%s", os.Getenv("GOPATH"), os.PathSeparator, os.PathListSeparator, os.Getenv("PATH")))
 
 
@@ -73,8 +69,11 @@ func main() {
 			test("./pkg/...")
 			test("./pkg/...")
 
 
 		case "package":
 		case "package":
-			test("./pkg/...")
-			build(".", []string{})
+			//checkCleanTree()
+			//test("./pkg/...")
+			//build(".", []string{})
+			//buildFrontend()
+			createRpmAndDeb()
 
 
 		case "build-ui":
 		case "build-ui":
 			buildFrontend()
 			buildFrontend()
@@ -87,17 +86,102 @@ func main() {
 	}
 	}
 }
 }
 
 
+func createRpmAndDeb() {
+	packageRoot, _ := ioutil.TempDir("", "grafana-linux-pack")
+	postInstallScriptPath, _ := ioutil.TempFile("", "postinstall")
+
+	versionFolder := filepath.Join(packageRoot, installRoot, "versions", version)
+	runError("mkdir", "-p", versionFolder)
+	runError("mkdir", "-p", filepath.Join(packageRoot, configRoot))
+
+	runError("cp", "-a", filepath.Join(workingDir, "tmp")+"/.", versionFolder)
+
+	fmt.Printf("PackageDir: %v\n", versionFolder)
+
+	GeneratePostInstallScript(postInstallScriptPath.Name())
+	fmt.Printf("script_path: %v\n", postInstallScriptPath.Name())
+
+	args := []string{
+		"-s", "dir",
+		"-t", "deb",
+		"--description", "Grafana",
+		"-C", packageRoot,
+		"--vendor", "Grafana",
+		"--url", "http://grafana.org",
+		"--license", "Apache 2.0",
+		"--maintainer", "contact@grafana.org",
+		"--after-install", postInstallScriptPath.Name(),
+		"--name", "grafana",
+		"--version", version,
+		"-p", "./dist",
+		".",
+	}
+
+	runPrint("fpm", args...)
+}
+
+func GeneratePostInstallScript(path string) {
+	content := `
+rm -f $INSTALL_ROOT_DIR/grafana
+rm -f $INSTALL_ROOT_DIR/init.sh
+ln -s $INSTALL_ROOT_DIR/versions/$VERSION/grafana $INSTALL_ROOT_DIR/grafana
+ln -s $INSTALL_ROOT_DIR/versions/$VERSION/scripts/init.sh $INSTALL_ROOT_DIR/init.sh
+if [ ! -L /etc/init.d/grafana ]; then
+    ln -sfn $INSTALL_ROOT_DIR/init.sh /etc/init.d/grafana
+    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
+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 checkCleanTree() {
+	rs, err := runError("git", "ls-files", "--modified")
+	if err != nil {
+		log.Fatalf("Failed to check if git tree was clean, %v, %v\n", string(rs), err)
+		return
+	}
+	count := len(string(rs))
+	if count > 0 {
+		log.Fatalf("Git repository has modified files, aborting")
+	}
+
+	log.Fatalf("Git repository is clean")
+}
+
+func ensureGoPath() {
+	if os.Getenv("GOPATH") == "" {
+		cwd, err := os.Getwd()
+		if err != nil {
+			log.Fatal(err)
+		}
+		gopath := filepath.Clean(filepath.Join(cwd, "../../../../"))
+		log.Println("GOPATH is", gopath)
+		os.Setenv("GOPATH", gopath)
+	}
+}
+
 func ChangeWorkingDir(dir string) {
 func ChangeWorkingDir(dir string) {
 	os.Chdir(dir)
 	os.Chdir(dir)
 }
 }
 
 
 func buildFrontend() {
 func buildFrontend() {
-	ChangeWorkingDir(path.Join(workingDir, "grafana"))
-	defer func() {
-		ChangeWorkingDir(path.Join(workingDir, "../"))
-	}()
-
-	runPrint("grunt")
+	runPrint("grunt", "release")
 }
 }
 
 
 func setup() {
 func setup() {

+ 4 - 0
docker/debtest/Dockerfile

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

+ 10 - 0
docker/debtest/build.sh

@@ -0,0 +1,10 @@
+#!/bin/bash
+
+cp Dockerfile ../../dist
+cd ../../dist
+
+docker build --tag "grafana/debtest" .
+
+rm Dockerfile
+
+docker run -i -t grafana/debtest /bin/bash

+ 1 - 1
pkg/util/encoding_test.go

@@ -11,6 +11,6 @@ func TestEncoding(t *testing.T) {
 	Convey("When generating base64 header", t, func() {
 	Convey("When generating base64 header", t, func() {
 		result := GetBasicAuthHeader("grafana", "1234")
 		result := GetBasicAuthHeader("grafana", "1234")
 
 
-		So(result, ShouldEqual, "Z3JhZmFuYToxMjM0")
+		So(result, ShouldEqual, "Basic Z3JhZmFuYToxMjM0")
 	})
 	})
 }
 }

+ 108 - 0
scripts/init.sh

@@ -0,0 +1,108 @@
+#!/bin/sh
+### BEGIN INIT INFO
+# Provides:          grafana
+# Required-Start:    $local_fs $remote_fs $network
+# Required-Stop:     $local_fs $remote_fs $network
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: Starts grafana at startup
+# Description:       Starts grafana at startup
+### END INIT INFO
+
+
+# Documentation available at
+# http://refspecs.linuxfoundation.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/iniscrptfunc.html
+# Debian provides some extra functions though
+. /lib/lsb/init-functions
+
+DAEMON_NAME="grafana"
+DAEMON_USER="grafana"
+DAEMON_PATH="%BIN_PATH%"
+DAEMON_OPTS="web"
+DAEMON_PWD="/opt/grafana"
+DAEMON_PID="/var/run/${DAEMON_NAME}.pid"
+DAEMON_NICE=0
+DAEMON_LOG='/var/log/grafana/grafana.log'
+
+[ -r "/etc/default/${DAEMON_NAME}" ] && . "/etc/default/${DAEMON_NAME}"
+
+do_start() {
+  local result
+
+        pidofproc -p "${DAEMON_PID}" "${DAEMON_PATH}" > /dev/null
+        if [ $? -eq 0 ]; then
+                log_warning_msg "${DAEMON_NAME} is already started"
+                result=0
+        else
+                log_daemon_msg "Starting ${DAEMON_DESC}" "${DAEMON_NAME}"
+                touch "${DAEMON_LOG}"
+                chown $DAEMON_USER "${DAEMON_LOG}"
+                chmod u+rw "${DAEMON_LOG}"
+                if [ -z "${DAEMON_USER}" ]; then
+                        start-stop-daemon --start --quiet --oknodo --background \
+                                --nicelevel $DAEMON_NICE \
+                                --chdir "${DAEMON_PWD}" \
+                                --pidfile "${DAEMON_PID}" --make-pidfile \
+                                --exec "${DAEMON_PATH}" -- -c $DAEMON_OPTS
+                        result=$?
+                else
+                        start-stop-daemon --start --quiet --oknodo --background \
+                                --nicelevel $DAEMON_NICE \
+                                --chdir "${DAEMON_PWD}" \
+                                --pidfile "${DAEMON_PID}" --make-pidfile \
+                                --chuid "${DAEMON_USER}" \
+                                --exec  "${DAEMON_PATH}" -- -c ${DAEMON_OPTS}
+                        result=$?
+                fi
+                log_end_msg $result
+        fi
+        return $result
+}
+
+do_stop() {
+        local result
+
+        pidofproc -p "${DAEMON_PID}" "${DAEMON_PATH}" > /dev/null
+        if [ $? -ne 0 ]; then
+                log_warning_msg "${DAEMON_NAME} is not started"
+                result=0
+        else
+                log_daemon_msg "Stopping ${DAEMON_DESC}" "${DAEMON_NAME}"
+                killproc -p "${DAEMON_PID}" "${DAEMON_PATH}"
+                result=$?
+                log_end_msg $result
+                rm "${DAEMON_PID}"
+        fi
+        return $result
+}
+
+do_restart() {
+        local result
+        do_stop
+        result=$?
+        if [ $result = 0 ]; then
+                do_start
+                result=$?
+        fi
+        return $result
+}
+
+do_status() {
+        local result
+        status_of_proc -p "${DAEMON_PID}" "${DAEMON_PATH}" "${DAEMON_NAME}"
+        result=$?
+        return $result
+}
+
+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

+ 6 - 11
src/app/plugins/datasource/influxdb_08/partials/config.html

@@ -1,4 +1,4 @@
-<h2>InfluxDB Details</h2>
+<h5>InfluxDB Details</h5>
 
 
 <div class="tight-form">
 <div class="tight-form">
 	<ul class="tight-form-list">
 	<ul class="tight-form-list">
@@ -6,29 +6,24 @@
 			Database
 			Database
 		</li>
 		</li>
 		<li>
 		<li>
-			<input type="text" class="tight-form-input input-xxlarge last" ng-model='current.database' placeholder="" required></input>
+			<input type="text" class="tight-form-input input-large" ng-model='current.database' placeholder="" required></input>
 		</li>
 		</li>
 	</ul>
 	</ul>
 	<div class="clearfix"></div>
 	<div class="clearfix"></div>
 </div>
 </div>
-<div class="tight-form">
+<div class="tight-form last">
 	<ul class="tight-form-list">
 	<ul class="tight-form-list">
 		<li class="tight-form-item" style="width: 80px">
 		<li class="tight-form-item" style="width: 80px">
 			User
 			User
 		</li>
 		</li>
 		<li>
 		<li>
-			<input type="text" class="tight-form-input input-xxlarge last" ng-model='current.user' placeholder="" required></input>
+			<input type="text" class="tight-form-input input-large" ng-model='current.user' placeholder="" required></input>
 		</li>
 		</li>
-	</ul>
-	<div class="clearfix"></div>
-</div>
-<div class="tight-form last">
-	<ul class="tight-form-list">
-		<li class="tight-form-item" style="width: 80px">
+		<li class="tight-form-item">
 			Password
 			Password
 		</li>
 		</li>
 		<li>
 		<li>
-			<input type="text" class="tight-form-input input-xxlarge last" ng-model='current.password' placeholder="" required></input>
+			<input type="text" class="tight-form-input input-large" ng-model='current.password' placeholder="" required></input>
 		</li>
 		</li>
 	</ul>
 	</ul>
 	<div class="clearfix"></div>
 	<div class="clearfix"></div>

+ 1 - 1
tasks/build_task.js

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