From 50efe02b224e9908b10dbb013584bd3a74d8a32d Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 5 Nov 2018 17:32:28 +0100 Subject: [PATCH 1/8] export: provide more help regarding export format this will provide the user with more info about the export format and default to not use the format for sharing on grafana.com etc. ref #13781 (cherry picked from commit 17adb58d803008562faaaa6ff51546816154e773) --- .../dashboard/export/export_modal.html | 12 +++++- .../features/dashboard/export/export_modal.ts | 40 ++++++++++++++----- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/public/app/features/dashboard/export/export_modal.html b/public/app/features/dashboard/export/export_modal.html index 0598c612fd6..3505e50b821 100644 --- a/public/app/features/dashboard/export/export_modal.html +++ b/public/app/features/dashboard/export/export_modal.html @@ -15,11 +15,19 @@ You can share dashboards on Grafana.com

+ + +
- - Cancel diff --git a/public/app/features/dashboard/export/export_modal.ts b/public/app/features/dashboard/export/export_modal.ts index f99946915d6..08a79702ed5 100644 --- a/public/app/features/dashboard/export/export_modal.ts +++ b/public/app/features/dashboard/export/export_modal.ts @@ -8,27 +8,47 @@ export class DashExportCtrl { dash: any; exporter: DashboardExporter; dismiss: () => void; + shareExternally: boolean; /** @ngInject */ constructor(private dashboardSrv, datasourceSrv, private $scope, private $rootScope) { this.exporter = new DashboardExporter(datasourceSrv); - this.exporter.makeExportable(this.dashboardSrv.getCurrent()).then(dash => { - this.$scope.$apply(() => { - this.dash = dash; - }); - }); + this.dash = this.dashboardSrv.getCurrent(); } - save() { - const blob = new Blob([angular.toJson(this.dash, true)], { + saveDashboardAsFile() { + if (this.shareExternally) { + this.exporter.makeExportable(this.dash).then((dashboardJson: any) => { + this.$scope.$apply(() => { + this._saveFile(dashboardJson); + }); + }); + } else { + this._saveFile(this.dash.getSaveModelClone()); + } + } + + viewJson() { + if (this.shareExternally) { + this.exporter.makeExportable(this.dash).then((dashboardJson: any) => { + this.$scope.$apply(() => { + this._viewJson(dashboardJson); + }); + }); + } else { + this._viewJson(this.dash.getSaveModelClone()); + } + } + + _saveFile(dash: any) { + const blob = new Blob([angular.toJson(dash, true)], { type: 'application/json;charset=utf-8', }); - saveAs(blob, this.dash.title + '-' + new Date().getTime() + '.json'); + saveAs(blob, dash.title + '-' + new Date().getTime() + '.json'); } - saveJson() { - const clone = this.dash; + _viewJson(clone: any) { const editScope = this.$rootScope.$new(); editScope.object = clone; editScope.enableCopy = true; From 4fa671acc14f63e9e9602486aa785ec190865187 Mon Sep 17 00:00:00 2001 From: bergquist Date: Tue, 6 Nov 2018 09:00:17 +0100 Subject: [PATCH 2/8] rename and mark functions as private (cherry picked from commit 7bde98aff9789c071bb3221d50ffe17798e371bb) --- public/app/features/dashboard/export/export_modal.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/public/app/features/dashboard/export/export_modal.ts b/public/app/features/dashboard/export/export_modal.ts index 08a79702ed5..0e48041ca87 100644 --- a/public/app/features/dashboard/export/export_modal.ts +++ b/public/app/features/dashboard/export/export_modal.ts @@ -21,11 +21,11 @@ export class DashExportCtrl { if (this.shareExternally) { this.exporter.makeExportable(this.dash).then((dashboardJson: any) => { this.$scope.$apply(() => { - this._saveFile(dashboardJson); + this.openSaveAsDialog(dashboardJson); }); }); } else { - this._saveFile(this.dash.getSaveModelClone()); + this.openSaveAsDialog(this.dash.getSaveModelClone()); } } @@ -33,22 +33,22 @@ export class DashExportCtrl { if (this.shareExternally) { this.exporter.makeExportable(this.dash).then((dashboardJson: any) => { this.$scope.$apply(() => { - this._viewJson(dashboardJson); + this.openJsonModal(dashboardJson); }); }); } else { - this._viewJson(this.dash.getSaveModelClone()); + this.openJsonModal(this.dash.getSaveModelClone()); } } - _saveFile(dash: any) { + private openSaveAsDialog(dash: any) { const blob = new Blob([angular.toJson(dash, true)], { type: 'application/json;charset=utf-8', }); saveAs(blob, dash.title + '-' + new Date().getTime() + '.json'); } - _viewJson(clone: any) { + private openJsonModal(clone: any) { const editScope = this.$rootScope.$new(); editScope.object = clone; editScope.enableCopy = true; From 43e78db0f6da8e4b6b1957c8e180b0db6ee57ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 7 Nov 2018 11:14:39 -0800 Subject: [PATCH 3/8] fixed exporter bug missing adding requires for datasources only used via data source variable, fixes #13891 (cherry picked from commit 99610e040fe020dafe064420253441148f9394ed) --- .../app/features/dashboard/export/exporter.ts | 33 ++++++++++++------- .../features/dashboard/specs/exporter.test.ts | 14 ++++++-- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/public/app/features/dashboard/export/exporter.ts b/public/app/features/dashboard/export/exporter.ts index d0802be72db..7aecb5c384f 100644 --- a/public/app/features/dashboard/export/exporter.ts +++ b/public/app/features/dashboard/export/exporter.ts @@ -29,19 +29,36 @@ export class DashboardExporter { } const templateizeDatasourceUsage = obj => { + let datasource = obj.datasource; + let datasourceVariable = null; + // ignore data source properties that contain a variable - if (obj.datasource && obj.datasource.indexOf('$') === 0) { - if (variableLookup[obj.datasource.substring(1)]) { - return; + if (datasource && datasource.indexOf('$') === 0) { + datasourceVariable = variableLookup[datasource.substring(1)]; + if (datasourceVariable && datasourceVariable.current) { + datasource = datasourceVariable.current.value; } } promises.push( - this.datasourceSrv.get(obj.datasource).then(ds => { + this.datasourceSrv.get(datasource).then(ds => { if (ds.meta.builtIn) { return; } + // add data source type to require list + requires['datasource' + ds.meta.id] = { + type: 'datasource', + id: ds.meta.id, + name: ds.meta.name, + version: ds.meta.info.version || '1.0.0', + }; + + // if used via variable we can skip templatizing usage + if (datasourceVariable) { + return; + } + const refName = 'DS_' + ds.name.replace(' ', '_').toUpperCase(); datasources[refName] = { name: refName, @@ -51,14 +68,8 @@ export class DashboardExporter { pluginId: ds.meta.id, pluginName: ds.meta.name, }; - obj.datasource = '${' + refName + '}'; - requires['datasource' + ds.meta.id] = { - type: 'datasource', - id: ds.meta.id, - name: ds.meta.name, - version: ds.meta.info.version || '1.0.0', - }; + obj.datasource = '${' + refName + '}'; }) ); }; diff --git a/public/app/features/dashboard/specs/exporter.test.ts b/public/app/features/dashboard/specs/exporter.test.ts index c7a232f925b..130b8ddbaea 100644 --- a/public/app/features/dashboard/specs/exporter.test.ts +++ b/public/app/features/dashboard/specs/exporter.test.ts @@ -32,8 +32,8 @@ describe('given dashboard with repeated panels', () => { { name: 'ds', type: 'datasource', - query: 'testdb', - current: { value: 'prod', text: 'prod' }, + query: 'other2', + current: { value: 'other2', text: 'other2' }, options: [], }, ], @@ -205,6 +205,11 @@ describe('given dashboard with repeated panels', () => { expect(variable.options[0].text).toBe('${VAR_PREFIX}'); expect(variable.options[0].value).toBe('${VAR_PREFIX}'); }); + + it('should add datasources only use via datasource variable to requires', () => { + const require = _.find(exported.__requires, { name: 'OtherDB_2' }); + expect(require.id).toBe('other2'); + }); }); // Stub responses @@ -219,6 +224,11 @@ stubs['other'] = { meta: { id: 'other', info: { version: '1.2.1' }, name: 'OtherDB' }, }; +stubs['other2'] = { + name: 'other2', + meta: { id: 'other2', info: { version: '1.2.1' }, name: 'OtherDB_2' }, +}; + stubs['-- Mixed --'] = { name: 'mixed', meta: { From 16517b304069ecc086582d7d1672674055536fa1 Mon Sep 17 00:00:00 2001 From: Dan Cech Date: Wed, 7 Nov 2018 17:36:44 -0500 Subject: [PATCH 4/8] add auth.proxy headers to default.ini (cherry picked from commit 502290817a5008c0f1c98c5ffe439ad5eb1d37a0) --- conf/defaults.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/defaults.ini b/conf/defaults.ini index eb8debc0094..01d3f378aeb 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -344,6 +344,7 @@ header_property = username auto_sign_up = true ldap_sync_ttl = 60 whitelist = +headers = #################################### Auth LDAP ########################### [auth.ldap] From 7a8e246349dd0d53cc11912ff27415a227d63a0d Mon Sep 17 00:00:00 2001 From: Dan Cech Date: Wed, 7 Nov 2018 18:21:25 -0500 Subject: [PATCH 5/8] add auth.proxy headers to sample.ini (cherry picked from commit 8a74fe2b76a5644ec16d3b622eaae6ff75871299) --- conf/sample.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/conf/sample.ini b/conf/sample.ini index e6a03718d19..c12ccbea8ec 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -294,6 +294,7 @@ log_queries = ;auto_sign_up = true ;ldap_sync_ttl = 60 ;whitelist = 192.168.1.1, 192.168.2.1 +;headers = Email:X-User-Email, Name:X-User-Name #################################### Basic Auth ########################## [auth.basic] From a23780ddf02a70974f79cb6f92ceacb260b7c4bf Mon Sep 17 00:00:00 2001 From: Julien Pivotto Date: Thu, 8 Nov 2018 12:30:10 +0100 Subject: [PATCH 6/8] Remove Origin and Referer headers while proxying requests Fix #13949 Fix #13328 Signed-off-by: Julien Pivotto (cherry picked from commit 62417ca69fbccb330a25768fbb667c72263cd9d3) --- pkg/api/pluginproxy/ds_proxy.go | 4 ++++ pkg/api/pluginproxy/ds_proxy_test.go | 26 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/pkg/api/pluginproxy/ds_proxy.go b/pkg/api/pluginproxy/ds_proxy.go index 0c000058e4b..38a2fd187e3 100644 --- a/pkg/api/pluginproxy/ds_proxy.go +++ b/pkg/api/pluginproxy/ds_proxy.go @@ -195,6 +195,10 @@ func (proxy *DataSourceProxy) getDirector() func(req *http.Request) { req.Header.Del("X-Forwarded-Proto") req.Header.Set("User-Agent", fmt.Sprintf("Grafana/%s", setting.BuildVersion)) + // Clear Origin and Referer to avoir CORS issues + req.Header.Del("Origin") + req.Header.Del("Referer") + // set X-Forwarded-For header if req.RemoteAddr != "" { remoteAddr, _, err := net.SplitHostPort(req.RemoteAddr) diff --git a/pkg/api/pluginproxy/ds_proxy_test.go b/pkg/api/pluginproxy/ds_proxy_test.go index 7dcd187c368..c9be169565f 100644 --- a/pkg/api/pluginproxy/ds_proxy_test.go +++ b/pkg/api/pluginproxy/ds_proxy_test.go @@ -362,6 +362,32 @@ func TestDSRouteRule(t *testing.T) { }) }) + Convey("When proxying a custom datasource", func() { + plugin := &plugins.DataSourcePlugin{} + ds := &m.DataSource{ + Type: "custom-datasource", + Url: "http://host/root/", + } + ctx := &m.ReqContext{} + proxy := NewDataSourceProxy(ds, plugin, ctx, "/path/to/folder/") + req, err := http.NewRequest(http.MethodGet, "http://grafana.com/sub", nil) + req.Header.Add("Origin", "grafana.com") + req.Header.Add("Referer", "grafana.com") + req.Header.Add("X-Canary", "stillthere") + So(err, ShouldBeNil) + + proxy.getDirector()(req) + + Convey("Should keep user request (including trailing slash)", func() { + So(req.URL.String(), ShouldEqual, "http://host/root/path/to/folder/") + }) + + Convey("Origin and Referer headers should be dropped", func() { + So(req.Header.Get("Origin"), ShouldEqual, "") + So(req.Header.Get("Referer"), ShouldEqual, "") + So(req.Header.Get("X-Canary"), ShouldEqual, "stillthere") + }) + }) }) } From 82bf655ec1ffa9bb0df78147c4790df6f95d45df Mon Sep 17 00:00:00 2001 From: Augustin Husson Date: Thu, 8 Nov 2018 16:23:40 +0100 Subject: [PATCH 7/8] don't drop the value when it equals to None (cherry picked from commit 2abf8a0e8bbf3b9734193c5a432e80d7260ec320) --- public/app/features/templating/template_srv.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/features/templating/template_srv.ts b/public/app/features/templating/template_srv.ts index 61326ad63ec..ef8139d8257 100644 --- a/public/app/features/templating/template_srv.ts +++ b/public/app/features/templating/template_srv.ts @@ -28,7 +28,7 @@ export class TemplateSrv { const existsOrEmpty = value => value || value === ''; this.index = this.variables.reduce((acc, currentValue) => { - if (currentValue.current && !currentValue.current.isNone && existsOrEmpty(currentValue.current.value)) { + if (currentValue.current && (currentValue.current.isNone || existsOrEmpty(currentValue.current.value))) { acc[currentValue.name] = currentValue; } return acc; From a7c82192ab9a17fdae6ea032e6e2ecc98cf7ff6f Mon Sep 17 00:00:00 2001 From: bergquist Date: Mon, 12 Nov 2018 11:53:41 +0100 Subject: [PATCH 8/8] release 5.3.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 85546d0813c..ee5f2d8b190 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "company": "Grafana Labs" }, "name": "grafana", - "version": "5.3.2", + "version": "5.3.4", "repository": { "type": "git", "url": "http://github.com/grafana/grafana.git"