Skip to content

Commit

Permalink
Merge pull request #14024 from bergquist/cp_v5.3.x
Browse files Browse the repository at this point in the history
Cherry picks for v5.3.4
  • Loading branch information
bergquist authored Nov 13, 2018
2 parents 77cd62d + 802387e commit 69630b9
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 26 deletions.
1 change: 1 addition & 0 deletions conf/defaults.ini
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ header_property = username
auto_sign_up = true
ldap_sync_ttl = 60
whitelist =
headers =

#################################### Auth LDAP ###########################
[auth.ldap]
Expand Down
1 change: 1 addition & 0 deletions conf/sample.ini
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"company": "Grafana Labs"
},
"name": "grafana",
"version": "5.3.3",
"version": "5.3.4",
"repository": {
"type": "git",
"url": "http://github.com/grafana/grafana.git"
Expand Down
4 changes: 4 additions & 0 deletions pkg/api/pluginproxy/ds_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
26 changes: 26 additions & 0 deletions pkg/api/pluginproxy/ds_proxy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
})
})
})
}

Expand Down
12 changes: 10 additions & 2 deletions public/app/features/dashboard/export/export_modal.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,19 @@
You can share dashboards on <a class="external-link" href="https://grafana.com">Grafana.com</a>
</p>

<gf-form-switch
class="gf-form"
label="Export for sharing externally"
label-class="width-16"
checked="ctrl.shareExternally"
tooltip="Useful for sharing dashboard publicly on grafana.com. Will templatize data source names. Can then only be used with the specific dashboard import API.">
</gf-form-switch>

<div class="gf-form-button-row">
<button type="button" class="btn gf-form-btn width-10 btn-success" ng-click="ctrl.save()">
<button type="button" class="btn gf-form-btn width-10 btn-success" ng-click="ctrl.saveDashboardAsFile()">
<i class="fa fa-save"></i> Save to file
</button>
<button type="button" class="btn gf-form-btn width-10 btn-secondary" ng-click="ctrl.saveJson()">
<button type="button" class="btn gf-form-btn width-10 btn-secondary" ng-click="ctrl.viewJson()">
<i class="fa fa-file-text-o"></i> View JSON
</button>
<a class="btn btn-link" ng-click="ctrl.dismiss()">Cancel</a>
Expand Down
38 changes: 29 additions & 9 deletions public/app/features/dashboard/export/export_modal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

saveDashboardAsFile() {
if (this.shareExternally) {
this.exporter.makeExportable(this.dash).then((dashboardJson: any) => {
this.$scope.$apply(() => {
this.openSaveAsDialog(dashboardJson);
});
});
});
} else {
this.openSaveAsDialog(this.dash.getSaveModelClone());
}
}

viewJson() {
if (this.shareExternally) {
this.exporter.makeExportable(this.dash).then((dashboardJson: any) => {
this.$scope.$apply(() => {
this.openJsonModal(dashboardJson);
});
});
} else {
this.openJsonModal(this.dash.getSaveModelClone());
}
}

save() {
const blob = new Blob([angular.toJson(this.dash, true)], {
private openSaveAsDialog(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;
private openJsonModal(clone: any) {
const editScope = this.$rootScope.$new();
editScope.object = clone;
editScope.enableCopy = true;
Expand Down
33 changes: 22 additions & 11 deletions public/app/features/dashboard/export/exporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 + '}';
})
);
};
Expand Down
14 changes: 12 additions & 2 deletions public/app/features/dashboard/specs/exporter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [],
},
],
Expand Down Expand Up @@ -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
Expand All @@ -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: {
Expand Down
2 changes: 1 addition & 1 deletion public/app/features/templating/template_srv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 69630b9

Please sign in to comment.