diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8d9599f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+SOURCES/grafana-7.5.9.tar.gz
+SOURCES/grafana-vendor-7.5.9-2.tar.xz
+SOURCES/grafana-webpack-7.5.9-2.tar.gz
diff --git a/.grafana.metadata b/.grafana.metadata
new file mode 100644
index 0000000..af2fa86
--- /dev/null
+++ b/.grafana.metadata
@@ -0,0 +1,3 @@
+e658bc3706a71a2a77f34755ac362fd506d7b1a0 SOURCES/grafana-7.5.9.tar.gz
+8fc46c12ac1bae0f2e0434e8fdf71e61e922c74a SOURCES/grafana-vendor-7.5.9-2.tar.xz
+28052475c9cb45ac6523479ab9fd3da4ba678400 SOURCES/grafana-webpack-7.5.9-2.tar.gz
diff --git a/SOURCES/001-wrappers-grafana-cli.patch b/SOURCES/001-wrappers-grafana-cli.patch
new file mode 100644
index 0000000..01fe90e
--- /dev/null
+++ b/SOURCES/001-wrappers-grafana-cli.patch
@@ -0,0 +1,49 @@
+diff --git a/packaging/wrappers/grafana-cli b/packaging/wrappers/grafana-cli
+index 9cad151c0d..a786edc596 100755
+--- a/packaging/wrappers/grafana-cli
++++ b/packaging/wrappers/grafana-cli
+@@ -5,18 +5,19 @@
+ # the system-wide Grafana configuration that was bundled with the package as we
+ # use the binary.
+
+-DEFAULT=/etc/default/grafana
++DEFAULT=/etc/sysconfig/grafana-server
+
+ 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
++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
+@@ -36,4 +38,13 @@ OPTS="--homepath=${GRAFANA_HOME} \
+ cfg:default.paths.logs=${LOG_DIR} \
+ cfg:default.paths.plugins=${PLUGINS_DIR}'"
+
+-eval $EXECUTABLE "$OPTS" "$@"
++if [ "$(id -u)" -eq 0 ]; then
++ cd "${GRAFANA_HOME}"
++ exec runuser -u "${GRAFANA_USER}" -- "$EXECUTABLE" "$OPTS" "$@"
++elif [ "$(id -u -n)" = "${GRAFANA_USER}" ]; then
++ cd "${GRAFANA_HOME}"
++ exec "$EXECUTABLE" "$OPTS" "$@"
++else
++ echo "$0: please run this script as user \"${GRAFANA_USER}\" or root."
++ exit 5
++fi
diff --git a/SOURCES/002-manpages.patch b/SOURCES/002-manpages.patch
new file mode 100644
index 0000000..ccc1385
--- /dev/null
+++ b/SOURCES/002-manpages.patch
@@ -0,0 +1,144 @@
+diff --git a/docs/man/man1/grafana-cli.1 b/docs/man/man1/grafana-cli.1
+new file mode 100644
+index 0000000000..7ac2af882c
+--- /dev/null
++++ b/docs/man/man1/grafana-cli.1
+@@ -0,0 +1,60 @@
++.TH GRAFANA "1" "June 2021" "Grafana cli version 7.5.9" "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\-\-configOverrides\fR value
++Configuration options to override defaults as a string. e.g. cfg:default.paths.log=/dev/null
++.TP
++\fB\-\-homepath\fR value
++Path to Grafana install/home path, defaults to working directory
++.TP
++\fB\-\-config\fR value
++Path to config file
++.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..c616268b31
+--- /dev/null
++++ b/docs/man/man1/grafana-server.1
+@@ -0,0 +1,72 @@
++.TH VERSION "1" "June 2021" "Version 7.5.9" "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.
++.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 uint
++.IP
++Define custom port for profiling (default 6060)
++.HP
++\fB\-tracing\fR
++.IP
++Turn on tracing
++.HP
++\fB\-tracing\-file\fR string
++.IP
++Define tracing output file (default "trace.out")
++.TP
++\fB\-v\fR
++.IP
++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/SOURCES/003-fix-dashboard-abspath-test.patch b/SOURCES/003-fix-dashboard-abspath-test.patch
new file mode 100644
index 0000000..ad7e5bf
--- /dev/null
+++ b/SOURCES/003-fix-dashboard-abspath-test.patch
@@ -0,0 +1,24 @@
+diff --git a/pkg/services/provisioning/dashboards/file_reader_linux_test.go b/pkg/services/provisioning/dashboards/file_reader_linux_test.go
+index 3584bbc242..1a89767b69 100644
+--- a/pkg/services/provisioning/dashboards/file_reader_linux_test.go
++++ b/pkg/services/provisioning/dashboards/file_reader_linux_test.go
+@@ -28,6 +28,7 @@ func TestProvisionedSymlinkedFolder(t *testing.T) {
+ }
+
+ want, err := filepath.Abs(containingID)
++ want, err = filepath.EvalSymlinks(want)
+
+ if err != nil {
+ t.Errorf("expected err to be nil")
+diff --git a/pkg/services/provisioning/dashboards/file_reader_test.go b/pkg/services/provisioning/dashboards/file_reader_test.go
+index 946d487d5f..2acef40eed 100644
+--- a/pkg/services/provisioning/dashboards/file_reader_test.go
++++ b/pkg/services/provisioning/dashboards/file_reader_test.go
+@@ -318,6 +318,7 @@ func TestDashboardFileReader(t *testing.T) {
+ }
+
+ absPath1, err := filepath.Abs(unprovision + "/dashboard1.json")
++ absPath1, err = filepath.EvalSymlinks(absPath1)
+ So(err, ShouldBeNil)
+ // This one does not exist on disk, simulating a deleted file
+ absPath2, err := filepath.Abs(unprovision + "/dashboard2.json")
diff --git a/SOURCES/004-skip-x86-goldenfiles-tests.patch b/SOURCES/004-skip-x86-goldenfiles-tests.patch
new file mode 100644
index 0000000..bb61e0b
--- /dev/null
+++ b/SOURCES/004-skip-x86-goldenfiles-tests.patch
@@ -0,0 +1,69 @@
+diff --git a/packages/grafana-data/src/dataframe/ArrowDataFrame.test.ts b/packages/grafana-data/src/dataframe/ArrowDataFrame.test.ts
+index 96efaccfce..bcdd98144f 100644
+--- a/packages/grafana-data/src/dataframe/ArrowDataFrame.test.ts
++++ b/packages/grafana-data/src/dataframe/ArrowDataFrame.test.ts
+@@ -52,7 +52,7 @@ describe('Read/Write arrow Table to DataFrame', () => {
+ expect(after).toEqual(before);
+ });
+
+- test('should read all types', () => {
++ test.skip('should read all types', () => {
+ const fullpath = path.resolve(__dirname, './__snapshots__/all_types.golden.arrow');
+ const arrow = fs.readFileSync(fullpath);
+ const table = Table.from([arrow]);
+diff --git a/packages/grafana-runtime/src/utils/queryResponse.test.ts b/packages/grafana-runtime/src/utils/queryResponse.test.ts
+index 0adb915d2c..8985d7beab 100644
+--- a/packages/grafana-runtime/src/utils/queryResponse.test.ts
++++ b/packages/grafana-runtime/src/utils/queryResponse.test.ts
+@@ -47,7 +47,7 @@ const emptyResults = {
+ /* eslint-enable */
+
+ describe('Query Response parser', () => {
+- test('should parse output with dataframe', () => {
++ test.skip('should parse output with dataframe', () => {
+ const res = toDataQueryResponse(resp);
+ const frames = res.data;
+ expect(frames).toHaveLength(2);
+@@ -131,7 +131,7 @@ describe('Query Response parser', () => {
+ `);
+ });
+
+- test('should parse output with dataframe in order of queries', () => {
++ test.skip('should parse output with dataframe in order of queries', () => {
+ const queries: DataQuery[] = [{ refId: 'B' }, { refId: 'A' }];
+ const res = toDataQueryResponse(resp, queries);
+ const frames = res.data;
+@@ -250,7 +250,7 @@ describe('Query Response parser', () => {
+ expect(ids).toEqual(['A', 'B', 'X']);
+ });
+
+- test('resultWithError', () => {
++ test.skip('resultWithError', () => {
+ // Generated from:
+ // qdr.Responses[q.GetRefID()] = backend.DataResponse{
+ // Error: fmt.Errorf("an Error: %w", fmt.Errorf("another error")),
+diff --git a/pkg/tsdb/influxdb/flux/executor_test.go b/pkg/tsdb/influxdb/flux/executor_test.go
+index 7cfc8bd20a..add6b5f3b8 100644
+--- a/pkg/tsdb/influxdb/flux/executor_test.go
++++ b/pkg/tsdb/influxdb/flux/executor_test.go
+@@ -68,6 +68,7 @@ func executeMockedQuery(t *testing.T, name string, query queryModel) *backend.Da
+ }
+
+ func verifyGoldenResponse(t *testing.T, name string) *backend.DataResponse {
++ t.Skip("x86 memory dump is not compatible with other architectures")
+ dr := executeMockedQuery(t, name, queryModel{MaxDataPoints: 100})
+
+ err := experimental.CheckGoldenDataResponse(filepath.Join("testdata", fmt.Sprintf("%s.golden.txt", name)),
+diff --git a/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts b/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts
+index afc8ba357b..587092a58d 100644
+--- a/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts
++++ b/public/app/plugins/datasource/cloudwatch/specs/datasource.test.ts
+@@ -78,7 +78,7 @@ describe('CloudWatchDatasource', () => {
+ });
+
+ describe('When getting log groups', () => {
+- it('should return log groups as an array of strings', async () => {
++ it.skip('should return log groups as an array of strings', async () => {
+ const response = {
+ results: {
+ A: {
diff --git a/SOURCES/005-remove-unused-dependencies.patch b/SOURCES/005-remove-unused-dependencies.patch
new file mode 100644
index 0000000..19d72f0
--- /dev/null
+++ b/SOURCES/005-remove-unused-dependencies.patch
@@ -0,0 +1,63 @@
+diff --git a/go.mod b/go.mod
+index 426b70ab7a..dc0c9a61ef 100644
+--- a/go.mod
++++ b/go.mod
+@@ -21,7 +21,6 @@ require (
+ github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b
+ github.com/centrifugal/centrifuge v0.13.0
+ github.com/cortexproject/cortex v1.4.1-0.20201022071705-85942c5703cf
+- github.com/crewjam/saml v0.4.6-0.20201227203850-bca570abb2ce
+ github.com/davecgh/go-spew v1.1.1
+ github.com/denisenkom/go-mssqldb v0.0.0-20200910202707-1e08a3fab204
+ github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 // indirect
+@@ -57,7 +56,6 @@ require (
+ github.com/jmespath/go-jmespath v0.4.0
+ github.com/jonboulle/clockwork v0.2.2 // indirect
+ github.com/json-iterator/go v1.1.10
+- github.com/jung-kurt/gofpdf v1.16.2
+ github.com/lib/pq v1.9.0
+ github.com/linkedin/goavro/v2 v2.10.0
+ github.com/magefile/mage v1.11.0
+diff --git a/go.sum b/go.sum
+index 98874d6a7c..03243066ac 100644
+--- a/go.sum
++++ b/go.sum
+@@ -282,8 +282,6 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsr
+ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+ github.com/crewjam/httperr v0.0.0-20190612203328-a946449404da/go.mod h1:+rmNIXRvYMqLQeR4DHyTvs6y0MEMymTz4vyFpFkKTPs=
+-github.com/crewjam/saml v0.4.6-0.20201227203850-bca570abb2ce h1:pAuTpLhCqC20s2RLhUirfw606jReW+8z2U5EvG+0S7E=
+-github.com/crewjam/saml v0.4.6-0.20201227203850-bca570abb2ce/go.mod h1:/gCaeLf13J8/621RNZ6TaExji/8xCWcn6UmdJ57wURQ=
+ github.com/crossdock/crossdock-go v0.0.0-20160816171116-049aabb0122b/go.mod h1:v9FBN7gdVTpiD/+LZ7Po0UKvROyT87uLVxTHVky/dlQ=
+ github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
+ github.com/cznic/b v0.0.0-20180115125044-35e9bbe41f07/go.mod h1:URriBxXwVq5ijiJ12C7iIZqlA69nTlI+LgI6/pwftG8=
+@@ -914,10 +912,6 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7
+ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
+ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+ github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
+-github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
+-github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
+-github.com/jung-kurt/gofpdf v1.16.2 h1:jgbatWHfRlPYiK85qgevsZTHviWXKwB1TTiKdz5PtRc=
+-github.com/jung-kurt/gofpdf v1.16.2/go.mod h1:1hl7y57EsiPAkLbOwzpzqgx1A30nQCk/YmFV8S2vmK0=
+ github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0=
+ github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM=
+ github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
+diff --git a/pkg/extensions/main.go b/pkg/extensions/main.go
+index 24031ace2e..081475fc89 100644
+--- a/pkg/extensions/main.go
++++ b/pkg/extensions/main.go
+@@ -6,14 +6,12 @@ import (
+
+ _ "github.com/beevik/etree"
+ _ "github.com/cortexproject/cortex/pkg/util"
+- _ "github.com/crewjam/saml"
+ _ "github.com/gobwas/glob"
+ "github.com/grafana/grafana/pkg/registry"
+ "github.com/grafana/grafana/pkg/services/licensing"
+ "github.com/grafana/grafana/pkg/services/validations"
+ _ "github.com/grafana/loki/pkg/logproto"
+ _ "github.com/grpc-ecosystem/go-grpc-middleware"
+- _ "github.com/jung-kurt/gofpdf"
+ _ "github.com/linkedin/goavro/v2"
+ _ "github.com/pkg/errors"
+ _ "github.com/robfig/cron"
diff --git a/SOURCES/006-fix-gtime-test-32bit.patch b/SOURCES/006-fix-gtime-test-32bit.patch
new file mode 100644
index 0000000..c38a50f
--- /dev/null
+++ b/SOURCES/006-fix-gtime-test-32bit.patch
@@ -0,0 +1,17 @@
+diff --git a/pkg/components/gtime/gtime_test.go b/pkg/components/gtime/gtime_test.go
+index 0b1b23a1db..eb9fe718c7 100644
+--- a/pkg/components/gtime/gtime_test.go
++++ b/pkg/components/gtime/gtime_test.go
+@@ -20,9 +20,9 @@ func TestParseInterval(t *testing.T) {
+ {inp: "1d", duration: 24 * time.Hour},
+ {inp: "1w", duration: 168 * time.Hour},
+ {inp: "2w", duration: 2 * 168 * time.Hour},
+- {inp: "1M", duration: time.Duration(daysInMonth * 24 * int(time.Hour))},
+- {inp: "1y", duration: time.Duration(daysInYear * 24 * int(time.Hour))},
+- {inp: "5y", duration: time.Duration(calculateDays5y() * 24 * int(time.Hour))},
++ {inp: "1M", duration: time.Duration(int64(daysInMonth) * 24 * int64(time.Hour))},
++ {inp: "1y", duration: time.Duration(int64(daysInYear) * 24 * int64(time.Hour))},
++ {inp: "5y", duration: time.Duration(int64(calculateDays5y()) * 24 * int64(time.Hour))},
+ {inp: "invalid-duration", err: regexp.MustCompile(`^time: invalid duration "?invalid-duration"?$`)},
+ }
+ for i, tc := range tcs {
diff --git a/SOURCES/008-remove-unused-frontend-crypto.patch b/SOURCES/008-remove-unused-frontend-crypto.patch
new file mode 100644
index 0000000..2409e23
--- /dev/null
+++ b/SOURCES/008-remove-unused-frontend-crypto.patch
@@ -0,0 +1,26 @@
+diff --git a/package.json b/package.json
+index 9c5a2d93e2..7f65949ea4 100644
+--- a/package.json
++++ b/package.json
+@@ -294,6 +294,9 @@
+ "whatwg-fetch": "3.1.0"
+ },
+ "resolutions": {
++ "crypto-browserify": "https://registry.yarnpkg.com/@favware/skip-dependency/-/skip-dependency-1.1.1.tgz",
++ "selfsigned": "https://registry.yarnpkg.com/@favware/skip-dependency/-/skip-dependency-1.1.1.tgz",
++ "http-signature": "https://registry.yarnpkg.com/@favware/skip-dependency/-/skip-dependency-1.1.1.tgz",
+ "caniuse-db": "1.0.30000772",
+ "react-use-measure": "https://github.com/mckn/react-use-measure.git#remove-cjs-export"
+ },
+diff --git a/scripts/webpack/webpack.common.js b/scripts/webpack/webpack.common.js
+index 3e56d31c37..a03ed1a67a 100644
+--- a/scripts/webpack/webpack.common.js
++++ b/scripts/webpack/webpack.common.js
+@@ -66,6 +66,7 @@ module.exports = {
+ },
+ node: {
+ fs: 'empty',
++ crypto: false,
+ },
+ plugins: [
+ new MonacoWebpackPlugin({
diff --git a/SOURCES/009-patch-unused-backend-crypto.patch b/SOURCES/009-patch-unused-backend-crypto.patch
new file mode 100644
index 0000000..12be571
--- /dev/null
+++ b/SOURCES/009-patch-unused-backend-crypto.patch
@@ -0,0 +1,168 @@
+diff --git a/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go b/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go
+new file mode 100644
+index 0000000..871e612
+--- /dev/null
++++ b/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go
+@@ -0,0 +1,25 @@
++package elgamal
++
++import (
++ "io"
++ "math/big"
++)
++
++// PublicKey represents an ElGamal public key.
++type PublicKey struct {
++ G, P, Y *big.Int
++}
++
++// PrivateKey represents an ElGamal private key.
++type PrivateKey struct {
++ PublicKey
++ X *big.Int
++}
++
++func Encrypt(random io.Reader, pub *PublicKey, msg []byte) (c1, c2 *big.Int, err error) {
++ panic("ElGamal encryption not available")
++}
++
++func Decrypt(priv *PrivateKey, c1, c2 *big.Int) (msg []byte, err error) {
++ panic("ElGamal encryption not available")
++}
+diff --git a/vendor/golang.org/x/crypto/openpgp/packet/packet.go b/vendor/golang.org/x/crypto/openpgp/packet/packet.go
+index 9728d61..9f04c2d 100644
+--- a/vendor/golang.org/x/crypto/openpgp/packet/packet.go
++++ b/vendor/golang.org/x/crypto/openpgp/packet/packet.go
+@@ -16,7 +16,6 @@ import (
+ "math/big"
+ "math/bits"
+
+- "golang.org/x/crypto/cast5"
+ "golang.org/x/crypto/openpgp/errors"
+ )
+
+@@ -487,7 +486,7 @@ func (cipher CipherFunction) KeySize() int {
+ case Cipher3DES:
+ return 24
+ case CipherCAST5:
+- return cast5.KeySize
++ panic("cast5 cipher not available")
+ case CipherAES128:
+ return 16
+ case CipherAES192:
+@@ -517,7 +516,7 @@ func (cipher CipherFunction) new(key []byte) (block cipher.Block) {
+ case Cipher3DES:
+ block, _ = des.NewTripleDESCipher(key)
+ case CipherCAST5:
+- block, _ = cast5.NewCipher(key)
++ panic("cast5 cipher not available")
+ case CipherAES128, CipherAES192, CipherAES256:
+ block, _ = aes.NewCipher(key)
+ }
+diff --git a/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go b/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go
+index 6126030..3a54c5f 100644
+--- a/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go
++++ b/vendor/golang.org/x/crypto/openpgp/packet/symmetrically_encrypted.go
+@@ -5,13 +5,12 @@
+ package packet
+
+ import (
+- "crypto/cipher"
+ "crypto/sha1"
+ "crypto/subtle"
+- "golang.org/x/crypto/openpgp/errors"
+ "hash"
+ "io"
+- "strconv"
++
++ "golang.org/x/crypto/openpgp/errors"
+ )
+
+ // SymmetricallyEncrypted represents a symmetrically encrypted byte string. The
+@@ -45,46 +44,7 @@ func (se *SymmetricallyEncrypted) parse(r io.Reader) error {
+ // packet can be read. An incorrect key can, with high probability, be detected
+ // immediately and this will result in a KeyIncorrect error being returned.
+ func (se *SymmetricallyEncrypted) Decrypt(c CipherFunction, key []byte) (io.ReadCloser, error) {
+- keySize := c.KeySize()
+- if keySize == 0 {
+- return nil, errors.UnsupportedError("unknown cipher: " + strconv.Itoa(int(c)))
+- }
+- if len(key) != keySize {
+- return nil, errors.InvalidArgumentError("SymmetricallyEncrypted: incorrect key length")
+- }
+-
+- if se.prefix == nil {
+- se.prefix = make([]byte, c.blockSize()+2)
+- _, err := readFull(se.contents, se.prefix)
+- if err != nil {
+- return nil, err
+- }
+- } else if len(se.prefix) != c.blockSize()+2 {
+- return nil, errors.InvalidArgumentError("can't try ciphers with different block lengths")
+- }
+-
+- ocfbResync := OCFBResync
+- if se.MDC {
+- // MDC packets use a different form of OCFB mode.
+- ocfbResync = OCFBNoResync
+- }
+-
+- s := NewOCFBDecrypter(c.new(key), se.prefix, ocfbResync)
+- if s == nil {
+- return nil, errors.ErrKeyIncorrect
+- }
+-
+- plaintext := cipher.StreamReader{S: s, R: se.contents}
+-
+- if se.MDC {
+- // MDC packets have an embedded hash that we need to check.
+- h := sha1.New()
+- h.Write(se.prefix)
+- return &seMDCReader{in: plaintext, h: h}, nil
+- }
+-
+- // Otherwise, we just need to wrap plaintext so that it's a valid ReadCloser.
+- return seReader{plaintext}, nil
++ panic("OCFB cipher not available")
+ }
+
+ // seReader wraps an io.Reader with a no-op Close method.
+@@ -254,37 +214,5 @@ func (c noOpCloser) Close() error {
+ // written.
+ // If config is nil, sensible defaults will be used.
+ func SerializeSymmetricallyEncrypted(w io.Writer, c CipherFunction, key []byte, config *Config) (contents io.WriteCloser, err error) {
+- if c.KeySize() != len(key) {
+- return nil, errors.InvalidArgumentError("SymmetricallyEncrypted.Serialize: bad key length")
+- }
+- writeCloser := noOpCloser{w}
+- ciphertext, err := serializeStreamHeader(writeCloser, packetTypeSymmetricallyEncryptedMDC)
+- if err != nil {
+- return
+- }
+-
+- _, err = ciphertext.Write([]byte{symmetricallyEncryptedVersion})
+- if err != nil {
+- return
+- }
+-
+- block := c.new(key)
+- blockSize := block.BlockSize()
+- iv := make([]byte, blockSize)
+- _, err = config.Random().Read(iv)
+- if err != nil {
+- return
+- }
+- s, prefix := NewOCFBEncrypter(block, iv, OCFBNoResync)
+- _, err = ciphertext.Write(prefix)
+- if err != nil {
+- return
+- }
+- plaintext := cipher.StreamWriter{S: s, W: ciphertext}
+-
+- h := sha1.New()
+- h.Write(iv)
+- h.Write(iv[blockSize-2:])
+- contents = &seMDCWriter{w: plaintext, h: h}
+- return
++ panic("OCFB cipher not available")
+ }
diff --git a/SOURCES/010-fips.patch b/SOURCES/010-fips.patch
new file mode 100644
index 0000000..f9adee9
--- /dev/null
+++ b/SOURCES/010-fips.patch
@@ -0,0 +1,140 @@
+diff --git a/vendor/golang.org/x/crypto/internal/boring/boring.go b/vendor/golang.org/x/crypto/internal/boring/boring.go
+new file mode 100644
+index 0000000..a9c550e
+--- /dev/null
++++ b/vendor/golang.org/x/crypto/internal/boring/boring.go
+@@ -0,0 +1,74 @@
++// Copyright 2017 The Go Authors. All rights reserved.
++// Copyright 2021 Red Hat.
++// Use of this source code is governed by a BSD-style
++// license that can be found in the LICENSE file.
++
++// +build linux
++// +build !android
++// +build !no_openssl
++// +build !cmd_go_bootstrap
++// +build !msan
++
++package boring
++
++// #include "openssl_pbkdf2.h"
++// #cgo LDFLAGS: -ldl
++import "C"
++import (
++ "bytes"
++ "crypto/sha1"
++ "crypto/sha256"
++ "hash"
++ "unsafe"
++)
++
++var (
++ emptySha1 = sha1.Sum([]byte{})
++ emptySha256 = sha256.Sum256([]byte{})
++)
++
++func hashToMD(h hash.Hash) *C.GO_EVP_MD {
++ emptyHash := h.Sum([]byte{})
++
++ switch {
++ case bytes.Equal(emptyHash, emptySha1[:]):
++ return C._goboringcrypto_EVP_sha1()
++ case bytes.Equal(emptyHash, emptySha256[:]):
++ return C._goboringcrypto_EVP_sha256()
++ }
++ return nil
++}
++
++// charptr returns the address of the underlying array in b,
++// being careful not to panic when b has zero length.
++func charptr(b []byte) *C.char {
++ if len(b) == 0 {
++ return nil
++ }
++ return (*C.char)(unsafe.Pointer(&b[0]))
++}
++
++// ucharptr returns the address of the underlying array in b,
++// being careful not to panic when b has zero length.
++func ucharptr(b []byte) *C.uchar {
++ if len(b) == 0 {
++ return nil
++ }
++ return (*C.uchar)(unsafe.Pointer(&b[0]))
++}
++
++func Pbkdf2Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
++ // println("[debug] using pbkdf2 from OpenSSL")
++ ch := h()
++ md := hashToMD(ch)
++ if md == nil {
++ return nil
++ }
++
++ out := make([]byte, keyLen)
++ ok := C._goboringcrypto_PKCS5_PBKDF2_HMAC(charptr(password), C.int(len(password)), ucharptr(salt), C.int(len(salt)), C.int(iter), md, C.int(keyLen), ucharptr(out))
++ if ok != 1 {
++ panic("boringcrypto: PKCS5_PBKDF2_HMAC failed")
++ }
++ return out
++}
+diff --git a/vendor/golang.org/x/crypto/internal/boring/notboring.go b/vendor/golang.org/x/crypto/internal/boring/notboring.go
+new file mode 100644
+index 0000000..e244fb5
+--- /dev/null
++++ b/vendor/golang.org/x/crypto/internal/boring/notboring.go
+@@ -0,0 +1,16 @@
++// Copyright 2017 The Go Authors. All rights reserved.
++// Copyright 2021 Red Hat.
++// Use of this source code is governed by a BSD-style
++// license that can be found in the LICENSE file.
++
++// +build !linux !cgo android cmd_go_bootstrap msan no_openssl
++
++package boring
++
++import (
++ "hash"
++)
++
++func Pbkdf2Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
++ panic("boringcrypto: not available")
++}
+diff --git a/vendor/golang.org/x/crypto/internal/boring/openssl_pbkdf2.h b/vendor/golang.org/x/crypto/internal/boring/openssl_pbkdf2.h
+new file mode 100644
+index 0000000..6dfdf10
+--- /dev/null
++++ b/vendor/golang.org/x/crypto/internal/boring/openssl_pbkdf2.h
+@@ -0,0 +1,5 @@
++#include "/usr/lib/golang/src/crypto/internal/boring/goboringcrypto.h"
++
++DEFINEFUNC(int, PKCS5_PBKDF2_HMAC,
++ (const char *pass, int passlen, const unsigned char *salt, int saltlen, int iter, EVP_MD *digest, int keylen, unsigned char *out),
++ (pass, passlen, salt, saltlen, iter, digest, keylen, out))
+diff --git a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go
+index 593f653..799a611 100644
+--- a/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go
++++ b/vendor/golang.org/x/crypto/pbkdf2/pbkdf2.go
+@@ -19,8 +19,11 @@ pbkdf2.Key.
+ package pbkdf2 // import "golang.org/x/crypto/pbkdf2"
+
+ import (
++ "crypto/boring"
+ "crypto/hmac"
+ "hash"
++
++ xboring "golang.org/x/crypto/internal/boring"
+ )
+
+ // Key derives a key from the password, salt and iteration count, returning a
+@@ -40,6 +43,10 @@ import (
+ // Using a higher iteration count will increase the cost of an exhaustive
+ // search but will also make derivation proportionally slower.
+ func Key(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
++ if boring.Enabled() {
++ return xboring.Pbkdf2Key(password, salt, iter, keyLen, h)
++ }
++
+ prf := hmac.New(h, password)
+ hashLen := prf.Size()
+ numBlocks := (keyLen + hashLen - 1) / hashLen
diff --git a/SOURCES/Makefile b/SOURCES/Makefile
new file mode 100644
index 0000000..acd932c
--- /dev/null
+++ b/SOURCES/Makefile
@@ -0,0 +1,63 @@
+ifndef VER
+ $(error VER is undefined)
+endif
+ifndef REL
+ $(error REL is undefined)
+endif
+
+NAME := grafana
+RPM_NAME := $(NAME)
+SOURCE_DIR := $(NAME)-$(VER)
+SOURCE_TAR := $(NAME)-$(VER).tar.gz
+VENDOR_TAR := $(RPM_NAME)-vendor-$(VER)-$(REL).tar.xz
+WEBPACK_TAR := $(RPM_NAME)-webpack-$(VER)-$(REL).tar.gz
+
+ALL_PATCHES := $(wildcard *.patch)
+PATCHES_TO_APPLY := $(filter-out 009-patch-unused-backend-crypto.patch 010-fips.patch,$(ALL_PATCHES))
+
+all: $(SOURCE_TAR) $(VENDOR_TAR) $(WEBPACK_TAR)
+
+$(SOURCE_TAR):
+ spectool -g $(RPM_NAME).spec
+
+$(VENDOR_TAR): $(SOURCE_TAR)
+ rm -rf grafana-$(VER)
+ tar xfz grafana-$(VER).tar.gz
+
+ # patches can affect Go or Node.js dependencies, or the webpack
+ for patch in $(PATCHES_TO_APPLY); do patch -d grafana-$(VER) -p1 --fuzz=0 < $$patch; done
+
+ # Go
+ cd grafana-$(VER) && go mod vendor -v
+ # Remove unused crypto
+ rm grafana-$(VER)/vendor/golang.org/x/crypto/cast5/cast5.go
+ rm grafana-$(VER)/vendor/golang.org/x/crypto/ed25519/ed25519.go
+ rm grafana-$(VER)/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/const.go
+ rm grafana-$(VER)/vendor/golang.org/x/crypto/ed25519/internal/edwards25519/edwards25519.go
+ rm grafana-$(VER)/vendor/golang.org/x/crypto/openpgp/elgamal/elgamal.go
+ rm grafana-$(VER)/vendor/golang.org/x/crypto/openpgp/packet/ocfb.go
+ awk '$$2~/^v/ && $$4 != "indirect" {print "Provides: bundled(golang(" $$1 ")) = " substr($$2, 2)}' grafana-$(VER)/go.mod | \
+ sed -E 's/=(.*)-(.*)-(.*)/=\1-\2.\3/g' > $@.manifest
+
+ # Node.js
+ cd grafana-$(VER) && yarn install --pure-lockfile
+ # Remove files with licensing issues
+ find grafana-$(VER) -type d -name 'node-notifier' -prune -exec rm -r {} \;
+ find grafana-$(VER) -type d -name 'property-information' -prune -exec rm -r {} \;
+ find grafana-$(VER) -type f -name '*.exe' -delete
+ rm -r grafana-$(VER)/node_modules/visjs-network/examples
+ ./list_bundled_nodejs_packages.py grafana-$(VER)/ >> $@.manifest
+
+ # Create tarball
+ XZ_OPT=-9 tar cfJ $@ \
+ grafana-$(VER)/vendor \
+ $$(find grafana-$(VER) -type d -name "node_modules" -prune)
+
+$(WEBPACK_TAR): $(VENDOR_TAR)
+ cd grafana-$(VER) && \
+ ../build_frontend.sh
+
+ tar cfz $@ grafana-$(VER)/public/build grafana-$(VER)/public/views grafana-$(VER)/plugins-bundled
+
+clean:
+ rm -rf *.tar.gz *.tar.xz *.manifest *.rpm $(NAME)-*/
diff --git a/SOURCES/build_frontend.sh b/SOURCES/build_frontend.sh
new file mode 100755
index 0000000..fa0fb8e
--- /dev/null
+++ b/SOURCES/build_frontend.sh
@@ -0,0 +1,17 @@
+#!/bin/bash -eu
+
+# Build the frontend
+yarn run build
+
+# Build the bundled plugins
+mkdir plugins-bundled/external
+yarn run plugins:build-bundled
+for plugin in plugins-bundled/internal/input-datasource; 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
+
+# Fix permissions (webpack sometimes outputs files with mode = 666 due to reasons unknown (race condition/umask issue afaics))
+chmod -R g-w,o-w public/build plugins-bundled
diff --git a/SOURCES/distro-defaults.ini b/SOURCES/distro-defaults.ini
new file mode 100644
index 0000000..daa0679
--- /dev/null
+++ b/SOURCES/distro-defaults.ini
@@ -0,0 +1,942 @@
+##################### Grafana Configuration Defaults #####################
+#
+# 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
+
+# CDN Url
+cdn_url =
+
+# Sets the maximum time in minutes before timing out read of an incoming request and closing idle connections.
+# `0` means there is no timeout for reading the request.
+read_timeout = 0
+
+#################################### 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
+
+# Database drivers may support different transaction isolation levels.
+# Currently, only "mysql" driver supports isolation levels.
+# If the value is empty - driver's default isolation level is applied.
+# For "mysql" use "READ-UNCOMMITTED", "READ-COMMITTED", "REPEATABLE-READ" or "SERIALIZABLE".
+isolation_level =
+
+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
+
+# How many seconds the data proxy waits before sending a keepalive request.
+keep_alive_seconds = 30
+
+# How many seconds the data proxy waits for a successful TLS Handshake before timing out.
+tls_handshake_timeout_seconds = 10
+
+# How many seconds the data proxy will wait for a server's first response headers after
+# fully writing the request headers if the request has an "Expect: 100-continue"
+# header. A value of 0 will result in the body being sent immediately, without
+# waiting for the server to approve.
+expect_continue_timeout_seconds = 1
+
+# Optionally limits the total number of connections per host, including connections in the dialing,
+# active, and idle states. On limit violation, dials will block.
+# A value of zero (0) means no limit.
+max_conns_per_host = 0
+
+# The maximum number of idle connections that Grafana will keep alive.
+max_idle_connections = 100
+
+# The maximum number of idle connections per host that Grafana will keep alive.
+max_idle_connections_per_host = 2
+
+# How many seconds the data proxy keeps an idle connection open before timing out.
+idle_conn_timeout_seconds = 90
+
+# If enabled and user is not anonymous, data proxy will add X-Grafana-User header with username into the request.
+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
+
+# The name of the distributor of the Grafana instance. Ex hosted-grafana, grafana-labs
+reporting_distributor = grafana-labs
+
+# 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 ,