Quellcode durchsuchen

Merge remote-tracking branch 'grafana/master' into alpha-react-table

* grafana/master:
  Fixed styling of gicon's in dropdown menus
  cleanup plugin versions
  use explore icon
  fix comments
  typescript functions on replace
  remove console.log
  add ScopedVars to replace function
  Expose onQueryChange to angular plugins
  fix allow anonymous initial bind for ldap search
ryan vor 6 Jahren
Ursprung
Commit
ea5db92996

+ 2 - 1
packages/grafana-ui/src/types/panel.ts

@@ -1,8 +1,9 @@
 import { ComponentClass } from 'react';
 import { ComponentClass } from 'react';
 import { TimeSeries, LoadingState, TableData } from './data';
 import { TimeSeries, LoadingState, TableData } from './data';
 import { TimeRange } from './time';
 import { TimeRange } from './time';
+import { ScopedVars } from './datasource';
 
 
-export type InterpolateFunction = (value: string, format?: string | Function) => string;
+export type InterpolateFunction = (value: string, scopedVars?: ScopedVars, format?: string | Function) => string;
 
 
 export interface PanelProps<T = any> {
 export interface PanelProps<T = any> {
   panelData: PanelData;
   panelData: PanelData;

+ 12 - 1
pkg/login/ldap.go

@@ -18,6 +18,7 @@ import (
 
 
 type ILdapConn interface {
 type ILdapConn interface {
 	Bind(username, password string) error
 	Bind(username, password string) error
+	UnauthenticatedBind(username string) error
 	Search(*ldap.SearchRequest) (*ldap.SearchResult, error)
 	Search(*ldap.SearchRequest) (*ldap.SearchResult, error)
 	StartTLS(*tls.Config) error
 	StartTLS(*tls.Config) error
 	Close()
 	Close()
@@ -259,7 +260,17 @@ func (a *ldapAuther) initialBind(username, userPassword string) error {
 		bindPath = fmt.Sprintf(a.server.BindDN, username)
 		bindPath = fmt.Sprintf(a.server.BindDN, username)
 	}
 	}
 
 
-	if err := a.conn.Bind(bindPath, userPassword); err != nil {
+	bindFn := func() error {
+		return a.conn.Bind(bindPath, userPassword)
+	}
+
+	if userPassword == "" {
+		bindFn = func() error {
+			return a.conn.UnauthenticatedBind(bindPath)
+		}
+	}
+
+	if err := bindFn(); err != nil {
 		a.log.Info("Initial bind failed", "error", err)
 		a.log.Info("Initial bind failed", "error", err)
 
 
 		if ldapErr, ok := err.(*ldap.Error); ok {
 		if ldapErr, ok := err.(*ldap.Error); ok {

+ 81 - 3
pkg/login/ldap_test.go

@@ -13,6 +13,70 @@ import (
 )
 )
 
 
 func TestLdapAuther(t *testing.T) {
 func TestLdapAuther(t *testing.T) {
+	Convey("initialBind", t, func() {
+		Convey("Given bind dn and password configured", func() {
+			conn := &mockLdapConn{}
+			var actualUsername, actualPassword string
+			conn.bindProvider = func(username, password string) error {
+				actualUsername = username
+				actualPassword = password
+				return nil
+			}
+			ldapAuther := &ldapAuther{
+				conn: conn,
+				server: &LdapServerConf{
+					BindDN:       "cn=%s,o=users,dc=grafana,dc=org",
+					BindPassword: "bindpwd",
+				},
+			}
+			err := ldapAuther.initialBind("user", "pwd")
+			So(err, ShouldBeNil)
+			So(ldapAuther.requireSecondBind, ShouldBeTrue)
+			So(actualUsername, ShouldEqual, "cn=user,o=users,dc=grafana,dc=org")
+			So(actualPassword, ShouldEqual, "bindpwd")
+		})
+
+		Convey("Given bind dn configured", func() {
+			conn := &mockLdapConn{}
+			var actualUsername, actualPassword string
+			conn.bindProvider = func(username, password string) error {
+				actualUsername = username
+				actualPassword = password
+				return nil
+			}
+			ldapAuther := &ldapAuther{
+				conn: conn,
+				server: &LdapServerConf{
+					BindDN: "cn=%s,o=users,dc=grafana,dc=org",
+				},
+			}
+			err := ldapAuther.initialBind("user", "pwd")
+			So(err, ShouldBeNil)
+			So(ldapAuther.requireSecondBind, ShouldBeFalse)
+			So(actualUsername, ShouldEqual, "cn=user,o=users,dc=grafana,dc=org")
+			So(actualPassword, ShouldEqual, "pwd")
+		})
+
+		Convey("Given empty bind dn and password", func() {
+			conn := &mockLdapConn{}
+			unauthenticatedBindWasCalled := false
+			var actualUsername string
+			conn.unauthenticatedBindProvider = func(username string) error {
+				unauthenticatedBindWasCalled = true
+				actualUsername = username
+				return nil
+			}
+			ldapAuther := &ldapAuther{
+				conn:   conn,
+				server: &LdapServerConf{},
+			}
+			err := ldapAuther.initialBind("user", "pwd")
+			So(err, ShouldBeNil)
+			So(ldapAuther.requireSecondBind, ShouldBeTrue)
+			So(unauthenticatedBindWasCalled, ShouldBeTrue)
+			So(actualUsername, ShouldBeEmpty)
+		})
+	})
 
 
 	Convey("When translating ldap user to grafana user", t, func() {
 	Convey("When translating ldap user to grafana user", t, func() {
 
 
@@ -365,12 +429,26 @@ func TestLdapAuther(t *testing.T) {
 }
 }
 
 
 type mockLdapConn struct {
 type mockLdapConn struct {
-	result           *ldap.SearchResult
-	searchCalled     bool
-	searchAttributes []string
+	result                      *ldap.SearchResult
+	searchCalled                bool
+	searchAttributes            []string
+	bindProvider                func(username, password string) error
+	unauthenticatedBindProvider func(username string) error
 }
 }
 
 
 func (c *mockLdapConn) Bind(username, password string) error {
 func (c *mockLdapConn) Bind(username, password string) error {
+	if c.bindProvider != nil {
+		return c.bindProvider(username, password)
+	}
+
+	return nil
+}
+
+func (c *mockLdapConn) UnauthenticatedBind(username string) error {
+	if c.unauthenticatedBindProvider != nil {
+		return c.unauthenticatedBindProvider(username)
+	}
+
 	return nil
 	return nil
 }
 }
 
 

+ 35 - 0
public/app/features/dashboard/dashgrid/PanelChrome.test.tsx

@@ -0,0 +1,35 @@
+import { PanelChrome } from './PanelChrome';
+
+jest.mock('sass/_variables.generated.scss', () => ({
+  panelhorizontalpadding: 10,
+  panelVerticalPadding: 10,
+}));
+
+describe('PanelChrome', () => {
+  let chrome: PanelChrome;
+
+  beforeEach(() => {
+    chrome = new PanelChrome({
+      panel: {
+        scopedVars: {
+          aaa: { value: 'AAA', text: 'upperA' },
+          bbb: { value: 'BBB', text: 'upperB' },
+        },
+      },
+      dashboard: {},
+      plugin: {},
+      isFullscreen: false,
+    });
+  });
+
+  it('Should replace a panel variable', () => {
+    const out = chrome.replaceVariables('hello $aaa');
+    expect(out).toBe('hello AAA');
+  });
+
+  it('But it should prefer the local variable value', () => {
+    const extra = { aaa: { text: '???', value: 'XXX' } };
+    const out = chrome.replaceVariables('hello $aaa and $bbb', extra);
+    expect(out).toBe('hello XXX and BBB');
+  });
+});

+ 7 - 2
public/app/features/dashboard/dashgrid/PanelChrome.tsx

@@ -19,6 +19,7 @@ import { profiler } from 'app/core/profiler';
 import { DashboardModel, PanelModel } from '../state';
 import { DashboardModel, PanelModel } from '../state';
 import { PanelPlugin } from 'app/types';
 import { PanelPlugin } from 'app/types';
 import { DataQueryResponse, TimeRange, LoadingState, PanelData, DataQueryError } from '@grafana/ui';
 import { DataQueryResponse, TimeRange, LoadingState, PanelData, DataQueryError } from '@grafana/ui';
+import { ScopedVars } from '@grafana/ui';
 
 
 import variables from 'sass/_variables.generated.scss';
 import variables from 'sass/_variables.generated.scss';
 import templateSrv from 'app/features/templating/template_srv';
 import templateSrv from 'app/features/templating/template_srv';
@@ -85,8 +86,12 @@ export class PanelChrome extends PureComponent<Props, State> {
     });
     });
   };
   };
 
 
-  replaceVariables = (value: string, format?: string) => {
-    return templateSrv.replace(value, this.props.panel.scopedVars, format);
+  replaceVariables = (value: string, extraVars?: ScopedVars, format?: string) => {
+    let vars = this.props.panel.scopedVars;
+    if (extraVars) {
+      vars = vars ? { ...vars, ...extraVars } : extraVars;
+    }
+    return templateSrv.replace(value, vars, format);
   };
   };
 
 
   onDataResponse = (dataQueryResponse: DataQueryResponse) => {
   onDataResponse = (dataQueryResponse: DataQueryResponse) => {

+ 3 - 0
public/app/features/explore/QueryEditor.tsx

@@ -43,6 +43,9 @@ export default class QueryEditor extends PureComponent<QueryEditorProps, any> {
           this.props.onQueryChange(target);
           this.props.onQueryChange(target);
           this.props.onExecuteQuery();
           this.props.onExecuteQuery();
         },
         },
+        onQueryChange: () => {
+          this.props.onQueryChange(target);
+        },
         events: exploreEvents,
         events: exploreEvents,
         panel: { datasource, targets: [target] },
         panel: { datasource, targets: [target] },
         dashboard: {},
         dashboard: {},

+ 1 - 1
public/app/features/panel/metrics_panel_ctrl.ts

@@ -224,7 +224,7 @@ class MetricsPanelCtrl extends PanelCtrl {
       items.push({
       items.push({
         text: 'Explore',
         text: 'Explore',
         click: 'ctrl.explore();',
         click: 'ctrl.explore();',
-        icon: 'fa fa-fw fa-rocket',
+        icon: 'gicon gicon-explore',
         shortcut: 'x',
         shortcut: 'x',
       });
       });
     }
     }

+ 2 - 2
public/app/features/plugins/partials/plugin_edit.html

@@ -25,7 +25,7 @@
       </div>
       </div>
 
 
       <aside class="page-sidebar">
       <aside class="page-sidebar">
-        <section class="page-sidebar-section">
+        <section class="page-sidebar-section" ng-if="ctrl.model.info.version">
           <h4>Version</h4>
           <h4>Version</h4>
           <span>{{ctrl.model.info.version}}</span>
           <span>{{ctrl.model.info.version}}</span>
           <div ng-show="ctrl.model.hasUpdate">
           <div ng-show="ctrl.model.hasUpdate">
@@ -54,7 +54,7 @@
             </li>
             </li>
           </ul>
           </ul>
         </section>
         </section>
-        <section class="page-sidebar-section">
+        <section class="page-sidebar-section" ng-if="ctrl.model.info.links">
           <h5>Links</h4>
           <h5>Links</h4>
           <ul class="ui-list">
           <ul class="ui-list">
             <li ng-repeat="link in ctrl.model.info.links">
             <li ng-repeat="link in ctrl.model.info.links">

+ 2 - 2
public/app/features/templating/template_srv.ts

@@ -1,7 +1,7 @@
 import kbn from 'app/core/utils/kbn';
 import kbn from 'app/core/utils/kbn';
 import _ from 'lodash';
 import _ from 'lodash';
 import { variableRegex } from 'app/features/templating/variable';
 import { variableRegex } from 'app/features/templating/variable';
-import { TimeRange } from '@grafana/ui/src';
+import { TimeRange, ScopedVars } from '@grafana/ui/src';
 
 
 function luceneEscape(value) {
 function luceneEscape(value) {
   return value.replace(/([\!\*\+\-\=<>\s\&\|\(\)\[\]\{\}\^\~\?\:\\/"])/g, '\\$1');
   return value.replace(/([\!\*\+\-\=<>\s\&\|\(\)\[\]\{\}\^\~\?\:\\/"])/g, '\\$1');
@@ -220,7 +220,7 @@ export class TemplateSrv {
     return values;
     return values;
   }
   }
 
 
-  replace(target, scopedVars?, format?) {
+  replace(target: string, scopedVars?: ScopedVars, format?: string | Function) {
     if (!target) {
     if (!target) {
       return target;
       return target;
     }
     }

+ 1 - 2
public/app/plugins/datasource/cloudwatch/plugin.json

@@ -16,7 +16,6 @@
     "logos": {
     "logos": {
       "small": "img/amazon-web-services.png",
       "small": "img/amazon-web-services.png",
       "large": "img/amazon-web-services.png"
       "large": "img/amazon-web-services.png"
-    },
-    "version": "5.0.0"
+    }
   }
   }
 }
 }

+ 1 - 4
public/app/plugins/datasource/elasticsearch/plugin.json

@@ -14,10 +14,7 @@
       "small": "img/elasticsearch.svg",
       "small": "img/elasticsearch.svg",
       "large": "img/elasticsearch.svg"
       "large": "img/elasticsearch.svg"
     },
     },
-    "links": [
-      {"name": "elastic.co", "url": "https://www.elastic.co/products/elasticsearch"}
-    ],
-    "version": "5.0.0"
+    "links": [{ "name": "elastic.co", "url": "https://www.elastic.co/products/elasticsearch" }]
   },
   },
 
 
   "alerting": true,
   "alerting": true,

+ 1 - 2
public/app/plugins/datasource/graphite/plugin.json

@@ -31,7 +31,6 @@
         "name": "Graphite 1.1 Release",
         "name": "Graphite 1.1 Release",
         "url": "https://grafana.com/blog/2018/01/11/graphite-1.1-teaching-an-old-dog-new-tricks/"
         "url": "https://grafana.com/blog/2018/01/11/graphite-1.1-teaching-an-old-dog-new-tricks/"
       }
       }
-    ],
-    "version": "5.0.0"
+    ]
   }
   }
 }
 }

+ 1 - 2
public/app/plugins/datasource/influxdb/plugin.json

@@ -22,7 +22,6 @@
     "logos": {
     "logos": {
       "small": "img/influxdb_logo.svg",
       "small": "img/influxdb_logo.svg",
       "large": "img/influxdb_logo.svg"
       "large": "img/influxdb_logo.svg"
-    },
-    "version": "5.0.0"
+    }
   }
   }
 }
 }

+ 1 - 2
public/app/plugins/datasource/mysql/plugin.json

@@ -12,8 +12,7 @@
     "logos": {
     "logos": {
       "small": "img/mysql_logo.svg",
       "small": "img/mysql_logo.svg",
       "large": "img/mysql_logo.svg"
       "large": "img/mysql_logo.svg"
-    },
-    "version": "5.0.0"
+    }
   },
   },
 
 
   "alerting": true,
   "alerting": true,

+ 1 - 2
public/app/plugins/datasource/opentsdb/plugin.json

@@ -18,7 +18,6 @@
     "logos": {
     "logos": {
       "small": "img/opentsdb_logo.png",
       "small": "img/opentsdb_logo.png",
       "large": "img/opentsdb_logo.png"
       "large": "img/opentsdb_logo.png"
-    },
-    "version": "5.0.0"
+    }
   }
   }
 }
 }

+ 1 - 2
public/app/plugins/datasource/postgres/plugin.json

@@ -12,8 +12,7 @@
     "logos": {
     "logos": {
       "small": "img/postgresql_logo.svg",
       "small": "img/postgresql_logo.svg",
       "large": "img/postgresql_logo.svg"
       "large": "img/postgresql_logo.svg"
-    },
-    "version": "5.0.0"
+    }
   },
   },
 
 
   "alerting": true,
   "alerting": true,

+ 1 - 2
public/app/plugins/datasource/prometheus/plugin.json

@@ -42,7 +42,6 @@
         "name": "Prometheus",
         "name": "Prometheus",
         "url": "https://prometheus.io/"
         "url": "https://prometheus.io/"
       }
       }
-    ],
-    "version": "5.0.0"
+    ]
   }
   }
 }
 }

+ 1 - 2
public/app/plugins/panel/alertlist/plugin.json

@@ -14,7 +14,6 @@
     "logos": {
     "logos": {
       "small": "img/icn-singlestat-panel.svg",
       "small": "img/icn-singlestat-panel.svg",
       "large": "img/icn-singlestat-panel.svg"
       "large": "img/icn-singlestat-panel.svg"
-    },
-    "version": "5.0.0"
+    }
   }
   }
 }
 }

+ 1 - 2
public/app/plugins/panel/dashlist/plugin.json

@@ -14,7 +14,6 @@
     "logos": {
     "logos": {
       "small": "img/icn-dashlist-panel.svg",
       "small": "img/icn-dashlist-panel.svg",
       "large": "img/icn-dashlist-panel.svg"
       "large": "img/icn-dashlist-panel.svg"
-    },
-    "version": "5.0.0"
+    }
   }
   }
 }
 }

+ 1 - 2
public/app/plugins/panel/graph/plugin.json

@@ -14,7 +14,6 @@
     "logos": {
     "logos": {
       "small": "img/icn-graph-panel.svg",
       "small": "img/icn-graph-panel.svg",
       "large": "img/icn-graph-panel.svg"
       "large": "img/icn-graph-panel.svg"
-    },
-    "version": "5.0.0"
+    }
   }
   }
 }
 }

+ 1 - 2
public/app/plugins/panel/heatmap/plugin.json

@@ -18,7 +18,6 @@
     "links": [
     "links": [
       { "name": "Brendan Gregg - Heatmaps", "url": "http://www.brendangregg.com/heatmaps.html" },
       { "name": "Brendan Gregg - Heatmaps", "url": "http://www.brendangregg.com/heatmaps.html" },
       { "name": "Brendan Gregg - Latency Heatmaps", "url": " http://www.brendangregg.com/HeatMaps/latency.html" }
       { "name": "Brendan Gregg - Latency Heatmaps", "url": " http://www.brendangregg.com/HeatMaps/latency.html" }
-    ],
-    "version": "5.0.0"
+    ]
   }
   }
 }
 }

+ 1 - 2
public/app/plugins/panel/pluginlist/plugin.json

@@ -14,7 +14,6 @@
     "logos": {
     "logos": {
       "small": "img/icn-dashlist-panel.svg",
       "small": "img/icn-dashlist-panel.svg",
       "large": "img/icn-dashlist-panel.svg"
       "large": "img/icn-dashlist-panel.svg"
-    },
-    "version": "5.0.0"
+    }
   }
   }
 }
 }

+ 1 - 2
public/app/plugins/panel/singlestat/plugin.json

@@ -14,7 +14,6 @@
     "logos": {
     "logos": {
       "small": "img/icn-singlestat-panel.svg",
       "small": "img/icn-singlestat-panel.svg",
       "large": "img/icn-singlestat-panel.svg"
       "large": "img/icn-singlestat-panel.svg"
-    },
-    "version": "5.0.0"
+    }
   }
   }
 }
 }

+ 1 - 2
public/app/plugins/panel/table/plugin.json

@@ -14,7 +14,6 @@
     "logos": {
     "logos": {
       "small": "img/icn-table-panel.svg",
       "small": "img/icn-table-panel.svg",
       "large": "img/icn-table-panel.svg"
       "large": "img/icn-table-panel.svg"
-    },
-    "version": "5.0.0"
+    }
   }
   }
 }
 }

+ 1 - 2
public/app/plugins/panel/text/plugin.json

@@ -13,7 +13,6 @@
     "logos": {
     "logos": {
       "small": "img/icn-text-panel.svg",
       "small": "img/icn-text-panel.svg",
       "large": "img/icn-text-panel.svg"
       "large": "img/icn-text-panel.svg"
-    },
-    "version": "5.0.0"
+    }
   }
   }
 }
 }

+ 3 - 1
public/sass/components/_dropdown.scss

@@ -93,7 +93,9 @@
       }
       }
 
 
       .gicon {
       .gicon {
-        opacity: 0.9;
+        opacity: 0.7;
+        width: 14px;
+        height: 14px;
       }
       }
     }
     }
   }
   }