From 49fdbb3843753128eba5877c3e016e6af286455d Mon Sep 17 00:00:00 2001 From: Salman Jalali Date: Fri, 16 Jun 2017 16:10:45 -0700 Subject: [PATCH 1/7] Update kbn.js --- public/app/core/utils/kbn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/core/utils/kbn.js b/public/app/core/utils/kbn.js index d619d9c4977..6f8340d5940 100644 --- a/public/app/core/utils/kbn.js +++ b/public/app/core/utils/kbn.js @@ -841,7 +841,7 @@ function($, _) { { text: 'temperature', submenu: [ - {text: 'Celcius (°C)', value: 'celsius' }, + {text: 'Celsius (°C)', value: 'celsius' }, {text: 'Farenheit (°F)', value: 'farenheit' }, {text: 'Kelvin (K)', value: 'kelvin' }, ] From ad080af38f860e168e40e9357d66a2e1b619ff11 Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Sat, 17 Jun 2017 20:59:19 +0200 Subject: [PATCH 2/7] docs: add tutorial for using API --- docs/sources/tutorials/api_org_token_howto.md | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 docs/sources/tutorials/api_org_token_howto.md diff --git a/docs/sources/tutorials/api_org_token_howto.md b/docs/sources/tutorials/api_org_token_howto.md new file mode 100644 index 00000000000..e985b499dbe --- /dev/null +++ b/docs/sources/tutorials/api_org_token_howto.md @@ -0,0 +1,74 @@ ++++ +title = "API Tutorial: How To Create API Tokens And Dashboards For A Specific Organization" +type = "docs" +keywords = ["grafana", "tutorials", "API", "Token", "Org", "Organization"] +[menu.docs] +parent = "tutorials" +weight = 10 ++++ + +# API Tutorial: How To Create API Tokens And Dashboards For A Specific Organization + +A common scenario is to want to via the Grafana API setup new Grafana organizations or to add dynamically generated dashboards to an existing organization. + +## Authentication + +There are two ways to authenticate against the API: basic authentication and API Tokens. + +Some parts of the API are only available through basic authentication and these parts of the API usually require that the user is a Grafana Admin. But all organization actions are accessed via an API Token. An API Token is tied to an organization and can be used to create dashboards etc but only for that organization. + +## How To Create A New Organization and an API Token + +The task is to create a new organization and then add a Token that can be used by other users. In the examples below which use basic auth, the user is `admin` and the password is `admin`. + +1. [Create the org](http://docs.grafana.org/http_api/org/#create-organisation). Here is an example using curl: + ``` + curl -X POST -H "Content-Type: application/json" -d '{"name":"apiorg"}' http://admin:admin@localhost:3000/api/orgs + ``` + + This should return a response: `{"message":"Organization created","orgId":6}`. Use the orgId for the next steps. + +2. Optional step. If the org was created previously and/or step 3 fails then first [add your Admin user to the org](http://docs.grafana.org/http_api/org/#add-user-in-organisation): + ``` + curl -X POST -H "Content-Type: application/json" -d '{"loginOrEmail":"admin", "role": "Admin"}' http://admin:admin@localhost:3000/api/orgs//users + ``` + +3. [Switch the org context for the Admin user to the new org](http://docs.grafana.org/http_api/user/#switch-user-context): + ``` + curl -X POST http://admin:admin@localhost:3000/api/user/using/ + ``` + +4. [Create the API token](http://docs.grafana.org/http_api/auth/#create-api-key): + ``` + curl -X POST -H "Content-Type: application/json" -d '{"name":"apikeycurl", "role": "Admin"}' http://admin:admin@localhost:3000/api/auth/keys + ``` + + This should return a response: `{"name":"apikeycurl","key":"eyJrIjoiR0ZXZmt1UFc0OEpIOGN5RWdUalBJTllUTk83VlhtVGwiLCJuIjoiYXBpa2V5Y3VybCIsImlkIjo2fQ=="}`. + + Save the key returned here in your password manager as it is not possible to fetch again it in the future. + +## How To Add A Dashboard + +Using the Token that was created in the previous step, you can create a dashboard or carry out other actions without having to switch organizations. + +1. [Add a dashboard](http://docs.grafana.org/http_api/dashboard/#create-update-dashboard) using the key (or bearer token as it is also called): + + ``` + curl -X POST --insecure -H "Authorization: Bearer eyJrIjoiR0ZXZmt1UFc0OEpIOGN5RWdUalBJTllUTk83VlhtVGwiLCJuIjoiYXBpa2V5Y3VybCIsImlkIjo2fQ==" -H "Content-Type: application/json" -d '{ + "dashboard": { + "id": null, + "title": "Production Overview", + "tags": [ "templated" ], + "timezone": "browser", + "rows": [ + { + } + ], + "schemaVersion": 6, + "version": 0 + }, + "overwrite": false + }' http://localhost:3000/api/dashboards/db + ``` + + This import will not work if you exported the dashboard via the Share -> Export menu in the Grafana UI (it strips out data source names etc.). View the JSON and save it to a file instead or fetch the dashboard JSON via the API. From 0eb297822c44edea7d4e981b654b658fccd02d9a Mon Sep 17 00:00:00 2001 From: Daniel Lee Date: Sat, 17 Jun 2017 23:10:12 +0200 Subject: [PATCH 3/7] httpserver: fixes #8641 Changes to the http_server class meant that the TLS settings were not getting applied anymore. This fixes so that the minimum TLS version is 1.2 again. --- pkg/api/http_server.go | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/pkg/api/http_server.go b/pkg/api/http_server.go index 1e143ef876f..0468b5cbe8a 100644 --- a/pkg/api/http_server.go +++ b/pkg/api/http_server.go @@ -61,7 +61,7 @@ func (hs *HttpServer) Start(ctx context.Context) error { return nil } case setting.HTTPS: - err = hs.httpSrv.ListenAndServeTLS(setting.CertFile, setting.KeyFile) + err = hs.listenAndServeTLS(setting.CertFile, setting.KeyFile) if err == http.ErrServerClosed { hs.log.Debug("server was shutdown gracefully") return nil @@ -92,7 +92,7 @@ func (hs *HttpServer) Shutdown(ctx context.Context) error { return err } -func (hs *HttpServer) listenAndServeTLS(listenAddr, certfile, keyfile string) error { +func (hs *HttpServer) listenAndServeTLS(certfile, keyfile string) error { if certfile == "" { return fmt.Errorf("cert_file cannot be empty when using HTTPS") } @@ -127,14 +127,11 @@ func (hs *HttpServer) listenAndServeTLS(listenAddr, certfile, keyfile string) er tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, }, } - srv := &http.Server{ - Addr: listenAddr, - Handler: hs.macaron, - TLSConfig: tlsCfg, - TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0), - } - return srv.ListenAndServeTLS(setting.CertFile, setting.KeyFile) + hs.httpSrv.TLSConfig = tlsCfg + hs.httpSrv.TLSNextProto = make(map[string]func(*http.Server, *tls.Conn, http.Handler), 0) + + return hs.httpSrv.ListenAndServeTLS(setting.CertFile, setting.KeyFile) } func (hs *HttpServer) newMacaron() *macaron.Macaron { From 1f4140057b32c2b86ee855231245e5a73719dad7 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Sun, 18 Jun 2017 20:58:13 +0300 Subject: [PATCH 4/7] heatmap-tooltip: normalize histogram Y axis --- public/app/plugins/panel/heatmap/heatmap_tooltip.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/public/app/plugins/panel/heatmap/heatmap_tooltip.ts b/public/app/plugins/panel/heatmap/heatmap_tooltip.ts index 6d577ab9d37..3af78156536 100644 --- a/public/app/plugins/panel/heatmap/heatmap_tooltip.ts +++ b/public/app/plugins/panel/heatmap/heatmap_tooltip.ts @@ -172,9 +172,11 @@ export class HeatmapTooltip { } barWidth = Math.max(barWidth, 1); + // Normalize histogram Y axis + let histogramDomain = _.reduce(_.map(histogramData, d => d[1]), (sum, val) => sum + val, 0); let histYScale = d3.scaleLinear() - .domain([0, _.max(_.map(histogramData, d => d[1]))]) - .range([0, HISTOGRAM_HEIGHT]); + .domain([0, histogramDomain]) + .range([0, HISTOGRAM_HEIGHT]); let histogram = this.tooltip.select(".heatmap-histogram") .append("svg") From 9a7e460865b44b8884a2bce97c48f33fade5c4a7 Mon Sep 17 00:00:00 2001 From: Alexander Zobnin Date: Sun, 18 Jun 2017 21:41:00 +0300 Subject: [PATCH 5/7] fix heatmap count values bug introduced by #8632 --- .../app/plugins/panel/heatmap/heatmap_data_converter.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/public/app/plugins/panel/heatmap/heatmap_data_converter.ts b/public/app/plugins/panel/heatmap/heatmap_data_converter.ts index 07057c53985..d9e6bbb7d43 100644 --- a/public/app/plugins/panel/heatmap/heatmap_data_converter.ts +++ b/public/app/plugins/panel/heatmap/heatmap_data_converter.ts @@ -192,16 +192,16 @@ function pushToXBuckets(buckets, point, bucketNum, seriesName) { if (value === null || value === undefined || isNaN(value)) { return; } // Add series name to point for future identification - point.push(seriesName); + let point_ext = _.concat(point, seriesName); if (buckets[bucketNum] && buckets[bucketNum].values) { buckets[bucketNum].values.push(value); - buckets[bucketNum].points.push(point); + buckets[bucketNum].points.push(point_ext); } else { buckets[bucketNum] = { x: bucketNum, values: [value], - points: [point] + points: [point_ext] }; } } @@ -209,7 +209,7 @@ function pushToXBuckets(buckets, point, bucketNum, seriesName) { function pushToYBuckets(buckets, bucketNum, value, point, bounds) { var count = 1; // Use the 3rd argument as scale/count - if (point.length > 2) { + if (point.length > 3) { count = parseInt(point[2]); } if (buckets[bucketNum]) { From 41d300f69d09d44994cb21207ef53e0c188e109a Mon Sep 17 00:00:00 2001 From: Denis Doria Date: Mon, 19 Jun 2017 14:58:22 +0200 Subject: [PATCH 6/7] Fix timeInterval for mysql datasource (#8651) * Fix timeInterval for mysql datasource This changes the > to >= and the < to <=, so the intervals are inclusive. This should fix the #8635 * Fix validation --- pkg/tsdb/mysql/macros.go | 2 +- pkg/tsdb/mysql/macros_test.go | 2 +- public/app/plugins/datasource/mysql/partials/query.editor.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/tsdb/mysql/macros.go b/pkg/tsdb/mysql/macros.go index def2fde9fcc..34bbfdc6865 100644 --- a/pkg/tsdb/mysql/macros.go +++ b/pkg/tsdb/mysql/macros.go @@ -73,7 +73,7 @@ func (m *MySqlMacroEngine) EvaluateMacro(name string, args []string) (string, er if len(args) == 0 { return "", fmt.Errorf("missing time column argument for macro %v", name) } - return fmt.Sprintf("%s > FROM_UNIXTIME(%d) AND %s < FROM_UNIXTIME(%d)", args[0], uint64(m.TimeRange.GetFromAsMsEpoch()/1000), args[0], uint64(m.TimeRange.GetToAsMsEpoch()/1000)), nil + return fmt.Sprintf("%s >= FROM_UNIXTIME(%d) AND %s <= FROM_UNIXTIME(%d)", args[0], uint64(m.TimeRange.GetFromAsMsEpoch()/1000), args[0], uint64(m.TimeRange.GetToAsMsEpoch()/1000)), nil default: return "", fmt.Errorf("Unknown macro %v", name) } diff --git a/pkg/tsdb/mysql/macros_test.go b/pkg/tsdb/mysql/macros_test.go index 5b6b885ff0e..9684daac4e8 100644 --- a/pkg/tsdb/mysql/macros_test.go +++ b/pkg/tsdb/mysql/macros_test.go @@ -36,7 +36,7 @@ func TestMacroEngine(t *testing.T) { sql, err := engine.Interpolate("WHERE $__timeFilter(time_column)") So(err, ShouldBeNil) - So(sql, ShouldEqual, "WHERE time_column > FROM_UNIXTIME(18446744066914186738) AND time_column < FROM_UNIXTIME(18446744066914187038)") + So(sql, ShouldEqual, "WHERE time_column >= FROM_UNIXTIME(18446744066914186738) AND time_column <= FROM_UNIXTIME(18446744066914187038)") }) }) diff --git a/public/app/plugins/datasource/mysql/partials/query.editor.html b/public/app/plugins/datasource/mysql/partials/query.editor.html index de54f0ce942..c7b90ad7815 100644 --- a/public/app/plugins/datasource/mysql/partials/query.editor.html +++ b/public/app/plugins/datasource/mysql/partials/query.editor.html @@ -46,7 +46,7 @@ Table: Macros: - $__time(column) -> UNIX_TIMESTAMP(column) as time_sec -- $__timeFilter(column) -> UNIX_TIMESTAMP(time_date_time) > from AND UNIX_TIMESTAMP(time_date_time) < 1492750877 +- $__timeFilter(column) -> UNIX_TIMESTAMP(time_date_time) ≥ from AND UNIX_TIMESTAMP(time_date_time) ≤ 1492750877 From 8440d2d0a2713fe2afaf5b9c685c30ffa22efb64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Mon, 19 Jun 2017 16:02:16 -0400 Subject: [PATCH 7/7] fix: fixed search issues with in active mode and keyboard nav --- public/app/core/components/search/search.ts | 2 +- public/sass/components/_search.scss | 7 ++----- public/sass/components/_view_states.scss | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/public/app/core/components/search/search.ts b/public/app/core/components/search/search.ts index f6810f2bc76..4644e7a5893 100644 --- a/public/app/core/components/search/search.ts +++ b/public/app/core/components/search/search.ts @@ -77,7 +77,7 @@ export class SearchCtrl { this.moveSelection(-1); } if (evt.keyCode === 13) { - if (this.$scope.tagMode) { + if (this.tagsMode) { var tag = this.results[this.selectedIndex]; if (tag) { this.filterByTag(tag.term, null); diff --git a/public/sass/components/_search.scss b/public/sass/components/_search.scss index 3c9f44afb2f..e35bf4e6b6e 100644 --- a/public/sass/components/_search.scss +++ b/public/sass/components/_search.scss @@ -122,14 +122,11 @@ content: "\f015"; } - &:hover { + &:hover, + &.selected { background-color: $tight-form-func-bg; @include left-brand-border-gradient(); } - - &.selected { - background-color: $grafanaListBackground; - } } .search-result-tags { diff --git a/public/sass/components/_view_states.scss b/public/sass/components/_view_states.scss index 900c9d1489b..a1ed89f9888 100644 --- a/public/sass/components/_view_states.scss +++ b/public/sass/components/_view_states.scss @@ -51,7 +51,7 @@ .navbar-page-btn { border-color: transparent; background: transparent; - transform: translate3d(-95px, 0, 0); + transform: translate3d(-50px, 0, 0); transition: all 1.5s ease-in-out 1s; .icon-gf { opacity: 0;