diff --git a/.gitignore b/.gitignore index e69de29..15693e5 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,3 @@ +/grafana-*.tar.gz +/grafana-*.tar.gz.manifest +/grafana-*/ diff --git a/001-wrappers-grafana-cli.patch b/001-wrappers-grafana-cli.patch new file mode 100644 index 0000000..79bb3b5 --- /dev/null +++ b/001-wrappers-grafana-cli.patch @@ -0,0 +1,26 @@ +diff --git a/packaging/wrappers/grafana-cli b/packaging/wrappers/grafana-cli +index 9cad151c0d..6b7ec1ab42 100755 +--- a/packaging/wrappers/grafana-cli ++++ b/packaging/wrappers/grafana-cli +@@ -12,11 +12,12 @@ CONF_DIR=/etc/grafana + DATA_DIR=/var/lib/grafana + PLUGINS_DIR=/var/lib/grafana/plugins + LOG_DIR=/var/log/grafana ++LIBEXEC_DIR=/usr/libexec/grafana + + CONF_FILE=$CONF_DIR/grafana.ini + PROVISIONING_CFG_DIR=$CONF_DIR/provisioning + +-EXECUTABLE=$GRAFANA_HOME/bin/grafana-cli ++EXECUTABLE=$LIBEXEC_DIR/grafana-cli + + if [ ! -x $EXECUTABLE ]; then + echo "Program not installed or not executable" +@@ -24,6 +25,7 @@ if [ ! -x $EXECUTABLE ]; then + fi + + # overwrite settings from default file ++#shellcheck disable=SC1090 + if [ -f "$DEFAULT" ]; then + . "$DEFAULT" + fi diff --git a/002-manpages.patch b/002-manpages.patch new file mode 100644 index 0000000..d2b2f88 --- /dev/null +++ b/002-manpages.patch @@ -0,0 +1,219 @@ +diff --git a/docs/man/man1/grafana-cli.1 b/docs/man/man1/grafana-cli.1 +new file mode 100644 +index 0000000000..171748fcda +--- /dev/null ++++ b/docs/man/man1/grafana-cli.1 +@@ -0,0 +1,51 @@ ++.TH GRAFANA "1" "February 2019" "Grafana cli version 5.4.3" "User Commands" ++.SH NAME ++grafana-cli \- command line administration for the Grafana metrics dashboard and graph editor ++.SH DESCRIPTION ++.SS "NAME:" ++.IP ++grafana-cli ++.SS "USAGE:" ++.IP ++\fBgrafana\-cli\fP [\fIglobal options\fP] \fIcommand\fP [\fIcommand options\fP] [\fIarguments\fP...] ++.SS "COMMANDS:" ++.TP ++plugins ++Manage plugins for grafana ++.TP ++admin ++Grafana admin commands ++.TP ++help, h ++Shows a list of commands or help for one command ++.SS "GLOBAL OPTIONS:" ++.TP ++\fB\-\-pluginsDir\fR value ++path to the grafana plugin directory (default: "/var/lib/grafana/plugins") [$GF_PLUGIN_DIR] ++.TP ++\fB\-\-repo\fR value ++url to the plugin repository (default: "https://grafana.com/api/plugins") [$GF_PLUGIN_REPO] ++.TP ++\fB\-\-pluginUrl\fR value ++Full url to the plugin zip file instead of downloading the plugin from grafana.com/api [$GF_PLUGIN_URL] ++.TP ++\fB\-\-insecure\fR ++Skip TLS verification (insecure) ++.TP ++\fB\-\-debug\fR, \fB\-d\fR ++enable debug logging ++.TP ++\fB\-\-help\fR, \fB\-h\fR ++show help ++.TP ++\fB\-\-version\fR, \fB\-v\fR ++print the version ++.SH "SEE ALSO" ++Additional documentation for ++.B grafana-cli ++is available on-line at ++.BR http://docs.grafana.org/administration/cli/ . ++The full documentation for ++.B Grafana ++is available on-line at ++.BR http://docs.grafana.org/ . +diff --git a/docs/man/man1/grafana-server.1 b/docs/man/man1/grafana-server.1 +new file mode 100644 +index 0000000000..30b7c1306f +--- /dev/null ++++ b/docs/man/man1/grafana-server.1 +@@ -0,0 +1,156 @@ ++.TH VERSION "1" "February 2019" "Version 5.4.3" "User Commands" ++.SH NAME ++grafana-server \- back-end server for the Grafana metrics dashboard and graph editor ++.SH DESCRIPTION ++.B grafana-server ++is the back-end server for the Grafana metrics dashboard and graph editor. ++The ++.B grafana-server ++program should not normally be run from the command line, ++except when testing or for development purposes. ++Rather it should be managed by ++.BR systemd . ++After installing Grafana, the systemd service should be enabled and started as follows: ++.P ++.in 1i ++.B systemctl daemon-reload ++.br ++.B systemctl enable grafana-server.service ++.br ++.B systemctl start grafana-server.service ++.in ++.P ++.SH OPTIONS ++The ++.B gafana-server ++configuration is specified in ++.BR /etc/grafana/grafana.ini ++and is well documented with comments. ++The command-line options listed below override options of ++the same (or similar) name in the configuration file and also provide ++additional options for testing Grafana. ++.P ++.HP ++\fB\-config\fR string ++.IP ++path to config file ++.HP ++\fB\-homepath\fR string ++.IP ++path to grafana install/home path, defaults to working directory ++.HP ++\fB\-packaging\fR string ++.IP ++describes the way Grafana was installed (default "unknown") ++.HP ++\fB\-pidfile\fR string ++.IP ++path to pid file ++.HP ++\fB\-profile\fR ++.IP ++Turn on pprof profiling ++.HP ++\fB\-profile\-port\fR int ++.IP ++Define custom port for profiling (default 6060) ++.HP ++\fB\-test\fR.bench regexp ++.IP ++run only benchmarks matching regexp ++.HP ++\fB\-test\fR.benchmem ++.IP ++print memory allocations for benchmarks ++.HP ++\fB\-test\fR.benchtime d ++.IP ++run each benchmark for duration d (default 1s) ++.HP ++\fB\-test\fR.blockprofile file ++.IP ++write a goroutine blocking profile to file ++.HP ++\fB\-test\fR.blockprofilerate rate ++.IP ++set blocking profile rate (see runtime.SetBlockProfileRate) (default 1) ++.HP ++\fB\-test\fR.count n ++.IP ++run tests and benchmarks n times (default 1) ++.HP ++\fB\-test\fR.coverprofile file ++.IP ++write a coverage profile to file ++.HP ++\fB\-test\fR.cpu list ++.IP ++comma\-separated list of cpu counts to run each test with ++.HP ++\fB\-test\fR.cpuprofile file ++.IP ++write a cpu profile to file ++.HP ++\fB\-test\fR.failfast ++.IP ++do not start new tests after the first test failure ++.HP ++\fB\-test\fR.list regexp ++.IP ++list tests, examples, and benchmarks matching regexp then exit ++.HP ++\fB\-test\fR.memprofile file ++.IP ++write a memory profile to file ++.HP ++\fB\-test\fR.memprofilerate rate ++.IP ++set memory profiling rate (see runtime.MemProfileRate) ++.HP ++\fB\-test\fR.mutexprofile string ++.IP ++write a mutex contention profile to the named file after execution ++.HP ++\fB\-test\fR.mutexprofilefraction int ++.IP ++if >= 0, calls runtime.SetMutexProfileFraction() (default 1) ++.HP ++\fB\-test\fR.outputdir dir ++.IP ++write profiles to dir ++.HP ++\fB\-test\fR.parallel n ++.IP ++run at most n tests in parallel (default 8) ++.HP ++\fB\-test\fR.run regexp ++.IP ++run only tests and examples matching regexp ++.HP ++\fB\-test\fR.short ++.IP ++run smaller test suite to save time ++.HP ++\fB\-test\fR.testlogfile file ++.IP ++write test action log to file (for use only by cmd/go) ++.HP ++\fB\-test\fR.timeout d ++.IP ++panic test binary after duration d (default 0, timeout disabled) ++.HP ++\fB\-test\fR.trace file ++.IP ++write an execution trace to file ++.HP ++\fB\-test\fR.v ++.IP ++verbose: print additional output ++.TP ++\fB\-v\fR ++prints current version and exits ++.SH "SEE ALSO" ++The full documentation for ++.B Grafana ++is available on-line at ++.BR http://docs.grafana.org/ . diff --git a/003-golang1.15.patch b/003-golang1.15.patch new file mode 100644 index 0000000..d568703 --- /dev/null +++ b/003-golang1.15.patch @@ -0,0 +1,85 @@ +diff --git a/pkg/api/dashboard_test.go b/pkg/api/dashboard_test.go +index b58cf217d3..90e110974e 100644 +--- a/pkg/api/dashboard_test.go ++++ b/pkg/api/dashboard_test.go +@@ -3,6 +3,7 @@ package api + import ( + "encoding/json" + "fmt" ++ "strconv" + "io/ioutil" + "testing" + +@@ -828,7 +829,7 @@ func TestDashboardApiEndpoint(t *testing.T) { + bus.AddHandler("test", func(query *models.GetDashboardVersionQuery) error { + query.Result = &models.DashboardVersion{ + Data: simplejson.NewFromAny(map[string]interface{}{ +- "title": "Dash" + string(query.DashboardId), ++ "title": "Dash" + strconv.FormatInt(query.DashboardId, 10), + }), + } + return nil +diff --git a/pkg/components/gtime/gtime_test.go b/pkg/components/gtime/gtime_test.go +index 4dab30fbf6..e4ba096a43 100644 +--- a/pkg/components/gtime/gtime_test.go ++++ b/pkg/components/gtime/gtime_test.go +@@ -22,7 +22,7 @@ func TestParseInterval(t *testing.T) { + {interval: "1M", duration: now.Sub(now.AddDate(0, -1, 0))}, + {interval: "1y", duration: now.Sub(now.AddDate(-1, 0, 0))}, + {interval: "5y", duration: now.Sub(now.AddDate(-5, 0, 0))}, +- {interval: "invalid-duration", err: "time: invalid duration invalid-duration"}, ++ {interval: "invalid-duration", err: "time: invalid duration \"invalid-duration\""}, + } + + for i, tc := range tcs { +diff --git a/pkg/services/sqlstore/alert_notification_test.go b/pkg/services/sqlstore/alert_notification_test.go +index 75d5582022..4986d0d781 100644 +--- a/pkg/services/sqlstore/alert_notification_test.go ++++ b/pkg/services/sqlstore/alert_notification_test.go +@@ -168,7 +168,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) { + cmd.Frequency = "invalid duration" + + err := CreateAlertNotificationCommand(cmd) +- So(err.Error(), ShouldEqual, "time: invalid duration invalid duration") ++ So(err.Error(), ShouldEqual, "time: invalid duration \"invalid duration\"") + }) + }) + +@@ -199,7 +199,7 @@ func TestAlertNotificationSQLAccess(t *testing.T) { + + err := UpdateAlertNotification(updateCmd) + So(err, ShouldNotBeNil) +- So(err.Error(), ShouldEqual, "time: invalid duration invalid duration") ++ So(err.Error(), ShouldEqual, "time: invalid duration \"invalid duration\"") + }) + }) + +diff --git a/pkg/services/sqlstore/sqlbuilder_test.go b/pkg/services/sqlstore/sqlbuilder_test.go +index 42159171b0..abf669d294 100644 +--- a/pkg/services/sqlstore/sqlbuilder_test.go ++++ b/pkg/services/sqlstore/sqlbuilder_test.go +@@ -5,6 +5,7 @@ import ( + "math/rand" + "testing" + "time" ++ "strconv" + + "github.com/grafana/grafana/pkg/components/simplejson" + "github.com/grafana/grafana/pkg/models" +@@ -193,12 +194,12 @@ func test(t *testing.T, dashboardProps DashboardProps, dashboardPermission *Dash + func createDummyUser() (*models.User, error) { + uid := rand.Intn(9999999) + createUserCmd := &models.CreateUserCommand{ +- Email: string(uid) + "@example.com", +- Login: string(uid), +- Name: string(uid), ++ Email: strconv.Itoa(uid) + "@example.com", ++ Login: strconv.Itoa(uid), ++ Name: strconv.Itoa(uid), + Company: "", + OrgName: "", +- Password: string(uid), ++ Password: strconv.Itoa(uid), + EmailVerified: true, + IsAdmin: false, + SkipOrgSetup: false, diff --git a/004-remove-goldenfiles-test.patch b/004-remove-goldenfiles-test.patch new file mode 100644 index 0000000..bc08ffc --- /dev/null +++ b/004-remove-goldenfiles-test.patch @@ -0,0 +1,17 @@ +diff --git a/pkg/tsdb/influxdb/flux/executor_test.go b/pkg/tsdb/influxdb/flux/executor_test.go +index b42389c94d..a24e16f97e 100644 +--- a/pkg/tsdb/influxdb/flux/executor_test.go ++++ b/pkg/tsdb/influxdb/flux/executor_test.go +@@ -285,12 +285,3 @@ func TestBuckets(t *testing.T) { + fmt.Println("----------------------") + }) + } +- +-func TestGoldenFiles(t *testing.T) { +- t.Run("Renamed", func(t *testing.T) { +- _, err := verifyGoldenResponse("renamed") +- if err != nil { +- t.Fatal(err.Error()) +- } +- }) +-} diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..3f1696f --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +all: grafana-vendor-$(VER).tar.gz \ + grafana-vendor-$(VER).tar.gz.manifest \ + grafana-webpack-$(VER).tar.gz \ + grafana-webpack-$(VER).tar.gz.manifest + +grafana-$(VER).tar.gz grafana-$(VER): + wget https://github.com/grafana/grafana/archive/v$(VER)/grafana-$(VER).tar.gz + tar xfz grafana-$(VER).tar.gz + +grafana-vendor-$(VER).tar.gz: grafana-$(VER).tar.gz + cd grafana-$(VER) && go mod vendor -v + tar cfz $@ grafana-$(VER)/vendor + +grafana-vendor-$(VER).tar.gz.manifest: grafana-$(VER).tar.gz + awk '$$2~/^v/ && $$4 != "indirect" {print "Provides: bundled(golang(" $$1 ")) = " substr($$2, 2)}' grafana-$(VER)/go.mod | \ + sed -E 's/=(.*)-(.*)-(.*)/=\1-\2.\3/g' > $@ + +grafana-webpack-$(VER).tar.gz: grafana-$(VER).tar.gz + cd grafana-$(VER) && yarn install --pure-lockfile && yarn run build + cd grafana-$(VER) && \ + mkdir plugins-bundled/external && yarn run plugins:build-bundled && \ + for plugin in plugins-bundled/internal/*; do mv $$plugin $$plugin.tmp; mv $$plugin.tmp/dist $$plugin; rm -rf $$plugin.tmp; done && \ + rm plugins-bundled/README.md plugins-bundled/.gitignore plugins-bundled/external.json + tar cfz $@ grafana-$(VER)/public/build grafana-$(VER)/public/views grafana-$(VER)/plugins-bundled + +grafana-webpack-$(VER).tar.gz.manifest: grafana-$(VER).tar.gz + ./create_webpack_manifest.py grafana-$(VER)/ > $@ + +clean: + rm -rf *.tar.gz grafana-*/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..1c34177 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# grafana +The grafana package + +## Upgrade instructions +(replace X.Y.Z with the new Grafana version) + +* update `Version` and `%changelog` in the specfile +* create bundles and manifests: `VER=X.Y.Z make` +* update specfile with contents of `grafana-vendor-X.Y.Z.tar.gz.manifest` and `grafana-webpack-X.Y.Z.tar.gz.manifest` +* check if the default configuration has changed: `diff grafana-X.Y.Z/conf/defaults.ini distro-defaults.ini` and update `distro-defaults.ini` if necessary +* run local build: `rpkg local` +* run rpm linter: `rpkg lint` +* run local builds with different OS versions: `./run_container_build.sh version` +* run a scratch build: `fedpkg scratch-build --srpm` +* upload new source tarballs: `fedpkg new-sources grafana-X.Y.Z.tar.gz grafana-vendor-X.Y.Z.tar.gz grafana-webpack-X.Y.Z.tar.gz` diff --git a/create_webpack_manifest.py b/create_webpack_manifest.py new file mode 100755 index 0000000..0f62106 --- /dev/null +++ b/create_webpack_manifest.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +import sys +import json +import re +from packaging import version + + +def read_declared_pkgs(package_json_path): + with open(package_json_path) as f: + package_json = json.load(f) + return list(package_json['dependencies'].keys()) + + +def read_installed_pkgs(yarn_lock_path): + with open(yarn_lock_path) as f: + lockfile = f.read() + return re.findall(r'^"?' # can start with a " + r'(.+?)@.+(?:,.*)?:\n' # characters up to @ + r' version "(.+)"', # and the version + lockfile, re.MULTILINE) + + +def list_provides(declared_pkgs, installed_pkgs): + for declared_pkg in declared_pkgs: + # there can be multiple versions installed of one package (transitive dependencies) + # but rpm doesn't support Provides: with a single package and multiple versions + # so let's declare the oldest version here + versions = [version.parse(pkg_version) + for pkg_name, pkg_version in installed_pkgs if pkg_name == declared_pkg] + oldest_version = sorted(versions)[0] + yield f"Provides: bundled(nodejs-{declared_pkg}) = {oldest_version}" + + +if __name__ == "__main__": + if len(sys.argv) != 2: + print(f"usage: {sys.argv[0]} grafana-X.Y.Z/", file=sys.stdout) + sys.exit(1) + + grafana_dir = sys.argv[1] + declared_pkgs = read_declared_pkgs(f"{grafana_dir}/package.json") + installed_pkgs = read_installed_pkgs(f"{grafana_dir}/yarn.lock") + provides = list_provides(declared_pkgs, installed_pkgs) + for provide in sorted(provides): + print(provide) diff --git a/distro-defaults.ini b/distro-defaults.ini new file mode 100644 index 0000000..7b61f6e --- /dev/null +++ b/distro-defaults.ini @@ -0,0 +1,773 @@ +##################### Grafana Configuration Defaults for distros ##################### +# +# Do not modify this file in grafana installs +# + +# possible values : production, development +app_mode = production + +# instance name, defaults to HOSTNAME environment variable value or hostname if HOSTNAME var is empty +instance_name = ${HOSTNAME} + +#################################### Paths ############################### +[paths] +# Path to where grafana can store temp files, sessions, and the sqlite3 db (if that is used) +data = /var/lib/grafana + +# Temporary files in `data` directory older than given duration will be removed +temp_data_lifetime = 24h + +# Directory where grafana can store logs +logs = /var/log/grafana + +# Directory where grafana will automatically scan and look for plugins +plugins = /var/lib/grafana/plugins + +# folder that contains provisioning config files that grafana will apply on startup and while running. +provisioning = /etc/grafana/provisioning + +#################################### Server ############################## +[server] +# Protocol (http, https, h2, socket) +protocol = http + +# The ip address to bind to, empty will bind to all interfaces +http_addr = + +# The http port to use +http_port = 3000 + +# The public facing domain name used to access grafana from a browser +domain = localhost + +# Redirect to correct domain if host header does not match domain +# Prevents DNS rebinding attacks +enforce_domain = false + +# The full public facing url +root_url = %(protocol)s://%(domain)s:%(http_port)s/ + +# Serve Grafana from subpath specified in `root_url` setting. By default it is set to `false` for compatibility reasons. +serve_from_sub_path = false + +# Log web requests +router_logging = false + +# the path relative working path +static_root_path = public + +# enable gzip +enable_gzip = false + +# https certs & key file +cert_file = +cert_key = + +# Unix socket path +socket = /tmp/grafana.sock + +#################################### Database ############################ +[database] +# You can configure the database connection by specifying type, host, name, user and password +# as separate properties or as on string using the url property. + +# Either "mysql", "postgres" or "sqlite3", it's your choice +type = sqlite3 +host = 127.0.0.1:3306 +name = grafana +user = root +# If the password contains # or ; you have to wrap it with triple quotes. Ex """#password;""" +password = +# Use either URL or the previous fields to configure the database +# Example: mysql://user:secret@host:port/database +url = + +# Max idle conn setting default is 2 +max_idle_conn = 2 + +# Max conn setting default is 0 (mean not set) +max_open_conn = + +# Connection Max Lifetime default is 14400 (means 14400 seconds or 4 hours) +conn_max_lifetime = 14400 + +# Set to true to log the sql calls and execution times. +log_queries = + +# For "postgres", use either "disable", "require" or "verify-full" +# For "mysql", use either "true", "false", or "skip-verify". +ssl_mode = disable + +ca_cert_path = +client_key_path = +client_cert_path = +server_cert_name = + +# For "sqlite3" only, path relative to data_path setting +path = grafana.db + +# For "sqlite3" only. cache mode setting used for connecting to the database +cache_mode = private + +#################################### Cache server ############################# +[remote_cache] +# Either "redis", "memcached" or "database" default is "database" +type = database + +# cache connectionstring options +# database: will use Grafana primary database. +# redis: config like redis server e.g. `addr=127.0.0.1:6379,pool_size=100,db=0,ssl=false`. Only addr is required. ssl may be 'true', 'false', or 'insecure'. +# memcache: 127.0.0.1:11211 +connstr = + +#################################### Data proxy ########################### +[dataproxy] + +# This enables data proxy logging, default is false +logging = false + +# How long the data proxy waits before timing out, default is 30 seconds. +# This setting also applies to core backend HTTP data sources where query requests use an HTTP client with timeout set. +timeout = 30 + +# If enabled and user is not anonymous, data proxy will add X-Grafana-User header with username into the request, default is false. +send_user_header = false + +#################################### Analytics ########################### +[analytics] +# Server reporting, sends usage counters to stats.grafana.org every 24 hours. +# No ip addresses are being tracked, only simple counters to track +# running instances, dashboard and error counts. It is very helpful to us. +# Change this option to false to disable reporting. +reporting_enabled = false + +# Set to false to disable all checks to https://grafana.com +# for new versions (grafana itself and plugins), check is used +# in some UI views to notify that grafana or plugin update exists +# This option does not cause any auto updates, nor send any information +# only a GET request to https://grafana.com to get latest versions +check_for_updates = false + +# Google Analytics universal tracking code, only enabled if you specify an id here +google_analytics_ua_id = + +# Google Tag Manager ID, only enabled if you specify an id here +google_tag_manager_id = + +#################################### Security ############################ +[security] +# disable creation of admin user on first start of grafana +disable_initial_admin_creation = false + +# default admin user, created on startup +admin_user = admin + +# default admin password, can be changed before first start of grafana, or in profile settings +admin_password = admin + +# used for signing +secret_key = SW2YcwTIb9zpOOhoPsMm + +# disable gravatar profile images +disable_gravatar = false + +# data source proxy whitelist (ip_or_domain:port separated by spaces) +data_source_proxy_whitelist = + +# disable protection against brute force login attempts +disable_brute_force_login_protection = false + +# set to true if you host Grafana behind HTTPS. default is false. +cookie_secure = false + +# set cookie SameSite attribute. defaults to `lax`. can be set to "lax", "strict", "none" and "disabled" +cookie_samesite = lax + +# set to true if you want to allow browsers to render Grafana in a ,