Compare commits

..

2686 Commits

Author SHA1 Message Date
Torkel Ödegaard
2bf305b177 build(): updated build version 2016-03-30 22:30:41 -07:00
Torkel Ödegaard
d3a4b7a799 Merge branch 'master' of github.com:grafana/grafana 2016-03-30 21:27:08 -07:00
Torkel Ödegaard
b85b5e00d4 fix(): fixed panel resize and fullscreen panel height issue 2016-03-30 21:26:54 -07:00
Daniel Lee
45b90972dc feat(plugins): adds a readme for every native plugin 2016-03-30 23:33:30 +02:00
Torkel Ödegaard
7180d6aa07 Merge pull request #4504 from sebito91/master
Issue with templating latest InfluxDB v0.11.0, force query to lowercase
2016-03-30 13:20:48 -07:00
Torkel Ödegaard
9d6445d4ce build(): updated publish script 2016-03-30 12:41:16 -07:00
Torkel Ödegaard
953f9da3b5 build(): build fix 2016-03-30 12:02:44 -07:00
Torkel Ödegaard
97b304abc9 build(): added unix timestamp to iteration builds 2016-03-30 10:05:30 -07:00
Torkel Ödegaard
49a1d4417d fix(dashlist): fixed dashlist bug 2016-03-30 09:49:07 -07:00
Torkel Ödegaard
8451de8752 tech(): changed deps in package.json 2016-03-30 08:10:22 -07:00
Torkel Ödegaard
32bed83a17 docs(): updated 2016-03-30 08:01:54 -07:00
Torkel Ödegaard
92edce8fa1 Merge branch 'master' of github.com:grafana/grafana 2016-03-30 08:01:43 -07:00
Torkel Ödegaard
545d3208c8 docs(): updated plugin docs 2016-03-30 16:56:22 +02:00
Torkel Ödegaard
b745726462 Merge branch 'master' of github.com:grafana/grafana 2016-03-30 00:16:15 +02:00
Torkel Ödegaard
3dbfd49414 ux(): templating forms polish 2016-03-29 22:24:08 +02:00
Torkel Ödegaard
2ee9376df2 ux(): form tweaks 2016-03-29 20:49:42 +02:00
Sebastian Borza
aa62c2eff6 Force the query check to lowercase for tag values, fix issue with templating influxdb v0.11.0 2016-03-29 12:36:21 -05:00
Anthony Woods
04d142cd62 Merge pull request #4502 from grafana/issue4501
add missing ngInject comment.
2016-03-29 23:09:49 +08:00
woodsaj
2f3627e74b add missing ngInject comment. fixes #4501 2016-03-29 22:53:02 +08:00
Torkel Ödegaard
d545902acc ux(): updated and polished legend option forms 2016-03-29 15:53:41 +02:00
Torkel Ödegaard
4871a8f43e refactor(graph): changed how graph stores panel yaxis options 2016-03-29 14:54:33 +02:00
Torkel Ödegaard
32c8f495ab ux(): redesign of axis & grid forms 2016-03-29 12:32:40 +02:00
Torkel Ödegaard
0c21d2c047 fix(ux): css fix for tabbed view caused edit views in dashboard to create horizontal scrollbar 2016-03-29 11:07:55 +02:00
Torkel Ödegaard
0964a06ab5 Merge branch 'master' of github.com:grafana/grafana 2016-03-29 11:01:32 +02:00
Torkel Ödegaard
3e50ee6193 ux(): dashboard settings form polish, added on hover tooltip for checkbox directive 2016-03-29 11:01:00 +02:00
Anthony Woods
da98f47502 Merge pull request #4496 from grafana/issue4494
handle errors when requesting plugin list.
2016-03-29 16:16:17 +08:00
Anthony Woods
036f407d6a gofmt 2016-03-29 16:04:24 +08:00
Anthony Woods
2c60dbd4fb handle errors when requesting plugin list. fixes #4494 2016-03-29 15:35:08 +08:00
Torkel Ödegaard
b12ca1da88 build(): fixed failing build 2016-03-29 08:25:03 +02:00
Torkel Ödegaard
d4ada51fad build(): fixed issue with peer dependencies in package.json, fixes #4487 2016-03-29 06:16:49 +02:00
Torkel Ödegaard
f0ae6a0bb1 fix(build): fixed js issue with optimized build 2016-03-28 21:45:31 +02:00
Torkel Ödegaard
1e44ee9e9b feat(grafana-cli): minor changes 2016-03-28 21:42:26 +02:00
Torkel Ödegaard
b3bda2aa64 Merge branch 'master' of github.com:grafana/grafana 2016-03-28 20:44:54 +02:00
Torkel Ödegaard
82ad5a632d tech(): fixed broken tests due to angularjs upgrade 2016-03-28 20:44:32 +02:00
Torkel Ödegaard
21213a2587 Merge pull request #4488 from grafana/repoUrl
update default repo url in grafana-cli
2016-03-28 18:14:45 +02:00
Anthony Woods
776af45c09 update default repo url in grafana-cli 2016-03-28 23:36:27 +08:00
Torkel Ödegaard
70b66382eb tech(): updated angularjs 2016-03-28 17:08:31 +02:00
Torkel Ödegaard
14326b626e ux(): checkbox now works in dark and white theme 2016-03-28 13:10:42 +02:00
Torkel Ödegaard
1dabd68327 Merge branch 'master' into checkboxv3 2016-03-28 11:22:23 +02:00
Torkel Ödegaard
f27ce7e1e4 Merge pull request #4461 from dfwarden/ldap_nested_groups
LDAP Nested Groups
2016-03-28 11:19:28 +02:00
Torkel Ödegaard
91c5515d5b Merge branch 'master' of github.com:grafana/grafana 2016-03-28 11:16:03 +02:00
Torkel Ödegaard
6ab1937ff5 changelog(): comment about possible breaking change with templated dashboards 2016-03-28 11:15:48 +02:00
Torkel Ödegaard
576a490435 Merge pull request #4472 from volter/issue-3728
Solve issue #3728
2016-03-28 11:06:33 +02:00
Torkel Ödegaard
0afa545b06 Merge branch 'master' of github.com:grafana/grafana 2016-03-28 10:34:57 +02:00
Torkel Ödegaard
937cefe824 Merge pull request #4477 from grafana/dashlist-style
add card style css for dashlist panels and remove dark border on dash…
2016-03-28 10:34:49 +02:00
Torkel Ödegaard
896605f838 ux(): minor fix for row menu in pinned sidemenu state 2016-03-28 10:23:36 +02:00
Torkel Ödegaard
250e98837f Merge pull request #4484 from notpeter/CloudWatch-ListExamples
Docs: Examples for listing CloudWatch resources in templates.
2016-03-28 09:39:09 +02:00
Peter Tripp
2cb3505dce Examples for listing CloudWatch resources in templates. 2016-03-27 17:20:33 -07:00
Torkel Ödegaard
73f11fae2e Merge pull request #4483 from utkarshcmu/docs
Fixed some minor typos in docs
2016-03-27 13:42:52 +02:00
utkarshcmu
4ced5bbbc0 Fixed some minor typos in docs 2016-03-26 20:15:36 -07:00
Matt Toback
4421fda877 Merge pull request #4479 from grafana/worldping
Tightened up the bottom padding on playlist headers - distance to bot…
2016-03-25 17:42:39 -04:00
Matt Toback
5407052e0c Tightened up the bottom padding on playlist headers - distance to bottom border 2016-03-25 17:41:31 -04:00
Trent White
90c7943242 backing out card style on dashlist 2016-03-25 12:12:46 -04:00
Trent White
70d536c6c4 add card style css for dashlist panels and remove dark border on dashlist items to match the dropdown dashboard picker list 2016-03-25 11:54:50 -04:00
Torkel Ödegaard
319b934967 fix(): fixed failing test 2016-03-25 15:52:28 +01:00
Torkel Ödegaard
61017fc204 feat(plugins): import all dashboards feature 2016-03-25 15:35:58 +01:00
Torkel Ödegaard
1ff90b713f Merge pull request #4473 from grafana/new-panel-icons
added new icons for default panels
2016-03-25 13:46:23 +01:00
Torkel Ödegaard
7045d06221 Merge pull request #4474 from grafana/worldping-adjustments
Added a new util class for highlight words, proper variables added fo…
2016-03-25 13:44:36 +01:00
Torkel Ödegaard
05cc370c55 feat(plugins): added disable button to app config tab 2016-03-25 13:43:13 +01:00
Torkel Ödegaard
963e202745 fix(): data push fix 2016-03-25 09:40:05 +01:00
Matt
82b1a11820 Added a new util class for highlight words, proper variables added for light and dark 2016-03-24 22:01:33 -04:00
Trent White
694c6e8fd2 added new icons for default panels 2016-03-24 16:14:51 -04:00
Volker Fröhlich
45186255cf Solve issue 3728
Conditionally add a format element to ES annotation queries
2016-03-24 17:58:03 +01:00
bergquist
a531a1709e docs(plugin): add apps page 2016-03-24 11:55:36 +01:00
bergquist
f85a3ad44d docs(plugins): minor improvesments to plugin dev guide 2016-03-24 11:29:11 +01:00
Torkel Ödegaard
ee7afcbe9e ux() some final tweaks 2016-03-23 22:40:48 +01:00
Torkel Ödegaard
b3b63f836a ux(): checkbox v3 with hover style 2016-03-23 22:28:38 +01:00
Torkel Ödegaard
c2ef2ef287 ux(): updated checkbox v3 experiment 2016-03-23 21:18:37 +01:00
Torkel Ödegaard
e65fd45c65 ux(): checkbox experiment 2016-03-23 21:10:06 +01:00
Torkel Ödegaard
32a1d1445c refactor(): trying to move app events away from rootScope 2016-03-23 17:39:10 +01:00
Torkel Ödegaard
35c853e906 feat(plugins): fix for plugin logo to navbar on plugin page, #4452 2016-03-23 16:43:32 +01:00
Torkel Ödegaard
481139772b Merge branch 'master' of github.com:grafana/grafana 2016-03-23 16:38:47 +01:00
Torkel Ödegaard
5dfac9a765 feat(plugins): added plugin logo to navbar on plugin page, #4452 2016-03-23 16:37:58 +01:00
Carl Bergquist
ee92fee212 Merge pull request #4460 from grafana/influxdb
[InfluxDB] Adds support for 0.11.0 tags
2016-03-23 16:12:15 +01:00
Torkel Ödegaard
b06d809364 ux(): changed name again 2016-03-23 15:42:46 +01:00
Torkel Ödegaard
f8fb97d912 ux(): restored natural language input class 2016-03-23 15:41:01 +01:00
bergquist
5f2f4a0897 test(influxdb): remove redundant test 2016-03-23 15:23:14 +01:00
Torkel Ödegaard
b7d198793f refactor(): minor refactoring of #4455 2016-03-23 15:09:48 +01:00
bergquist
991b6eafca tech(influxdb): convert datasource to TS class 2016-03-23 14:45:24 +01:00
bergquist
5b75eea8cf fix(influxdb): remove unused parameter 2016-03-23 14:45:24 +01:00
bergquist
ba48f40d21 feat(influxdb): bases parsing upon query 2016-03-23 14:45:23 +01:00
bergquist
6fafc8dba1 add(influxdb): add support for 0.11.0 tags 2016-03-23 14:45:23 +01:00
bergquist
53312852e9 tests(influxdb): adds tests for influxdb response 2016-03-23 14:45:23 +01:00
Torkel Ödegaard
2d59112c1b Merge pull request #4455 from grafana/g3-app-improvements
Form adjustments for app work
2016-03-23 14:32:42 +01:00
Torkel Ödegaard
637db29fad tech(): updated phantomjs npm package to use phantomjs-prebuilt 2016-03-23 13:26:38 +01:00
David Warden
87aca5bf1b new config option for source of %s in group_search_filter, useful for nested LDAP groups 2016-03-23 08:21:25 -04:00
Torkel Ödegaard
585503f9fb fix(): renamed plugin.json for wip for new work in progress data source 2016-03-23 13:11:55 +01:00
Torkel Ödegaard
19e07a610a tech(): added gorilla dependency 2016-03-23 13:08:09 +01:00
Torkel Ödegaard
4058c85e2a fix(): singlestat init 2016-03-23 13:02:37 +01:00
Torkel Ödegaard
b3c073ab6c feat(panels): more panel refactoring, using events instead of overriding base class methods 2016-03-23 12:50:56 +01:00
Torkel Ödegaard
6a42b95d39 feat(panels): panel refactorings 2016-03-23 11:31:31 +01:00
Matt Toback
30b2a7169f Form adjustments for app work 2016-03-22 18:41:04 -04:00
Torkel Ödegaard
cb49e11eca feat(live): panel sdk/api refactorings 2016-03-22 21:27:53 +01:00
David Warden
5b5cf9f006 documentation for ldap nested groups 2016-03-22 13:54:36 -04:00
David Warden
2bf94d8db4 version bump go-ldap to v2.2.1 2016-03-22 13:54:36 -04:00
Torkel Ödegaard
7366cef1fe Merge branch 'master' into websocket 2016-03-22 18:33:39 +01:00
Torkel Ödegaard
1854381456 tech(): updated es6-shim, removed es5-shim, no longer needed as we upraded phantomjs to 2.x, also removed es6-promise, dont think we need it 2016-03-22 18:32:08 +01:00
Torkel Ödegaard
8dee54bf5d feat(live): progress on panel <-> data source communication patterns 2016-03-22 18:21:21 +01:00
bergquist
bbc4c361bb fix(npm): updates phantomjs requirement 2016-03-22 17:23:15 +01:00
bergquist
83b7397398 Revert "feat(influxdb): add support for 0.11.0 tags"
This reverts commit b73d196c6b.
2016-03-22 16:07:00 +01:00
Matt Toback
04a887dafa Merge pull request #4447 from grafana/grafana-worldping-tweaks
Updated card views to accommodate a 2 column layout at lg breakpoints
2016-03-22 10:33:00 -04:00
Matt Toback
4c5291f941 Updated card views to accommodate a 2 column layout at lg breakpoints 2016-03-22 10:21:47 -04:00
bergquist
b73d196c6b feat(influxdb): add support for 0.11.0 tags
this change is backwards compatible.

closes #4392
2016-03-22 14:35:46 +01:00
Torkel Ödegaard
d0564933a2 Merge branch 'master' into websocket 2016-03-22 10:42:41 +01:00
Torkel Ödegaard
03f91e8d85 fix(panel resize): fixed panel resize drag handling 2016-03-22 10:42:29 +01:00
Torkel Ödegaard
c711fb67c8 Merge branch 'master' into websocket 2016-03-22 10:31:57 +01:00
Torkel Ödegaard
7e6314dcac Merge branch 'master' of github.com:grafana/grafana 2016-03-22 10:16:01 +01:00
Torkel Ödegaard
10df9dc8c3 feat(plugins): finished app navigation enhancements, closes #4434 2016-03-22 10:15:47 +01:00
bergquist
4110c7ffb0 fix(switchorg): fixes broken redirect when switchin org 2016-03-22 09:25:46 +01:00
Carl Bergquist
7f79024e6a Merge pull request #4440 from utkarshcmu/redirect
Redirect to home when switching orgs
2016-03-22 08:28:39 +01:00
utkarshcmu
f6cbbe1e64 Redirect to home when switching orgs 2016-03-21 22:56:46 -07:00
Torkel Ödegaard
64312ceded ux(): updated http settings view with new checkboxes 2016-03-21 21:36:30 +01:00
Torkel Ödegaard
98206ab49f ux(): created new gf-form-switch directive clean/refactoring 2016-03-21 21:24:06 +01:00
Torkel Ödegaard
56622ee2c6 Merge branch 'master' of github.com:grafana/grafana 2016-03-21 19:07:19 +01:00
Torkel Ödegaard
65c0937741 ux(): app navigation improvements, changes to plugin.json for apps, merged pages with includes section, #4434 2016-03-21 19:07:08 +01:00
Torkel Ödegaard
8498bfd2c2 Merge pull request #4436 from grafana/org-details-improvements
Finishing touches
2016-03-21 17:17:59 +01:00
Torkel Ödegaard
7403b94b9d Merge branch 'checkboxv2' of github.com:grafana/grafana into checkboxv2 2016-03-21 14:19:32 +01:00
Torkel Ödegaard
d40cc32393 Merge branch 'master' of github.com:grafana/grafana into checkboxv2 2016-03-21 14:18:05 +01:00
Torkel Ödegaard
fc983f9751 ux(): checkbox v2 tweaks 2016-03-21 14:08:18 +01:00
Torkel Ödegaard
ae255a7adf ux(): new checkbox tweaks 2016-03-21 13:37:56 +01:00
bergquist
90c6b04361 fix(backendsrv): remove invalid check 2016-03-21 12:43:30 +01:00
bergquist
86a274a7ee feat(backendsrv): improves error response handling
datasourceRequests that could not reach the destination threw
invalid errors due to missing property. This fixes gives the user
a better error message.

closes #4428
2016-03-21 12:30:13 +01:00
Torkel Ödegaard
530b6a5088 ux(): another checkbox design 2016-03-21 11:27:53 +01:00
Torkel Ödegaard
5e52aaac6f ux(): checkbox style test 2016-03-21 11:07:37 +01:00
Torkel Ödegaard
3ea441d1a0 feat(live): tricky 2016-03-21 10:42:10 +01:00
bergquist
14df3c6249 feat(cli): use built in envvar support 2016-03-21 10:11:08 +01:00
bergquist
7f8643efde feat(cli): make all plugin commands subcommands 2016-03-21 10:01:07 +01:00
Torkel Ödegaard
273311eed2 ux(graph styles tab): updated forms in graph styles tab 2016-03-20 17:33:30 +01:00
Torkel Ödegaard
06468d6f43 Merge pull request #4368 from simnv/variable-escape
Slash escape regex
2016-03-20 11:22:33 +01:00
Torkel Ödegaard
4377e95c99 fix(graph legend): minor correction to last commit 2016-03-20 11:21:06 +01:00
Torkel Ödegaard
f4feb38089 fix(graph): fixed issue with graph and legend to the right in snapshots, closes #4400 2016-03-20 11:17:53 +01:00
Torkel Ödegaard
82232e2530 changelog(): added nested ldap group to changelog, #4401 2016-03-20 10:57:53 +01:00
Torkel Ödegaard
9c2809a1a4 ux(): button style tweaks, align with grafana.net styles more 2016-03-20 10:31:50 +01:00
simnv
dd5b4a25d1 Slash escaping test 2016-03-20 00:13:48 +06:00
Torkel Ödegaard
73e5c70d80 fix(ux): fixed ux issue in new cards data source list, now handles overflowing urls and titles, fixes #4403 2016-03-19 11:37:40 +01:00
Torkel Ödegaard
6d36641080 fix(text panel): fixed escaping issue with markdown in text panel, fixes #4409 2016-03-19 11:25:19 +01:00
Torkel Ödegaard
662dbaf8b2 Merge pull request #4420 from grafana/grafana-worldping-tweaks
Beginngings of style adjustments to support worldPing app
2016-03-19 11:10:14 +01:00
Torkel Ödegaard
e63ff1c762 feat(dataproxy): set flush interval, need a setting for this 2016-03-19 11:09:26 +01:00
Matt Toback
084ad69c53 Beginngings of style adjustments to support worldPing app 2016-03-18 19:32:50 -04:00
Torkel Ödegaard
1ccde201be feat(live datasouces): moved from Observable to Subject 2016-03-18 13:52:26 +01:00
bergquist
48a721e259 feat(tslint): remove two space requirements for comments 2016-03-18 13:20:49 +01:00
bergquist
4c7f638f3c fix(datasources): fixes header condition
closes #4402
2016-03-18 09:48:26 +01:00
bergquist
35e53ee511 docs(plugin): add info about enabling apps 2016-03-18 09:48:26 +01:00
bergquist
b1881e5f54 docs(plugins): update links to new examples 2016-03-18 09:48:26 +01:00
bergquist
3c39a935f8 docs(plugins): docs for app plugins 2016-03-18 09:48:26 +01:00
bergquist
2b0499c968 docs(plugin): update link to datasource docs 2016-03-18 09:48:26 +01:00
Carl Bergquist
504d800a0d Merge pull request #4412 from utkarshcmu/viewer
Viewer not able to delete snapshot anymore
2016-03-18 09:16:17 +01:00
utkarshcmu
9d4fa87914 Viewer not able to delete snapshot 2016-03-18 01:13:34 -07:00
Matt Toback
6016033b8b Finishing touches 2016-03-17 15:14:26 -04:00
Matt Toback
5af54c57ba Update admin.md 2016-03-17 14:31:55 -04:00
Torkel Ödegaard
9ddf22ea93 Merge branch 'master' into websocket 2016-03-17 10:16:05 +01:00
Torkel Ödegaard
b2fe7e518f ux(): added specific fallback logos for plugin depending on type, polished layout selector style 2016-03-17 10:15:16 +01:00
Matt Toback
6bf05a8154 Made the input shadow a bit more subtle while maintaining the box shadow 2016-03-16 16:08:18 -04:00
bergquist
a08809f8fe fix(phantomjs): upgrades to 2.1.1 for ssl support
closes #4371
2016-03-16 16:30:08 +01:00
bergquist
57ecb276c8 fix(singlestat): use exact value for coloring
closes #4259
2016-03-16 16:04:35 +01:00
Torkel Ödegaard
79a803ea8f feat(ds observable): minor progress on handling data source observable 2016-03-16 15:59:21 +01:00
Torkel Ödegaard
0f6579801d Merge branch 'master' into websocket
Conflicts:
	public/app/core/core.ts
2016-03-16 15:19:32 +01:00
Torkel Ödegaard
fcaf2bfdba fix(datasource): when addding data source withCredentials did not get set, fixes #4389 2016-03-16 15:16:28 +01:00
Torkel Ödegaard
4144f71e23 Merge branch 'datasource-lists-cards' 2016-03-16 15:05:46 +01:00
Torkel Ödegaard
852ecd71f7 ux(): update data source list to card view, #4364 2016-03-16 15:05:07 +01:00
bergquist
aadc6e0bbd fix(fonts): move icon fonts back to main css 2016-03-16 14:45:39 +01:00
Torkel Ödegaard
a738945a88 feat(data source observerable): started work on handling data source observerable 2016-03-16 14:19:30 +01:00
bergquist
9d3cbfe896 Merge branch 'cli_colors' 2016-03-16 14:18:19 +01:00
bergquist
1a11f1e8c6 Merge branch 'master' into cli_colors 2016-03-16 14:17:35 +01:00
bergquist
a12f5376b5 feat(cli): adds some colors to ls command 2016-03-16 14:09:30 +01:00
Carl Bergquist
fd531e84fc Merge pull request #4384 from vitorboschi/fixTypo
fix typo
2016-03-16 13:40:39 +01:00
Torkel Ödegaard
d26d7162a5 fix(opentsdb): fixed templating issue for single value variables, fixes #4312 2016-03-16 13:11:07 +01:00
Vitor Boschi
a9cdf580a7 fix typo 2016-03-16 09:06:44 -03:00
Carl Bergquist
990acb3fd3 Merge pull request #4383 from bbinet/patch-1
[docs] typos in plugins/installation.md
2016-03-16 11:59:51 +01:00
Bruno Binet
3486bf92eb [docs] typos 2016-03-16 11:56:19 +01:00
bergquist
ed1864e076 feat(dashlist): stores recently visited dashboards per orgid 2016-03-16 11:52:25 +01:00
bergquist
0998ce81f3 Merge branch 'local_fonts' 2016-03-16 11:08:53 +01:00
bergquist
99e068643b feat(fonts): download fonts from grafana instead of CDN
Makes its possible to run grafana without internet access.
The performance hit by not using a cdn is very small since
most grafana instances are setup on locally.

closes #4223
2016-03-16 10:51:59 +01:00
Torkel Ödegaard
0d7eb18d7b Merge branch 'master' of github.com:grafana/grafana 2016-03-16 10:32:24 +01:00
Torkel Ödegaard
81c11ebb53 fix(dashlist): fixed issue with viewing last viewed dashboards, when you had more than dashboards in last viewed than panel limit they did not show up in list 2016-03-16 10:32:11 +01:00
Carl Bergquist
2e73c58338 Merge pull request #4379 from mtanda/cloudwatch_tag_search_fix
(cloudwatch) remove duplicative attribute
2016-03-16 08:33:59 +01:00
Mitsuhiro Tanda
381a48f21d (cloudwatch) remove duplicative attribute 2016-03-16 15:41:52 +09:00
Torkel Ödegaard
e4c0c39fbf ux(): began work on updating data source list to cards view 2016-03-15 20:29:35 +01:00
Torkel Ödegaard
1abdd170d3 ux(): fixes to cards and sorting plugin list, #4364 2016-03-15 15:52:29 +01:00
Torkel Ödegaard
dddd155afa Merge branch 'master' of github.com:grafana/grafana 2016-03-15 15:28:55 +01:00
Torkel Ödegaard
c411714546 ux(): added card layout selector and list view mode, #4364 2016-03-15 15:28:37 +01:00
Trent White
cba7c1726f add graphite logo to datasource card 2016-03-15 10:08:23 -04:00
simnv
be8ec24106 Slash escape regex
Slash symbol "/" wasn't escaped when we chose variable from template dropdown, so we couldn't choose interface names like Gi9/10 when querying from influxdb.
2016-03-15 16:05:32 +05:00
Carl Bergquist
0b3ccaff27 Merge pull request #4361 from bergquist/remove_staticRoot
plugin.json: remove staticRoot field
2016-03-15 10:07:08 +01:00
Torkel Ödegaard
b273cd1339 Merge branch 'master' into websocket 2016-03-15 09:52:36 +01:00
Torkel Ödegaard
82eb32a71e ux(): initial pass at new card / list design, #4364 2016-03-15 09:15:24 +01:00
bergquist
e905c2c6b5 feat(plugin.json): remove staticRoot field 2016-03-15 09:00:55 +01:00
Torkel Ödegaard
13376d89cc Merge pull request #4363 from cookiefission/fix/trim-edges-typo
Fix minor typo in tooltip
2016-03-14 22:29:14 +01:00
Torkel Ödegaard
2e1f26096f feat(grafana_live): more work pushing data to websocket, #4355 2016-03-14 22:26:43 +01:00
Sean Kenny
8f97e8d5ed Fix minor typo in tooltip 2016-03-14 19:40:23 +00:00
Torkel Ödegaard
92f20b9b7d feat(websocket): reconnection and resubscription handling, #4355 2016-03-14 19:21:32 +01:00
Torkel Ödegaard
3d5251d9a5 feat(websocket): more work websocket ds, # 4355 2016-03-14 17:32:48 +01:00
Torkel Ödegaard
195be2742c feat(live): wip work 2016-03-14 16:18:07 +01:00
Torkel Ödegaard
2adc4d12be feat(live): work on websocket data source, #3455 2016-03-14 13:20:55 +01:00
Torkel Ödegaard
8d7b7009c3 Merge branch 'master' into websocket 2016-03-14 12:01:43 +01:00
Torkel Ödegaard
ca5a34ad1e fix(datasource): filter out built in data sources from data source type dropdown 2016-03-14 12:00:56 +01:00
Torkel Ödegaard
fbd94fc6ce feat(websockets): inital work on websockets, #4355 2016-03-14 11:59:51 +01:00
bergquist
953a07252a Revert "fix(datasource): fixes testdatasource bug"
This reverts commit f77bd59e1d.
2016-03-14 11:43:35 +01:00
bergquist
f77bd59e1d fix(datasource): fixes testdatasource bug 2016-03-14 11:33:38 +01:00
Torkel Ödegaard
5b6754ce6c Merge branch 'master' into websocket 2016-03-14 10:33:11 +01:00
Torkel Ödegaard
4aba3bc62b fix(opentsdb): fixed templating issue for OpenTSDB, fixes #4312, fixes #4311 2016-03-14 10:18:43 +01:00
Torkel Ödegaard
fc6ad2059a docs(): updated doc version 2016-03-14 10:03:18 +01:00
Torkel Ödegaard
69c8bb1eb3 feat(plugins): added filter (type) tabs po plugin list view 2016-03-14 09:10:32 +01:00
Torkel Ödegaard
c504abb84d feat(plugins): added dashboards tab to plugin edit page, #4275 2016-03-13 20:18:45 +01:00
Torkel Ödegaard
2527289e3e Merge branch 'master' of github.com:grafana/grafana 2016-03-13 19:21:56 +01:00
Torkel Ödegaard
581ffb862c feat(plugins): polish to plugin page, better handling for reading readme file contents 2016-03-13 19:21:44 +01:00
bergquist
8e70e9c1c3 feat(cli): improve error message for missing permission 2016-03-13 11:29:43 +01:00
Torkel Ödegaard
4a3c19c666 plugins(): dashboards, changed wording installed to imported when showing imported version in dashboard list 2016-03-12 10:49:30 +01:00
Torkel Ödegaard
d575a5ce12 feat(plugins): added prometheus dashboard to prometheus data source, #4298 2016-03-12 10:40:55 +01:00
Torkel Ödegaard
53dc145ce7 Merge branch 'dashboard-install' 2016-03-12 10:13:59 +01:00
Torkel Ödegaard
0398face05 feat(plugins): dashboard import for data sources is working! #4298 2016-03-12 10:13:49 +01:00
Torkel Ödegaard
ef7d8ab90b Merge branch 'master' of github.com:grafana/grafana 2016-03-12 00:16:21 +01:00
Torkel Ödegaard
28f4f3a8c8 fix(datasource edit): Editing datasources broken earlier today, fixes #4343 2016-03-12 00:16:08 +01:00
Torkel Ödegaard
3fb0b71822 refactor(): refactoring json usage 2016-03-12 00:13:06 +01:00
Torkel Ödegaard
40b2f00dc5 fix(): fixed from db -> json 2016-03-11 23:39:42 +01:00
Torkel Ödegaard
749da42ffc updated lib 2016-03-11 23:29:45 +01:00
Torkel Ödegaard
1f9f439acb lib(): added simplejson lib 2016-03-11 23:28:33 +01:00
Torkel Ödegaard
c5a817194a more work on dashboard importing and templating 2016-03-11 17:31:57 +01:00
bergquist
c1e4d0590c fix(plugins): fixes broken plugin link 2016-03-11 17:13:35 +01:00
bergquist
85466c7ee1 fix(plugins): fixes broken link 2016-03-11 17:04:26 +01:00
bergquist
740478344b Merge branch 'master' into cli_colors 2016-03-11 14:43:12 +01:00
bergquist
5094c1db2a feat(cli): improves error message for 401 requests 2016-03-11 14:34:48 +01:00
bergquist
f5bb2b11e5 feat(cli): improve error handling for missing plugin dir 2016-03-11 14:11:25 +01:00
bergquist
8da702c2e7 feat(cli): add grafana net url 2016-03-11 13:59:09 +01:00
Torkel Ödegaard
d2b0bad1cf fix(): fixed changed partials paths 2016-03-11 13:02:21 +01:00
Torkel Ödegaard
ece8a925a6 Merge branch 'master' of github.com:grafana/grafana
Conflicts:
	examples/nginx-app/package.json
	examples/nginx-app/plugin.json
2016-03-11 12:39:10 +01:00
Torkel Ödegaard
fc54c01f01 feat(plugins): more work on plugin dashboard install, #4298 2016-03-11 12:31:56 +01:00
Torkel Ödegaard
3fd420c901 Merge pull request #4335 from mtanda/cloudwatch_tag_query
(cloudwatch) support tag query
2016-03-11 11:21:12 +01:00
Mitsuhiro Tanda
01788e86e5 (cloudwatch) add document for new query 2016-03-11 18:18:14 +09:00
bergquist
4f52bc138f docs(examples): move app example into new repo 2016-03-11 10:06:44 +01:00
Torkel Ödegaard
2de439bd1e feat(plugins): progress on dashboard installs , #4298 2016-03-11 09:57:20 +01:00
Mitsuhiro Tanda
b989e2ce37 minor fix 2016-03-11 17:04:42 +09:00
Mitsuhiro Tanda
25f08ddd39 (cloudwatch) change parameter form of ec2_instance_attribute() 2016-03-11 16:59:06 +09:00
bergquist
a16c799da9 fix(examples): update link in readme 2016-03-11 08:52:14 +01:00
Mitsuhiro Tanda
0052e9d136 (cloudwatch) add ec2_instance_attribute() query 2016-03-11 16:48:29 +09:00
bergquist
b72cf90ed4 example(panel): rename to match new convetion 2016-03-11 08:39:05 +01:00
bergquist
69013ef8ad Merge branch 'master' of github.com:grafana/grafana 2016-03-11 08:35:24 +01:00
Carl Bergquist
16132e86a3 Merge pull request #4331 from mtanda/cloudwatch_add_metrics_dimensions
(cloudwatch) add metrics/dimensions of AWS/Events and AWS/Logs
2016-03-11 08:28:00 +01:00
Carl Bergquist
047191abf0 Merge pull request #4330 from tdyas/fix_nginx_app_example
remove extra comma in nginx-app's package.json
2016-03-11 08:02:48 +01:00
Torkel Ödegaard
11372ac9ff Merge pull request #4332 from simnv/influxdb-tags-multiple
InfluxDB: Fix groupby selection
2016-03-11 07:14:48 +01:00
simnv
336c1b7b6e Fix groupby selection
Default groupby selection for influxdb is escaped not like a regex, but as a glob. It works fine with one value in variable, but when you select multiple values, query is incorrect:
> SHOW TAG KEYS FROM "os.disk.fs.space_total" WHERE "host" =~ /{host-1,host-2}$/
2016-03-11 08:30:56 +05:00
Mitsuhiro Tanda
2c5abed2f1 (cloudwatch) add metrics/dimensions of AWS/Events and AWS/Logs 2016-03-11 12:11:01 +09:00
Tom Dyas
8c6890c95f remove extra comma in nginx-app's package.json
otherwise grunt fails due to a syntax error in package.json
2016-03-10 17:48:17 -05:00
Torkel Ödegaard
60adcedebe feat(plugins): worked on plugin dashboard import handling 2016-03-10 19:57:48 +01:00
bergquist
95de5f6fe1 feat(cli): adds some amazing colors 2016-03-10 17:33:44 +01:00
bergquist
788aafff3c feat(cli): disable dependecy downloads until needed 2016-03-10 17:16:01 +01:00
bergquist
c09d506245 feat(navigation): hide new and import for viewers
closes #4326
2016-03-10 16:38:16 +01:00
bergquist
18c5e90076 Merge branch 'cli_compose_download_url' 2016-03-10 16:29:37 +01:00
bergquist
fee0745e98 feat(cli): support for asking grafana net about plugins 2016-03-10 16:25:34 +01:00
bergquist
43073da7eb feat(renderer): add timeout for the renderer api
closes #4325
2016-03-10 16:02:10 +01:00
bergquist
0b6fee138a docs(configuration): add redis as session storage 2016-03-10 14:49:37 +01:00
Torkel Ödegaard
78b9c3004a feat(plugins): minor progress on dashboard imports 2016-03-10 14:28:31 +01:00
Carl Bergquist
c99aa74140 Merge pull request #4322 from utkarshcmu/add-api
#4258 Implemented GetDataSourceIdByName API
2016-03-10 11:46:32 +01:00
utkarshcmu
4fbff99186 Implemented GetDataSourceIdByName API 2016-03-10 01:31:10 -08:00
utkarshcmu
8afd56575c Moved api in correct group 2016-03-10 00:48:38 -08:00
Torkel Ödegaard
1951f3856f feat(plugins): refactored datasourceEditCtrl to typescript, #4298 2016-03-10 09:47:29 +01:00
Torkel Ödegaard
8357cdf591 Merge pull request #4313 from PaulMest/patch-1
Update ldap.md
2016-03-10 07:29:41 +01:00
Torkel Ödegaard
499bad5f53 Merge pull request #4320 from mtanda/templating_fix_on_time_range_change
fix to use variable.refresh flag
2016-03-10 07:26:24 +01:00
Mitsuhiro Tanda
df2a23d1a7 fix to use variable.refresh flag 2016-03-10 13:19:07 +09:00
Paul Mestemaker
d6ecf74db4 Update ldap.md
Added clearer language on which versions offer LDAP support.
2016-03-09 11:25:42 -08:00
bergquist
6670e6cd29 feat(cli): allow redirect for plugin-repo.json 2016-03-09 16:10:46 +01:00
Torkel Ödegaard
d8b11adfd5 Merge branch 'master' into dashboard-thing 2016-03-09 13:11:48 +01:00
Torkel Ödegaard
4a5b753fd8 feat(templating): refactoring of the refresh values of #4281 2016-03-09 13:10:02 +01:00
bergquist
d9231eb805 github(pr_template): minor guide for PRs 2016-03-09 12:42:36 +01:00
Torkel Ödegaard
bb1e7f62a0 fix(build): updated moment.js to fix systemjs build issue, fixes #4306 2016-03-09 12:39:05 +01:00
bergquist
e5ffb2bfd2 github(issue_template): minor improvement 2016-03-09 12:08:09 +01:00
bergquist
6fff0b3e2a Merge branch 'mtanda-refresh_temp_value_by_time_range_changes' 2016-03-09 12:02:02 +01:00
bergquist
f0d1853a66 style(templating): tigth-form -> gf-form 2016-03-09 11:56:52 +01:00
bergquist
7224728ab8 Merge branch 'refresh_temp_value_by_time_range_changes' of https://github.com/mtanda/grafana into mtanda-refresh_temp_value_by_time_range_changes 2016-03-09 11:46:49 +01:00
bergquist
ca7c3cc27d docs(changelog): add opentsdb annotations to changelog 2016-03-09 11:34:59 +01:00
Carl Bergquist
ac439d83fe Merge pull request #4296 from knowroozi/opentsdb_annotations
add annotations for opentsdb
2016-03-09 11:31:05 +01:00
Torkel Ödegaard
c0b92eb5d0 fix(jshint): fixed jshint warning 2016-03-09 10:31:43 +01:00
Torkel Ödegaard
5599bdf1bc Merge branch 'master' of github.com:grafana/grafana 2016-03-09 10:26:11 +01:00
Torkel Ödegaard
de41536046 fix(share): fixed checkboxes in share modal, fixes #4301 2016-03-09 10:26:00 +01:00
Torkel Ödegaard
30d321998c Merge pull request #4295 from utkarshcmu/nav-fix
Minor nav fix
2016-03-09 09:27:38 +01:00
bergquist
59a02ce76a example(plugin.json): add example dashboard file 2016-03-08 22:13:40 +01:00
bergquist
2c396d4922 example(plugin.json): align example app with latests version 2016-03-08 21:50:02 +01:00
Torkel Ödegaard
3191678b14 feat(plugins): work on plugins that include dashboards 2016-03-08 20:46:25 +01:00
Torkel Ödegaard
7ecf057901 Merge branch 'master' of github.com:grafana/grafana 2016-03-08 20:28:04 +01:00
Torkel Ödegaard
091726b374 feat(plugins): commented out dashboard import list 2016-03-08 20:27:40 +01:00
Torkel Ödegaard
dfaa6d8eb9 feat(plugins): a lot of work on #4298 2016-03-08 18:17:47 +01:00
Mitsuhiro Tanda
aff4bf8f6c minor refactoring 2016-03-09 01:47:38 +09:00
Mitsuhiro Tanda
ba1e1532ac change option name more clearly 2016-03-09 00:53:43 +09:00
bergquist
ae3bda81c5 example(plugin.json): add dashboards array in includes 2016-03-08 16:52:48 +01:00
bergquist
0ec747630d examples(plugin.json): add includes info 2016-03-08 16:50:33 +01:00
Kaveh Nowroozi
945131ccab add annotations for opentsdb 2016-03-08 10:47:36 -05:00
NickG123
f11b4cb481 Added a select box to templates that allows template values to be refreshed on refresh 2016-03-09 00:40:33 +09:00
utkarshcmu
92c6025390 Minor nav fix 2016-03-08 07:39:41 -08:00
Carl Bergquist
138c738db9 Merge pull request #4294 from utkarshcmu/docs-fix
Fixed some typos in docs
2016-03-08 16:30:53 +01:00
utkarshcmu
4fae1958fa Fixed some typos 2016-03-08 07:28:25 -08:00
bergquist
fb450385d7 docs(github): move markdown files into .github folder 2016-03-08 15:56:54 +01:00
Torkel Ödegaard
7b1d827460 Merge branch 'master' into dashboard-thing
Conflicts:
	public/app/features/datasources/partials/edit.html
2016-03-08 15:48:01 +01:00
Torkel Ödegaard
74ebc2d3b0 Merge branch 'master' of github.com:grafana/grafana 2016-03-08 15:32:15 +01:00
bergquist
95f3e52064 feat(cli): use commandline object all the way 2016-03-08 14:54:18 +01:00
bergquist
da2b65cd7c feat(editorconfig): add config for go files 2016-03-08 14:31:31 +01:00
bergquist
2fcb8b849e style(cli): fixed typos 2016-03-08 14:30:25 +01:00
bergquist
d7a72e30c0 gofmt 2016-03-08 13:29:42 +01:00
bergquist
f397d0ddd7 fix(cli): retry download when panicing
Will retry to download plugins once if the zip lib panics.

closes #4068
2016-03-08 13:16:58 +01:00
Torkel Ödegaard
db98632078 feat(plugins): progress on plugins page 2016-03-08 12:31:37 +01:00
Torkel Ödegaard
1509b4cb6e Merge pull request #4291 from utkarshcmu/ds-api
Pulled out the common code
2016-03-08 12:03:49 +01:00
utkarshcmu
f20f4d130b Pulled out the common code 2016-03-08 02:51:03 -08:00
Torkel Ödegaard
3af4b1ff98 Merge pull request #4287 from grafana/raintank-issue4283
refactor how template vars are updated. fixes #4283
2016-03-08 11:33:37 +01:00
Torkel Ödegaard
f80c2406a8 feat(plugins): remove app bundled plugins from plugins list 2016-03-08 11:29:36 +01:00
Carl Bergquist
17006b4539 Merge pull request #4290 from utkarshcmu/utkarshcmu-api-docs
Update data_source.md
2016-03-08 11:27:21 +01:00
Utkarsh Bhatnagar
e5d400ebb9 Update data_source.md 2016-03-08 02:19:52 -08:00
Carl Bergquist
f824004e4f Merge pull request #4279 from utkarshcmu/ds-api
Implemented GetDataSourceByName API
2016-03-08 11:13:22 +01:00
bergquist
453eebbac8 style(graph): convert query options to gf-form 2016-03-08 11:08:43 +01:00
utkarshcmu
1a39d93b4e Implemented GetDataSourceByName API 2016-03-08 01:54:10 -08:00
Torkel Ödegaard
6fac471415 feat(templating): fixed failing unit tests in PR #4287 2016-03-08 10:41:20 +01:00
bergquist
252568c91b fix(graph): type in html 2016-03-08 10:33:38 +01:00
bergquist
8e11f8dc21 feat(graph): add spacing above Series specific overrides 2016-03-08 10:30:38 +01:00
Torkel Ödegaard
2475ca8f9a fix(templaing): refactoring PR #4283 2016-03-08 09:32:54 +01:00
bergquist
2a18430a45 docs(plugin): add table reponse format for queries 2016-03-08 09:26:31 +01:00
woodsaj
dc4743a392 ensure current template variable is set.
- When distributing a dashboard it is often not practical to have
"current" template variable option set. This commit ensures that
for dashboards with no current, it is assigned when the dashboard
loads (assuming refresh on load is set.)
2016-03-08 15:41:24 +08:00
woodsaj
0cb57f52de refactor how template vars are updated. fixes #4283
Use promises to order the updates of variable options so that
parents are always updated before children.
This ensures that we only need to query the datasource once per
variable as variables that depend on other variables will only be
processed once their parent has been.
This commit also ensures that variable options are refreshed if
"refresh_on_load" is true even when query params are used to
set the variable seltion.
2016-03-08 15:03:34 +08:00
Torkel Ödegaard
d2aaa2211e fix(plugins): fixed failing unit tests, fixes #4280 2016-03-07 21:45:49 +01:00
Torkel Ödegaard
f4666df7da Merge branch 'master' of github.com:grafana/grafana 2016-03-07 18:04:06 +01:00
Torkel Ödegaard
4cd4ce504d feat(plugins): worked on markdown support for plugin page, #4275 2016-03-07 18:03:45 +01:00
bergquist
fadfa7cc42 fix(postcss): change sourcemap output folder 2016-03-07 17:52:47 +01:00
bergquist
b912edbbef feat(grunt): add autoprefix with postcss
closes #4250
2016-03-07 17:49:47 +01:00
Torkel Ödegaard
a6c6b00d7e Merge branch 'master' of github.com:grafana/grafana 2016-03-07 17:26:57 +01:00
Torkel Ödegaard
2a557f67d2 Do not set remember me cookie when days are set to zero 2016-03-07 17:26:31 +01:00
bergquist
1a6af064b0 fix(cli): improve logging when folders does not exists 2016-03-07 16:41:22 +01:00
bergquist
7ef62d28a5 feat(cli): add logging to catch panics 2016-03-07 16:11:28 +01:00
Torkel Ödegaard
b8fb8cdce6 feat(plugins): progress on plugin details page, # 4275 2016-03-07 14:32:16 +01:00
Torkel Ödegaard
135679096b feat(plugins): progress on plugin details page, # 4275 2016-03-07 14:31:17 +01:00
bergquist
1ff428087e feat(cli): add suppot for plugindir as environment variable 2016-03-07 14:20:51 +01:00
bergquist
f6c5242a93 feat(cli): make repo url a parameter
this is a quick hack to support repo url as parameter. Will refactor
later
2016-03-07 13:29:45 +01:00
Carl Bergquist
3d2d8f2d86 Merge pull request #4274 from utkarshcmu/utkarshcmu-lang
Fixing language plus typos
2016-03-07 13:01:01 +01:00
Utkarsh Bhatnagar
aef8dab4d9 Fixing language plus typos 2016-03-07 03:49:49 -08:00
bergquist
bcb7eff6fa docs(plugins): basic overview text 2016-03-07 12:16:52 +01:00
bergquist
e16f45e494 fix(playlist): fixes failed refactoring 2016-03-07 11:10:10 +01:00
bergquist
435d0f22f5 fix(dashlist): better handling of invalid dashboard ids 2016-03-07 11:04:02 +01:00
bergquist
dc2738afad docs(example): move datasource example to seperate repo 2016-03-07 09:02:22 +01:00
Torkel Ödegaard
08a45e9a3b docs(): docs update 2016-03-07 08:52:16 +01:00
Torkel Ödegaard
00c70307ad fix(panel): fixed to panel height for text panel and unknown panel 2016-03-06 19:23:22 +01:00
Carl Bergquist
883435336c Merge pull request #4265 from utkarshcmu/hide-pass
Hiding password text
2016-03-06 14:56:44 +01:00
Torkel Ödegaard
2c8e35a933 fix(panel): fixed issues with png rendering, also fixed #4260 2016-03-06 12:51:36 +01:00
Torkel Ödegaard
7df18678a4 fix(ux): fixed hidden overflow text in api key modal, fixes #4263 2016-03-06 12:37:06 +01:00
Torkel Ödegaard
260c731f6b fix(panel): fixes for panel height and alignment management and scrollable legends, closes #4266 2016-03-06 12:34:47 +01:00
utkarshcmu
00b1908f3c Hiding password text 2016-03-05 23:47:50 -08:00
Torkel Ödegaard
e73e7aea56 Merge branch 'master' of github.com:grafana/grafana 2016-03-05 13:44:24 +01:00
Torkel Ödegaard
a72d73294c ux(): updated fonts 2016-03-05 13:44:14 +01:00
bergquist
0f546a4692 fix(dashlink): improve variable naming 2016-03-05 12:34:45 +01:00
bergquist
dd7e215e78 feat(dashslist): make sure dashbords exists in recently viewd dashboards
closes #4249
2016-03-05 12:27:37 +01:00
Torkel Ödegaard
fcd75422d5 ux(): update all confirm modals to new design 2016-03-04 20:57:10 +01:00
bergquist
ad6837ee47 docs(plugins): small guide for developing plugins 2016-03-04 14:28:31 +01:00
bergquist
01d5bc73cc docs(plugins): add css to panel example 2016-03-04 13:11:05 +01:00
bergquist
f3b915c43a feat(example): turn panel into metrics panel 2016-03-04 13:11:05 +01:00
bergquist
73a49c463d docs(plugins): add placeholders for plugin docs 2016-03-04 13:11:05 +01:00
bergquist
d86cb92a94 docs(plugins): update readme to link to docs 2016-03-04 13:11:05 +01:00
bergquist
09c29cdda5 docs(plugins): json formating 2016-03-04 13:11:05 +01:00
bergquist
67dec6a665 docs(plugins): json formating 2016-03-04 13:11:05 +01:00
Torkel Ödegaard
b673bc1386 ux(): minor fix to login page 2016-03-04 12:13:40 +01:00
Torkel Ödegaard
4b08f3909d fix(graph): legend height calculation now takes into account series hidden from legend, fixes #4245 2016-03-04 11:16:31 +01:00
Torkel Ödegaard
35fc5007c8 Merge pull request #4251 from utkarshcmu/pref-migrations
Preferences table migration
2016-03-04 10:46:13 +01:00
utkarshcmu
ac499b3aff Minor Pre-PR fixes 2016-03-04 01:29:46 -08:00
Torkel Ödegaard
31c317f5f7 fix(graphite editor): fixed moving functions right and left, broken recently, fixes #3246 2016-03-04 09:42:35 +01:00
Torkel Ödegaard
a6623357ad ux(): minor tweak to validation state 2016-03-04 09:42:35 +01:00
bergquist
c6a1076e3a docs(plugins): json formating 2016-03-04 09:14:25 +01:00
bergquist
d318c84434 docs(plugins): add json formating 2016-03-04 08:47:22 +01:00
bergquist
c21a210198 docs(datasource): add request objects to docs 2016-03-04 08:45:46 +01:00
Torkel Ödegaard
fc877ae0f4 poc(websockets): websocket poc 2016-03-03 23:05:08 +01:00
Torkel Ödegaard
1049824014 ux(): minor tweak to validation state 2016-03-03 22:31:07 +01:00
bergquist
1d8222ef6a feat(example): add basic annotation support for ds 2016-03-03 16:37:21 +01:00
bergquist
ee635be441 docs(mkdocs): remove plugins from ref folder 2016-03-03 13:26:23 +01:00
bergquist
01d3282838 docs(plugins): add initial documentation for datasource plugins 2016-03-03 13:22:09 +01:00
Torkel Ödegaard
35a502f309 Merge pull request #4238 from bergquist/mount_dist_folder
fix(plugins): fixes missed dist loading for plugindir
2016-03-03 11:11:17 +01:00
utkarshcmu
662579e9a9 Added preferences migrations 2016-03-03 02:08:51 -08:00
bergquist
00dd0e8a9d fix(plugins): fixes missed dist loading for plugindir
closes #4230
2016-03-03 11:04:26 +01:00
Torkel Ödegaard
430c312263 Merge branch 'master' of github.com:grafana/grafana 2016-03-03 10:49:41 +01:00
Torkel Ödegaard
8ed8bfb8bc feat(prometheus): added special regex escape for prometheus, fixes #4234 2016-03-03 10:49:30 +01:00
Carl Bergquist
0939371e2e Merge pull request #4237 from utkarshcmu/utkarshcmu-docs
Updated Opentsdb docs for 2.2 support
2016-03-03 10:16:47 +01:00
Utkarsh Bhatnagar
f2dabd0731 Updated Opentsdb docs for 2.2 support 2016-03-03 01:13:30 -08:00
Torkel Ödegaard
e7ef79e0d3 refactor(): minor tweak to markdown to remove watchers 2016-03-03 09:04:06 +01:00
Carl Bergquist
ffda5bc0f7 Merge pull request #4235 from tobio/patch-1
Fix IAM role documentation link
2016-03-03 08:39:01 +01:00
Toby Brain
737896695c Fix IAM role documentation link 2016-03-03 15:33:52 +11:00
Torkel Ödegaard
ae69244ac7 updated keyboard shortcuts modal 2016-03-02 21:36:34 +01:00
Torkel Ödegaard
8232552152 ux(): updated api key modal 2016-03-02 21:34:04 +01:00
Torkel Ödegaard
f7b481fc28 ux(): updated inspector modal 2016-03-02 21:31:49 +01:00
Torkel Ödegaard
8bc1af9d1a ux(): work on new modal design #4191 2016-03-02 21:27:08 +01:00
Torkel Ödegaard
fd1a0edf7f ux(): worked on new modal design #4191 2016-03-02 20:56:04 +01:00
bergquist
4c83dba183 go fmt.... 2016-03-02 17:32:54 +01:00
Torkel Ödegaard
b641720575 Merge branch 'master' of github.com:grafana/grafana 2016-03-02 16:56:27 +01:00
Torkel Ödegaard
950455bd93 ux(): combined page header and tab views 2016-03-02 16:56:16 +01:00
bergquist
eb79436ab7 feat(plugins): mounts dist folder if exists in plugin
closes #4230
2016-03-02 15:13:19 +01:00
Carl Bergquist
10db47bf4c Merge pull request #4228 from utkarshcmu/patch-1
Update CHANGELOG.md
2016-03-02 11:37:08 +01:00
Utkarsh Bhatnagar
4d454f8914 Update CHANGELOG.md 2016-03-02 02:31:32 -08:00
Torkel Ödegaard
eb4a46b40f Merge pull request #4220 from mtanda/issue_1419
Align auto refresh interval
2016-03-02 11:26:34 +01:00
Torkel Ödegaard
7df326083d Merge pull request #4227 from utkarshcmu/tsdb-ms
Grafana supports ms resolution for Opentsdb
2016-03-02 11:24:14 +01:00
utkarshcmu
48f5a61564 Grafana supports ms resolution for Opentsdb 2016-03-02 02:14:58 -08:00
bergquist
19f0f7535f Merge branch 'example_datasource' 2016-03-02 10:45:44 +01:00
bergquist
e3e0b72b43 fix(examples): ignore dist folder 2016-03-02 10:45:17 +01:00
bergquist
3435df8b9c feat(examples): add datasource plugin example 2016-03-02 10:43:41 +01:00
Torkel Ödegaard
7e12460303 Merge branch 'master' of github.com:grafana/grafana 2016-03-02 08:55:25 +01:00
Torkel Ödegaard
9d3d0912e5 ux(): added on hover chevron to pinned brand button 2016-03-02 08:55:13 +01:00
Torkel Ödegaard
1ed4f64e60 templating(): minor update to regex escape chars, #2918 2016-03-02 08:44:20 +01:00
bergquist
8b64b2113e docs(plugins): improve install docs for plugins 2016-03-02 08:39:46 +01:00
bergquist
5bf2b6c382 docs(plugins): improve install docs for plugins 2016-03-02 08:38:56 +01:00
Mitsuhiro Tanda
fa0b06ac60 fix align bug 2016-03-02 16:06:54 +09:00
Mitsuhiro Tanda
ef22a87fcf remove align option 2016-03-02 16:02:08 +09:00
Torkel Ödegaard
bfce379471 Merge pull request #4222 from raintank/pluginSettingEditHooks
Add support for pre/post update hooks in the PluginEditCtrl.
2016-03-02 07:56:23 +01:00
Torkel Ödegaard
4872f6d2dc fix(jshint): removed unused var 2016-03-02 07:54:10 +01:00
Torkel Ödegaard
3c30870dc2 fix(templating): fixed issue with custom all value, fixes #4219 2016-03-02 07:52:48 +01:00
Anthony Woods
4317e4c4a2 Add support for pre/post update hooks in the PluginEditCtrl.
This allows users to intercept the update procedure from their own
controller to modify the pluginSettings before they are saved and
perform additional tasks like syncing state via a third party API.
2016-03-02 14:21:25 +08:00
Mitsuhiro Tanda
7da57e0aa5 align refresh interval 2016-03-02 14:26:15 +09:00
Torkel Ödegaard
0da4168836 fix(prometheus): fixed templating issue with prometheus for when using variable with non regex operator, #2918 2016-03-01 21:35:55 +01:00
Torkel Ödegaard
df67d57bca ux(): minor work on info popover 2016-03-01 21:01:41 +01:00
Torkel Ödegaard
82e7f1a212 Merge pull request #4201 from raintank/removeForcedHeader
remove forced page header from app pages.
2016-03-01 20:14:55 +01:00
Torkel Ödegaard
289521b4b7 Merge pull request #4217 from tdyas/redact_secret_settings
redact settings containing 'secret' besides 'password'
2016-03-01 20:14:34 +01:00
Tom Dyas
d557beb5f1 redact settings containing 'secret' besides 'password'
Ensure that settings with the word 'secret' in the name are redacted just
as ones with 'password' in the name are. For example, the Google Auth
client secret should be redacted now.
2016-03-01 13:50:45 -05:00
Torkel Ödegaard
2cf1193b56 Merge branch 'variable-value-formatting-rethink' 2016-03-01 19:13:11 +01:00
Torkel Ödegaard
57315f1e27 feat(templating): updates to template variable forms 2016-03-01 19:12:54 +01:00
Torkel Ödegaard
56bef637bd feat(templating): fixes for influxdb template variable formating, #2918 2016-03-01 16:33:01 +01:00
Torkel Ödegaard
d1bac6cde0 feat(templating): prometheus now works with new template variable formating/escaping, #2918 2016-03-01 16:11:05 +01:00
Torkel Ödegaard
23a136d9ef feat(templating): moved template interpolation into query building 2016-03-01 14:36:55 +01:00
bergquist
d8f7bce9d4 feat(dashlist): add info text about recently viewed beeing stored in localstorage
closes #4206
2016-03-01 14:28:47 +01:00
bergquist
39354249e9 Merge branch 'utkarshcmu-ms-detection' 2016-03-01 14:11:19 +01:00
bergquist
98e756e278 fix(tooltip): msdetection can now handle null data points 2016-03-01 14:10:09 +01:00
Anthony Woods
91ca5b6f2a Merge pull request #4208 from raintank/suppressNav
add supressNav property to plugin pages.
2016-03-01 20:56:31 +08:00
bergquist
b6ac0860c6 Merge branch 'ms-detection' of https://github.com/utkarshcmu/grafana into utkarshcmu-ms-detection 2016-03-01 13:55:59 +01:00
bergquist
00dc078311 feat(playlist): render playlists if playlist id is invalid
close #4209
2016-03-01 13:50:55 +01:00
Torkel Ödegaard
2d9a2506b4 ux(): fixed panel margin 2016-03-01 13:50:24 +01:00
Torkel Ödegaard
fa73b1ce80 feat(templating): changed how the All templating value works 2016-03-01 13:47:02 +01:00
Torkel Ödegaard
f4b97979c4 ux(): minor fix 2016-03-01 12:26:31 +01:00
bergquist
62b21c586d style(dashlist): rename last viewed -> recently viewed 2016-03-01 12:13:59 +01:00
bergquist
606c75162f feat(dashlist): add support for scripted dashboards
- dashlist will only show dashboards from same org
- notfound dashboards will not be added

closes #4207
2016-03-01 12:05:35 +01:00
Anthony Woods
a8c10dbc08 update json field name of suppressNav 2016-03-01 18:17:40 +08:00
bergquist
c6768a93c8 fix(dashlist): avoid null ref errors 2016-03-01 11:07:56 +01:00
Anthony Woods
74949d306f add supressNav property to plugin pages.
This allows pages to be registered that dont show up in the
Navigation menu when the App is pinned.
2016-03-01 18:07:51 +08:00
bergquist
77f93886da fix(cli): add latest version to list-remote command
closes #4205
2016-03-01 10:55:59 +01:00
Torkel Ödegaard
8f5a7f1764 feat(templating): more work on context specific varaiable formats, #2918 2016-03-01 10:51:39 +01:00
bergquist
f78f7d6b37 docs(plugins): basic instructions for installing plugins 2016-03-01 10:42:49 +01:00
utkarshcmu
75541b9cf0 Optimized msResolution func performation 2016-03-01 01:27:14 -08:00
utkarshcmu
922b7c44ce Added some more test for sanity 2016-03-01 01:15:29 -08:00
utkarshcmu
8bc63e9029 Added spec tests for millisecond resolution 2016-03-01 01:09:14 -08:00
bergquist
2647f59df1 docs(plugins): add skeleton pages for plugins 2016-03-01 09:39:10 +01:00
utkarshcmu
77f6449db9 Added millisecond detection in series 2016-03-01 00:20:34 -08:00
Torkel Ödegaard
f3ad71d751 feat(templating): lots of progress on template variable context specific formats, #2918, all elasticsearch / lucene use cases seem to work now 2016-03-01 08:43:54 +01:00
Torkel Ödegaard
2db62a211a Merge pull request #4202 from grafana/loading-pulse
Loading pulse
2016-03-01 08:36:32 +01:00
Carl Bergquist
4e6c1335d5 Merge pull request #4200 from grafana/mattttt-patch-1
Update repo in package.json to point to official
2016-03-01 08:15:57 +01:00
Carl Bergquist
f185528f1c Merge pull request #4195 from peggyl/fix-dashboard-typo
Fix typo in function name
2016-03-01 08:15:17 +01:00
Matt
2b668e628a Shame, bra toml 2016-03-01 15:14:50 +08:00
Matt
0688d7ca9f Moving from raintank to grafana, rebranded in Grafana orange 2016-03-01 15:14:04 +08:00
Anthony Woods
0135dff001 remove forced page header from app pages. 2016-03-01 15:00:33 +08:00
Matt Toback
efe25db40f Update repo in package.json to point to official 2016-03-01 11:25:54 +08:00
Peggy Li
773a5631c5 Fix typo in function name 2016-02-29 10:52:57 -08:00
bergquist
5d5f5cd9a6 fix(impressionstorage): remove console logging 2016-02-29 19:52:52 +01:00
bergquist
ad9b2ab617 fix(impressionStorage): use title instead of slut
closes #4194
2016-02-29 19:51:35 +01:00
Torkel Ödegaard
cb8b038795 feat(templating): progress on templating rethink 2016-02-29 17:31:31 +01:00
Torkel Ödegaard
078e69d06d feat(templating): simplified templating forms removed all formats 2016-02-29 17:07:53 +01:00
bergquist
df8e56ddf8 docs(plugins): move plugins into seperate folder 2016-02-29 16:53:47 +01:00
Torkel Ödegaard
f44d6e063c Merge branch 'master' into variable-value-formatting-rethink 2016-02-29 16:42:25 +01:00
Torkel Ödegaard
113509a4e9 Merge branch 'master' of github.com:grafana/grafana 2016-02-29 16:41:36 +01:00
Torkel Ödegaard
839c675cb9 ux(): minor tweak 2016-02-29 16:38:45 +01:00
bergquist
854c360def Merge branch 'plopp-master' 2016-02-29 15:02:14 +01:00
bergquist
0cbb95ed1e fix(export_csv): rename export to csv label 2016-02-29 15:01:26 +01:00
bergquist
d8929b1d3e Merge branch 'master' of https://github.com/plopp/grafana into plopp-master 2016-02-29 14:58:38 +01:00
Carl Bergquist
fa99a6745d Merge pull request #4192 from bergquist/last_viewed_dashboards
feat(dashlist): list last x viewed dashboards
2016-02-29 14:51:20 +01:00
bergquist
b79217be1e feat(impressionStore): remove un needed js-ts bridge 2016-02-29 14:37:09 +01:00
Torkel Ödegaard
d27a0f5b0c ux(): small ux fix for inspector modal 2016-02-29 14:35:55 +01:00
Torkel Ödegaard
97c27668bc fix(): fix failing build and removed panel icon from edit mode tabs 2016-02-29 14:15:46 +01:00
bergquist
e5970e83ff feat(dashlist): list last x viewed dashboards
closes #3896
2016-02-29 14:14:43 +01:00
Torkel Ödegaard
d3c022f89e Merge branch 'master' of github.com:grafana/grafana 2016-02-29 13:43:18 +01:00
Torkel Ödegaard
3624587f08 misc(): added elasticsearch.yml config file to docker test env 2016-02-29 13:42:55 +01:00
Torkel Ödegaard
56c080417a fix(logging): only log to xorm.log when in dev mode, fixes #4182 2016-02-29 13:42:07 +01:00
Torkel Ödegaard
da4e3784e9 Merge pull request #4190 from raintank/issue4185
fix app->plugin renamin in more places
2016-02-29 12:59:31 +01:00
Anthony Woods
35f7a71f9a fix app->plugin renamin in more places 2016-02-29 19:54:36 +08:00
Torkel Ödegaard
bf22b4cbfe Merge pull request #4189 from raintank/issue4185
correct path for app page links.
2016-02-29 12:50:13 +01:00
Anthony Woods
4741152f05 correct path for app page links. 2016-02-29 19:37:35 +08:00
bergquist
fb33cf4576 docs(changelog): add info about templated timeshift 2016-02-29 11:14:24 +01:00
Carl Bergquist
1fb38abf6b Merge pull request #4063 from mtanda/timeshift_template
timeFrom and timeShift templating
2016-02-29 11:11:45 +01:00
bergquist
4299feee37 feat(templates): collapse submenu if none visable templates 2016-02-29 10:49:11 +01:00
bergquist
86b1906798 fix(templating): make checkboxes a new row 2016-02-29 10:29:40 +01:00
bergquist
18a0a85df6 Merge branch 'hide_template' of https://github.com/mtanda/grafana into mtanda-hide_template 2016-02-29 10:20:44 +01:00
bergquist
05ba32b552 feat(datasource): add type to datasource list
closes #4183
2016-02-29 10:18:50 +01:00
bergquist
c30c12d369 fix(single_stat): rounding bug in value => text 2016-02-29 10:05:41 +01:00
Mitsuhiro Tanda
09dfaf9875 timeFrom and timeShift templating 2016-02-29 17:53:41 +09:00
Torkel Ödegaard
ae604b6289 ux(annotations): minor polish to annotations editor 2016-02-29 09:50:40 +01:00
Anthony Woods
fc8146b53d Merge pull request #4187 from raintank/issue4185
replace 'app' with 'plugins' where needed.
2016-02-29 15:59:30 +08:00
Anthony Woods
641845519d replace 'app' with 'plugins' where needed. 2016-02-29 15:50:02 +08:00
Carl Bergquist
b32809d03f Merge pull request #4105 from benrubson/issue3982-2
Add some more steps for template auto interval
2016-02-29 08:49:27 +01:00
Carl Bergquist
02b2c7482a Merge pull request #4138 from utkarshcmu/tsdb-refac2
Opentsdb 2.2 support without breaking 2.1
2016-02-29 06:55:41 +01:00
Torkel Ödegaard
6fd0d5e267 Merge pull request #4178 from mtanda/prometheus_template_label
(prometheus) fix label_values() templating
2016-02-28 16:40:37 +01:00
benrubson
a4ecacb9b5 rebase against master 2016-02-28 15:32:34 +01:00
Torkel Ödegaard
b9e0fcdf85 Merge pull request #4103 from benrubson/issue3982
Add a minimum value option for template auto interval
2016-02-28 15:11:33 +01:00
Torkel Ödegaard
4ef79d250d feat(templating): initial work on rethink of value formating 2016-02-28 11:44:11 +01:00
utkarshcmu
18c57ea230 Made opentsdb query_ctrl robust 2016-02-28 01:50:50 -08:00
utkarshcmu
a883424d25 smooth upgrade from Grafana 2.6 to 3.0 2016-02-28 01:50:11 -08:00
utkarshcmu
7fa170cee9 Fixed the UI as per new UX convention 2016-02-28 01:50:10 -08:00
utkarshcmu
8925329950 Added default opentsdb version to datasource 2016-02-28 01:50:10 -08:00
utkarshcmu
4aa5dab62d Added query ctrl tests for Opentsdb 2016-02-28 01:50:10 -08:00
utkarshcmu
936dd2eaaa Added relevant docs and changes 2016-02-28 01:50:10 -08:00
utkarshcmu
09e80f0390 Labels fixed in legend for Filters 2016-02-28 01:49:34 -08:00
utkarshcmu
63dfa303e5 Datasource working with filters after fixing bugs 2016-02-28 01:49:34 -08:00
utkarshcmu
599b1eb689 Smooth transition from opentsdb 2.1 to 2.2 2016-02-28 01:49:34 -08:00
utkarshcmu
4a636b6da7 add, edit, remove filters functionality implemented 2016-02-28 01:49:34 -08:00
utkarshcmu
d92172f50c Added Filters UI 2016-02-28 01:49:34 -08:00
utkarshcmu
2623240635 Fill Policy visible only in <=2.2 2016-02-28 01:49:34 -08:00
utkarshcmu
908e8577bb Removed unused code from datasource.js 2016-02-28 01:49:33 -08:00
utkarshcmu
f90fda8e6f Tracking opentsdb version in opentsdb config 2016-02-28 01:49:33 -08:00
benrubson
f4037667fa rebase against master 2016-02-28 10:43:11 +01:00
benrubson
a1fd12ef42 rebase against master 2016-02-28 10:05:12 +01:00
Torkel Ödegaard
517721eaa4 Merge pull request #4108 from benrubson/issue3982-3
Make auto interval calculation more accurate
2016-02-28 07:58:48 +01:00
Torkel Ödegaard
b56a2c14bb Merge pull request #4161 from godfreyhe/fix_bug_getAggregators
fix bug: can't get the aggregators from opentsdb server
2016-02-28 07:52:02 +01:00
Torkel Ödegaard
62d703fdf7 fix(snapshots): fixed share nav link in snapshots, fixes #4172 2016-02-28 07:39:24 +01:00
Torkel Ödegaard
f29899e566 Merge branch 'master' of github.com:grafana/grafana 2016-02-28 07:29:09 +01:00
Torkel Ödegaard
9cebcc45c1 fix(unsaved changes): fix for unsaved changes warning when changing time range to relative rime range, #4176 2016-02-28 07:28:55 +01:00
Mitsuhiro Tanda
3125177e5c (prometheus) fix label_values() templating 2016-02-28 13:33:29 +09:00
godfreyhe
7810413699 use ES6 arrow function instead of self var on getAggregators 2016-02-28 11:48:54 +08:00
Torkel Ödegaard
261db14c4b Merge pull request #4169 from utkarshcmu/nav-fix
Playlist nav fix
2016-02-27 09:49:29 +01:00
utkarshcmu
16783bff16 Playlist nav fix 2016-02-27 00:40:39 -08:00
Torkel Ödegaard
352cdc137d fix(ux): fixed select box appearance in firefox, fixes #4168 2016-02-27 07:12:05 +01:00
Torkel Ödegaard
bd2e1ef67e feat(plugins): fixed failing api test 2016-02-26 20:27:29 +01:00
Torkel Ödegaard
7f970bbc7b ux(): mini polish to forms, reducing padding between checkbox and label 2016-02-26 19:06:35 +01:00
Torkel Ödegaard
35609fe3d1 ux(): mini fix to alert close btn 2016-02-26 18:59:24 +01:00
Torkel Ödegaard
4fcca7c61b Merge branch 'plugins-list-and-edit-view' 2016-02-26 18:55:33 +01:00
Torkel Ödegaard
d55dc92502 feat(plugins): restored config view functionality to plugin page 2016-02-26 18:55:17 +01:00
Torkel Ödegaard
c148d89004 feat(plugins): progress on plugins page 2016-02-26 18:25:39 +01:00
godfreyhe
8e7a127792 fix bug: can't get the aggregators from opentsdb server 2016-02-26 20:47:22 +08:00
bergquist
6afe2c4e9f ux(influxdb): query options minor changes 2016-02-26 13:25:31 +01:00
bergquist
be69e2c02c ux(influxdb): tight-form -> gf-form 2016-02-26 11:58:59 +01:00
bergquist
e3be9f7fe9 ux(graph): widen input in general tab 2016-02-26 11:36:23 +01:00
bergquist
ca3cb07fcb ux(settings_meta): add space to fill empty labels 2016-02-26 11:33:19 +01:00
Torkel Ödegaard
b98e5690eb ux(): sidemenu, fix to hide subnav menu when you click on hover subnav items 2016-02-26 10:22:06 +01:00
Mitsuhiro Tanda
45e6187c1a add hide template variable option 2016-02-26 00:43:48 +09:00
Torkel Ödegaard
c521182ceb feat(plugins): more work on plugins list/edit view 2016-02-25 15:56:28 +01:00
bergquist
83662b5195 Merge branch 'master' of github.com:grafana/grafana 2016-02-25 15:05:20 +01:00
Torkel Ödegaard
8db7cf49a6 feat(plugins): began refactoring AppSettings -> PluginSettings, and have the plugins list view and plugin edit view be common for all plugins 2016-02-25 14:55:31 +01:00
Torkel Ödegaard
30f3b55baf fix(prometheus): set default templating format to pipe 2016-02-25 10:26:07 +01:00
bergquist
8750ba94c8 fix(docker): rename docker-compose build file 2016-02-25 10:18:48 +01:00
Torkel Ödegaard
b5beac879e Merge branch 'matt-tab-style-tweaks' 2016-02-25 09:32:06 +01:00
Torkel Ödegaard
e8b6995cc7 ux(): form tweaks 2016-02-25 09:28:58 +01:00
Matt
7ca8db15d9 Removed commented out old code 2016-02-25 12:36:03 +11:00
Matt
9d96382ecc Reduced height of tabs and nav-tabs elsewhere 2016-02-25 12:30:36 +11:00
Matt
b86b8965f1 Reduced the heigh of the tabs, adjusted padding on h3 2016-02-25 12:05:19 +11:00
Torkel Ödegaard
f6c49daaa6 Merge branch 'master' of github.com:grafana/grafana 2016-02-24 19:33:08 +01:00
Torkel Ödegaard
a129a6192a ux(): fixed hight of top navbar 2016-02-24 18:34:31 +01:00
Torkel Ödegaard
22ae259cf5 ux(): varios tweaks and polish 2016-02-24 17:49:08 +01:00
Torkel Ödegaard
e627820d3d ux(): padding / margin tweaks and polish 2016-02-24 17:06:02 +01:00
bergquist
65711f4bfe ux(settings_meta): move create new button to bottom of page 2016-02-24 16:01:28 +01:00
bergquist
4531f39c30 ux(settings_rows): move create new button to bottom of page 2016-02-24 15:55:50 +01:00
bergquist
3db1188444 ux(templates): move create new button to bottom of page 2016-02-24 15:18:08 +01:00
bergquist
be3d38ac92 ux(annotations): move create new button to bottom of page 2016-02-24 15:07:34 +01:00
bergquist
b490bdfe33 ux(row_editor): tight-form -> gf-form 2016-02-24 13:49:42 +01:00
Carl Bergquist
95725e407e Merge pull request #4137 from tinyspeck/fix-debian-bin-path
Fix the path to grafana-webserver in the Debian install docs.
2016-02-24 12:26:37 +01:00
bergquist
f6457a2023 ux(templating): tight-form -> gf-form 2016-02-24 11:56:45 +01:00
bergquist
7dcb85010a ux(annotations): change to new tab header 2016-02-24 11:19:09 +01:00
bergquist
0525bf5d4e ux(table): tight-form -> gf-form 2016-02-24 10:42:53 +01:00
Torkel Ödegaard
7207068181 ux(): worked more on new tabs view 2016-02-24 10:32:22 +01:00
bergquist
59d2fe8aa4 ux(dashlist_options): tight-form -> gf-form 2016-02-24 10:09:12 +01:00
Daniel Lee
be92c8bde1 chore(docker): rename fig.yml to docker-compose.yml
Support for the old fig.yml file standard has been removed
in newer versions of docker-compose.
2016-02-24 09:56:57 +01:00
bergquist
a3e22091be ux(submenu): tight-form -> gf-form 2016-02-24 08:32:09 +01:00
bergquist
17b7dfb27b ux(api-keys): tight-form -> gf-form 2016-02-24 07:33:04 +01:00
bergquist
06173b9194 ux(admin): tight-form -> gf-form 2016-02-24 07:25:05 +01:00
bergquist
2a45e879bb ux(panel_timesettings): tight-form -> gf-form 2016-02-24 07:20:54 +01:00
Andrew MacDonald
ce6c67f9bc Fix the path to grafana-webserver in the Debian install docs. 2016-02-23 16:06:56 -08:00
Carl Bergquist
87cb0c2aec Merge pull request #4133 from utkarshcmu/snapshot-shortcut
keyboard shortcut for taking snapshot
2016-02-23 20:31:47 +01:00
utkarshcmu
d0b191af18 Changed snapshot shortcut to CTRL+I 2016-02-23 11:23:13 -08:00
bergquist
b607adadcf ux(panel_links): tight-form -> gf-form 2016-02-23 19:04:54 +01:00
bergquist
e7828c1e5e ux(templating): tight-form -> gf-form 2016-02-23 19:04:54 +01:00
Torkel Ödegaard
c051cb8be1 Merge branch 'tag-box-shadow' 2016-02-23 17:48:29 +01:00
Torkel Ödegaard
6f51fc34c3 ux(): mini tweak to page header gradient line opacity 2016-02-23 17:48:22 +01:00
Torkel Ödegaard
02b02c51e8 ux(): minor change to dashboard header style 2016-02-23 17:40:39 +01:00
Torkel Ödegaard
a414dd028c updated panel edit view 2016-02-23 17:31:19 +01:00
utkarshcmu
c2439b04c9 keyboard shortcut for taking snapshot 2016-02-23 08:11:04 -08:00
bergquist
ed550a894f ux(reset_password): tight-form -> gf-form 2016-02-23 16:14:29 +01:00
bergquist
8b51f58fe7 ux(row_editor): tight-form -> gf-form 2016-02-23 15:48:39 +01:00
bergquist
310b0e888d ux(dashboard_timepicker): tight-form -> gf-form 2016-02-23 15:26:44 +01:00
bergquist
c189c20164 ux(modal): tight-form -> gf-form 2016-02-23 14:49:10 +01:00
Torkel Ödegaard
0811338370 ux(): updated dashboard settings view 2016-02-23 14:05:12 +01:00
Torkel Ödegaard
ecc22757b8 ux(): added dashboard-padding variable 2016-02-23 13:32:14 +01:00
Torkel Ödegaard
5e553e40fa ux(): restored style for tabbed-view-title 2016-02-23 13:29:26 +01:00
Torkel Ödegaard
26c5029256 ux(): new dashboard tabs view 2016-02-23 13:20:59 +01:00
bergquist
75454b02c0 fix(dataproxy): remove partially used cache
closes #4044
2016-02-23 13:05:47 +01:00
bergquist
bbc079e57b ux(snapshots): migrates to gf-form 2016-02-23 13:05:47 +01:00
Carl Bergquist
83bbffd491 Merge pull request #4127 from utkarshcmu/export-shortcut
Export shortcut
2016-02-23 12:37:29 +01:00
bergquist
fc5e1d97af ux(dashboard_links): start migration to gf-form 2016-02-23 10:25:58 +01:00
bergquist
85041d297c ux(import): minor fixes 2016-02-23 10:24:47 +01:00
utkarshcmu
17c7ce9b40 Added export option in Help modal 2016-02-23 00:57:39 -08:00
utkarshcmu
6506161107 Added keyboard shortcut to export dashboard 2016-02-23 00:55:34 -08:00
Torkel Ödegaard
590da0cab3 ux(): fixes to light theme popover / tooltip colors 2016-02-23 09:48:52 +01:00
Torkel Ödegaard
44b6a3a054 changelog(): updated with feature links in annotations 2016-02-23 08:43:34 +01:00
Torkel Ödegaard
a11396c901 Merge branch 'annotations-v2' 2016-02-23 08:42:08 +01:00
Torkel Ödegaard
cd52c24e87 feat(annotations): more work on new annotations 2016-02-23 08:42:03 +01:00
Torkel Ödegaard
2e52008542 feat(annotations): updated editor, removed line color and icon size 2016-02-23 08:22:00 +01:00
Torkel Ödegaard
a6a5f393cc feat(annotations): updated flot events lib and refactored it to use tether-drop lib 2016-02-23 08:09:56 +01:00
bergquist
b3f2f0fa1e ux(import): migrate to gf-form 2016-02-23 07:55:24 +01:00
Carl Bergquist
f788c8cb37 Merge pull request #3632 from mtanda/cloudwatch_annotation_describe_alarms
(cloudwatch) multiple CloudWatch alarm annotation support
2016-02-23 07:41:10 +01:00
Torkel Ödegaard
deaeec0bc7 Merge pull request #4124 from utkarshcmu/nav
some more nav fixes
2016-02-23 05:36:11 +01:00
utkarshcmu
16656af847 some more nav fixes 2016-02-22 14:03:05 -08:00
Matt
3b279983e6 Tried to reduce the opacity of the header bottom-border some to make it seem less intense. Want to get some feedback. Also added a box-shadow to the tags to smooth out the edges (something we've done at raintank) 2016-02-22 17:01:58 -05:00
Torkel Ödegaard
55d4392d90 fix(annotations editor): fixed lagging annotations editor view 2016-02-22 21:55:03 +01:00
Torkel Ödegaard
acfc119409 ux(): added New and Import under divider to dashboard subnav 2016-02-22 21:51:31 +01:00
Torkel Ödegaard
18fcb23371 Merge pull request #4119 from grafana/select-form-updates
Select form updates
2016-02-22 21:02:46 +01:00
Matt
1ae2fc648d grr, .bra.toml 2016-02-22 14:32:01 -05:00
Matt
2215095be8 adjusted button copy on New playlist page 2016-02-22 14:30:35 -05:00
Matt
28d2966819 Merge branch 'master' of https://github.com/grafana/grafana into select-form-updates 2016-02-22 14:25:34 -05:00
Torkel Ödegaard
92efd17952 fix(ux): fixed panel json edit view 2016-02-22 19:03:53 +01:00
Torkel Ödegaard
3a7ec2a26e fixed unit test 2016-02-22 19:00:48 +01:00
Torkel Ödegaard
56a05d78bd Merge branch 'popover-to-drop' 2016-02-22 18:56:54 +01:00
Torkel Ödegaard
fa5cf602f5 removed old popover and unused boostrap components 2016-02-22 18:56:35 +01:00
Torkel Ödegaard
c94659f552 ux(color popover): refactored color popover to use drop lib 2016-02-22 18:46:58 +01:00
bergquist
1164510004 ux(dashboard): migrate view json to gf-form 2016-02-22 18:03:51 +01:00
Matt
f24867029c Merge branch 'master' of https://github.com/grafana/grafana into select-form-updates 2016-02-22 11:47:50 -05:00
Matt
680ff95b8e Form adjustments and startting to add sidemenu 2016-02-22 11:39:11 -05:00
bergquist
31ea5f550f feat(playlist): changes tag result into a list 2016-02-22 16:45:14 +01:00
bergquist
fc62af6b3a style(admin): remove white spaces 2016-02-22 16:21:14 +01:00
Carl Bergquist
f8533e6641 Merge pull request #4083 from marknmel/patch-1
Update kbn.js - correct typo for megabits/sec
2016-02-22 16:08:25 +01:00
Carl Bergquist
87fec9d434 Merge pull request #4093 from utkarshcmu/minor-nav
some nav fixes
2016-02-22 16:07:39 +01:00
bergquist
b1e9327a2b ux(admin): migrates edit org page 2016-02-22 16:05:55 +01:00
bergquist
0aa4b47d59 ux(admin): migrated admin new user page to gf-form 2016-02-22 15:56:18 +01:00
bergquist
b9d50fa144 ux(admin): migrates admin edit user page 2016-02-22 15:32:55 +01:00
Torkel Ödegaard
3231d767d5 in progress work 2016-02-22 15:15:01 +01:00
Torkel Ödegaard
3f05b4bb1e fix(annotations): updated annotations query editor 2016-02-22 14:54:19 +01:00
Torkel Ödegaard
9eabd956b7 ux(): tweak to help popover annimation and fixed pull-right state 2016-02-22 14:20:43 +01:00
Torkel Ödegaard
eb58414600 ux(): fixed sidemenu submenu hover issue that caused it to be hidden as the mouse tried to move on to the submenu 2016-02-22 12:39:56 +01:00
Torkel Ödegaard
cb83c237f4 Merge branch 'master' of github.com:grafana/grafana
Conflicts:
	public/sass/_grafana.scss
2016-02-22 12:00:57 +01:00
Torkel Ödegaard
773a13dc26 fix(): fixed systemjs config for test 2016-02-22 11:45:10 +01:00
Torkel Ödegaard
8c2f7ac083 Merge branch 'master' of github.com:grafana/grafana 2016-02-22 11:42:11 +01:00
Torkel Ödegaard
f375c3000d ux(): help popover 2016-02-22 11:41:50 +01:00
bergquist
ea4ce0ce1f ux(playlist): finalize the ux for playlists 2016-02-22 11:29:09 +01:00
benrubson
c9fe2bab60 make it more smartly 2016-02-22 10:27:08 +01:00
bergquist
6c617ba28c fix(annotations): rearrange missplaced save button 2016-02-22 10:21:22 +01:00
Torkel Ödegaard
b98c826e95 ux(): worked on new popover 2016-02-22 10:17:35 +01:00
benrubson
2034d4b971 update kbn specs to make tests OK 2016-02-22 10:12:02 +01:00
bergquist
f225bb0032 ux(annotations): migrate annotations editors to new form 2016-02-22 10:07:02 +01:00
benrubson
69b87fdb9a make auto interval calculation more accurate 2016-02-22 08:55:52 +01:00
benrubson
6f70445654 Add some more auto interval steps 2016-02-22 08:02:01 +01:00
Torkel Ödegaard
145c14ed57 Merge branch 'master' of github.com:grafana/grafana
Conflicts:
	public/sass/.sass-lint.yml
	tasks/options/sasslint.js
2016-02-22 05:52:02 +01:00
benrubson
b9843fe6d1 Code style typo 2016-02-21 22:07:01 +01:00
benrubson
ab9757082e Code style typo 2016-02-21 22:00:00 +01:00
benrubson
d6e4fb46cf Add a minimum value option for template auto interval 2016-02-21 21:48:09 +01:00
Torkel Ödegaard
a93fe5b2b2 poc(): tether drop 2016-02-21 18:08:44 +01:00
Torkel Ödegaard
8f9c3c8381 lib(): added teather lib and tested it with the panel menu 2016-02-21 16:44:11 +01:00
Torkel Ödegaard
363f36dfae ux(): tweaks 2016-02-21 15:21:01 +01:00
Torkel Ödegaard
7328f4d3fd ux(): minor tweak 2016-02-21 13:07:17 +01:00
Torkel Ödegaard
8f3b6a23f6 fix(): gradient hover only on main submenu item 2016-02-21 12:49:30 +01:00
Torkel Ödegaard
cc4fdd6d0c ux(): fixed issue with cach buster for temlpates, and updated on hover style for sidemenu to look better 2016-02-21 12:47:57 +01:00
Torkel Ödegaard
3781a099dd fix(): removed css background that should not have been there in last commit 2016-02-21 09:06:59 +01:00
Torkel Ödegaard
e4d52b2851 fix(snapshot): fixed snapshot header, fixes #4094 2016-02-21 09:02:32 +01:00
Torkel Ödegaard
ac45ccbad7 fix(panel): fixed text panel issue due to recent style changes, fixes #4095 2016-02-21 08:51:01 +01:00
Torkel Ödegaard
1a412378db fix(forms): reverted back to old checkboxes as the new ones are broken and missing clear state, fixes #4096 2016-02-21 08:18:49 +01:00
utkarshcmu
17904a6e8b some nav fixes 2016-02-20 15:33:58 -08:00
Torkel Ödegaard
9c47fdeb2f ux(): tweaks to light theme 2016-02-21 00:31:35 +01:00
Torkel Ödegaard
808ac2cefc clean(): removed trailing whitespce 2016-02-21 00:08:35 +01:00
Torkel Ödegaard
aaf6dd2cd6 Merge branch 'avatar' 2016-02-21 00:06:45 +01:00
Torkel Ödegaard
08f7ccff38 feat(avatar): added server side proxy and cache of gravatar requests 2016-02-21 00:06:28 +01:00
Matt Toback
13720759a5 Merge pull request #4089 from grafana/matt-weekend-ui
Matt weekend ui
2016-02-20 15:00:44 -05:00
Matt
a2731da987 Errant space and no new line on animations mixin! grr 2016-02-20 14:44:21 -05:00
Matt
a8e1572955 Merge branch 'master' of https://github.com/grafana/grafana into matt-weekend-ui 2016-02-20 14:40:25 -05:00
Matt
3ca8e8a6d2 Added a mixin to handle vendor prefixes for animations. Trying out slight opacity on menu 2016-02-20 14:40:16 -05:00
Torkel Ödegaard
bf4a00b663 ux(): added lines backgrounds, did not add them to the page background, could not make them look good / fit in without being distracting 2016-02-20 18:50:41 +01:00
Torkel Ödegaard
4ab041f79e ux(): added sass linter, almost no rules enabled yet 2016-02-20 18:31:09 +01:00
Torkel Ödegaard
f3fe1a5320 fix(build): trying to fix build 2016-02-20 17:54:51 +01:00
Torkel Ödegaard
f808baafa7 ux(): fixes to side menu and gravatar url 2016-02-20 17:43:26 +01:00
Torkel Ödegaard
1f28ff6890 ux(): added gf-form-select-wrapper 2016-02-20 17:21:35 +01:00
Torkel Ödegaard
640c9a49d8 ux(): merge fixes 2016-02-20 16:51:54 +01:00
Torkel Ödegaard
5d51b439d2 ux(): trying to cleanup new form styles, probably broken it 2016-02-20 16:34:40 +01:00
Matt
9ae050f0e5 Trying to fix gf-form styles 2016-02-20 10:18:16 -05:00
Torkel Ödegaard
c77f91213c ux(): minor tweak 2016-02-20 16:16:29 +01:00
Matt
0f7d6a780a Backed out the bra toml file 2016-02-20 10:15:41 -05:00
Matt
ab4957684f Merged with master, I think 2016-02-20 10:13:18 -05:00
Torkel Ödegaard
1dbaabffbc ux(): dark shade / contrast mini tweak 2016-02-20 16:09:31 +01:00
Torkel Ödegaard
d42bfc2570 ux(): fixed compile issue with last commit 2016-02-20 15:48:42 +01:00
Torkel Ödegaard
9ed45ba761 ux(): clean / simplify markup and css for navbar button 2016-02-20 15:36:52 +01:00
Matt
9d893eec01 Adding delay and animation to submenu 2016-02-20 09:02:12 -05:00
Torkel Ödegaard
52241b8e0b ux(): completed gf-size class rename 2016-02-20 14:48:10 +01:00
Torkel Ödegaard
701a2fdcf3 ux(): tweaks and polish, and also simpifying width classes, gf-size-xxx and gf-size-max-xx are now width-(1-30), and max-width-(1-30) 2016-02-20 14:21:39 +01:00
Torkel Ödegaard
995f17493e ux(): updated influxdb datasource edit forms 2016-02-20 12:55:47 +01:00
Torkel Ödegaard
eb787adccd ux(): added style guide to admin page 2016-02-20 11:35:10 +01:00
Torkel Ödegaard
57e6e0092d ux(): more work on style guide 2016-02-20 11:32:50 +01:00
Torkel Ödegaard
a685e46fb6 ux(): minor tweaks 2016-02-20 11:05:06 +01:00
Matt
1144988443 Merged trent's styles and added admin submenu 2016-02-19 22:00:29 -05:00
Matthew Toback
27dc32e2e8 Started moving select box styles into gf-form 2016-02-19 21:24:46 -05:00
Trent White
6721cec73f created secondary button style, added a couple of variables, played with the plugins page to get the underline in place. Worth a look, but check that I was building everything properly :) 2016-02-19 18:22:24 -05:00
Trent White
18bbefee1c saw how checkbox images were called in css variables, so updated pageImgURL variable. 2016-02-19 17:39:18 -05:00
Trent White
bd0357b637 added angular gradient to page and login. Tweaked header underline to not be so heavy. Tweaked stacked logo on login. Created an alternative to avatar when there's no connection to gravatar - could use work, but I think you get the idea. 2016-02-19 17:34:09 -05:00
Matt Toback
49507ea377 Beginnings of changes 2016-02-19 14:09:48 -05:00
marknmel
2c0b191ef5 Updated typos - Kilobits, Megabits and Gigabits
Update typos - Kilobits, Megabits and Gigabits - not Kilobites, Megabites, or Gigabites
2016-02-19 10:24:49 -05:00
marknmel
02ac7a4001 Update kbn.js
data rate for Mbits has typo - should be megabits/sec - not megabites/sec
2016-02-19 10:05:01 -05:00
Torkel Ödegaard
fbe422008a ux(): began work on sasslint 2016-02-19 15:58:26 +01:00
Torkel Ödegaard
d0d21ba9a6 ux(): updated orange color and fixed sidemenu background on dark theme 2016-02-19 15:33:24 +01:00
bergquist
c78669353f ux(playlist): migrate playlists page to new styles 2016-02-19 15:19:01 +01:00
bergquist
afb62638a8 ux(import): convert to new css format 2016-02-19 15:04:49 +01:00
Torkel Ödegaard
4a062b6d00 ux(): colors refactoring 2016-02-19 14:24:19 +01:00
bergquist
6590e6fae8 feat(panel-menu): remove duplicate in fullscreen
closes #4064
2016-02-19 14:18:26 +01:00
bergquist
ab7bbd5a44 ux(datasource): align name and http settings 2016-02-19 14:08:23 +01:00
bergquist
317f2d043f ux(playlist): migrate to new stylesheet 2016-02-19 13:53:29 +01:00
Torkel Ödegaard
c21b353042 ux(): color/grays palate refactoring 2016-02-19 12:26:59 +01:00
bergquist
a73ef353f0 Merge branch 'timepicker' 2016-02-19 09:13:41 +01:00
bergquist
d769f6c084 ux(timepicker): fix css for the timepicker 2016-02-19 09:13:22 +01:00
Torkel Ödegaard
ed58474c37 Merge pull request #4072 from AutogrowSystems/settings-validation-static-root-path-error-fix
Fixed bug that wasn't showing the StaticRootPath when validation failed
2016-02-19 07:49:40 +01:00
Robert McLeod
4c3048964d removed unused import: errors 2016-02-19 16:09:40 +13:00
Robert McLeod
cacf14a41e Fixed bug that wasn't showing the StaticRootPath when validation failed 2016-02-19 16:00:51 +13:00
Torkel Ödegaard
e24e34619a ux(): began long on tiresome work on color refactors, polished button styles, added buttons to styleguide 2016-02-18 20:41:23 +01:00
Torkel Ödegaard
ac1648c946 ux(): minor tweaks 2016-02-18 19:47:00 +01:00
Torkel Ödegaard
65f9cc986a ux(): styleguide with auto generated colors generated from the sass variable files 2016-02-18 18:01:24 +01:00
Torkel Ödegaard
252cd4901b ux(): added style guide page 2016-02-18 18:01:23 +01:00
bergquist
a2b69e96b9 fix(playlist): give buttons more space to not squash 2016-02-18 15:58:02 +01:00
Torkel Ödegaard
3a0a8810d1 ux(): making light theme better and changing page header 2016-02-18 15:22:20 +01:00
Torkel Ödegaard
b9c60125e8 fix(ux): fixed broken tight forms (mainly query editors) 2016-02-18 14:57:04 +01:00
Torkel Ödegaard
cae975cb39 ux(): fixed login, signup, signup step2 and invite views 2016-02-18 14:44:36 +01:00
Torkel Ödegaard
2f2326006d Merge remote-tracking branch 'origin/master' into style-changes-bulletfactory 2016-02-18 13:37:31 +01:00
bergquist
d183c11e69 feat(cloudwatch): add more metrics for Route53
Thank you https://github.com/aruetten for helping
us find the new metrics

closes #4053
2016-02-18 13:09:50 +01:00
bergquist
653d4b1d6a chore(docs): remove old http api docs 2016-02-18 12:53:43 +01:00
Carl Bergquist
d1f6bbf32f Merge pull request #3923 from utkarshcmu/docs-refac
Arranged http_api docs in a better way
2016-02-18 12:52:50 +01:00
Torkel Ödegaard
22fac87473 added little more spacing between sections 2016-02-18 12:28:49 +01:00
Torkel Ödegaard
3003a8cb6e ux(sass): a lot of polish on headings and margins, ONLY USE bottom margins, othewise margin collapse causes issues 2016-02-18 12:16:47 +01:00
bergquist
f4908b6315 feat(panel): disable span options in fullscreen
closes #4018
2016-02-18 11:19:29 +01:00
bergquist
63ca9f6f5a fix(legend): only add overflow scroll when needed
In firefox the scrollbar is always show when setting
overflow: scroll. This commit makes sure the overflow
setting is only applied when needed.

closes #4049
2016-02-18 11:08:13 +01:00
Carl Bergquist
b9059181fd Merge pull request #4066 from utkarshcmu/user-removal
Added Confirmation modal for user deletion
2016-02-18 09:53:59 +01:00
Torkel Ödegaard
25ca751ab8 Merge branch 'style-changes-bulletfactory' of github.com:grafana/grafana into style-changes-bulletfactory 2016-02-18 09:44:46 +01:00
Torkel Ödegaard
08c1def8b7 ux(): minor update 2016-02-18 09:44:40 +01:00
utkarshcmu
71210dd624 Merge branch 'master' of https://github.com/grafana/grafana into user-removal 2016-02-17 23:09:23 -08:00
Dieter Plaetinck
fee9df4c2b Merge pull request #4065 from grafana/log-level-fix
allow setting level on logger.
2016-02-18 17:03:42 +11:00
Dieter Plaetinck
5d7d165be5 allow setting level on logger.
performance workaround, see https://github.com/grafana/grafana/issues/4055
2016-02-18 16:46:47 +11:00
Trent White
b5d4a678d4 pinned sidebar min-height fix 2016-02-17 12:55:57 -05:00
Torkel Ödegaard
8193d50da7 ux(): updated graph form styles 2016-02-17 13:46:18 +01:00
Torkel Ödegaard
ffc9a8322b Merge pull request #4054 from mtanda/cloudwatch_template_dimension_fix
(cloudwatch) fix template replace in legend
2016-02-17 06:11:26 +01:00
Mitsuhiro Tanda
f28eec8be3 (cloudwatch) fix template replace with panel repeat 2016-02-17 11:59:53 +09:00
Mitsuhiro Tanda
807c052fea (cloudwatch) fix dimension template replace in legend 2016-02-17 11:55:11 +09:00
Matt Toback
45e232ef62 Added a calc to make the page height 100%. Well supported, verified on caniuse 2016-02-16 16:32:09 -05:00
Torkel Ödegaard
9accb962aa ux(sass): temp fix for dashboard edit tabs 2016-02-16 15:21:07 +01:00
Torkel Ödegaard
4ab3542c88 ux(): fixes 2016-02-16 15:12:20 +01:00
Torkel Ödegaard
5a67ca255f ux(): fixes to light theme 2016-02-16 15:03:33 +01:00
Torkel Ödegaard
c97dbf390e ux(): fixed invite box 2016-02-16 14:39:45 +01:00
Torkel Ödegaard
008a031493 ux(sass): fixes and tweaks 2016-02-16 14:07:41 +01:00
Torkel Ödegaard
b05939ec9a ux(sass): work on sass variables, getting messy 2016-02-16 12:15:09 +01:00
Carl Bergquist
84e50f9003 Merge pull request #4046 from utkarshcmu/patch-1
Updated contributing.md with gofmt check
2016-02-16 11:36:34 +01:00
Torkel Ödegaard
7c917156ee ux(sass): variable refactoring 2016-02-16 10:42:06 +01:00
bergquist
6a7e9134a5 fix(renderer): add .exe for phantomjs on windows
closes #3657
2016-02-16 10:12:17 +01:00
Utkarsh Bhatnagar
86ef33f84f fixed language 2016-02-16 00:45:07 -08:00
Utkarsh Bhatnagar
6f794b7d11 Adding gofmt test run to contributing.md 2016-02-16 00:43:48 -08:00
Torkel Ödegaard
febad7b1d7 ux(saas): variable renaming 2016-02-16 09:42:46 +01:00
bergquist
48c5e26acd docs(changelog): add info about cli tool 2016-02-16 09:33:54 +01:00
Carl Bergquist
3f0679896b Merge pull request #4037 from grafana/cmd
Move grafana/grafana-cli into grafana/grafana
2016-02-16 09:31:15 +01:00
Carl Bergquist
96e98f6d4c Merge pull request #4045 from utkarshcmu/patch-1
Typo in contributing.md
2016-02-16 09:26:20 +01:00
Utkarsh Bhatnagar
b067317595 Typo in contributing.md 2016-02-16 00:19:11 -08:00
Carl Bergquist
1febd578a4 Merge pull request #4020 from AxelVoitier/master
Adding units volt-ampere (VA), kilovolt-ampere (kVA) and volt-ampere reactive (var)
2016-02-16 09:00:19 +01:00
bergquist
4131d8b57a feat(cli): add command for upgrading one plugin 2016-02-16 08:49:27 +01:00
bergquist
36f4f1d0f3 fix(cli): add new executables to gitignore 2016-02-16 08:47:26 +01:00
Torkel Ödegaard
1cd3985913 ux(sass): variable renaming 2016-02-16 08:30:37 +01:00
Torkel Ödegaard
058c905432 ux(sass): variable renaming 2016-02-16 08:17:08 +01:00
Torkel Ödegaard
41b775561a ux(): datasource form tweaks 2016-02-16 07:57:58 +01:00
Torkel Ödegaard
0ee7ac2c5e Merge pull request #4015 from onlyjob/codespell
minor spelling corrections
2016-02-16 07:27:12 +01:00
Dmitry Smirnov
3fd6ae597d minor spelling corrections
Signed-off-by: Dmitry Smirnov <onlyjob@member.fsf.org>
2016-02-16 12:12:04 +11:00
Marcus Kempe
14312d225c Added exporting graph data to CSV with series.alias in columns. 2016-02-15 22:49:25 +01:00
Torkel Ödegaard
262a03667e ux(): updated some forms with the new flexbox based classes 2016-02-15 22:37:48 +01:00
Torkel Ödegaard
422decde3b ux(): trying out flexbox for new form styles 2016-02-15 22:24:28 +01:00
Torkel Ödegaard
6fc2b69697 ux(sass): restored old responsive rules 2016-02-15 19:04:35 +01:00
Torkel Ödegaard
594ab0e2b5 ux(sass): restored missing clearfix class 2016-02-15 18:44:49 +01:00
bergquist
ea9ac0d2d2 chore(cli): improve unittests 2016-02-15 18:32:36 +01:00
Torkel Ödegaard
9045be0c12 ux(sass): rename less folder to sass 2016-02-15 18:17:06 +01:00
Torkel Ödegaard
bc4c71a7c6 ux(sass): added bootstrap 4 grid and breakpoint system 2016-02-15 18:04:45 +01:00
Torkel Ödegaard
18079aaced ux(sass): restored label colors 2016-02-15 17:15:54 +01:00
Torkel Ödegaard
47644f2755 ux(): restored dropdown divider class 2016-02-15 17:14:02 +01:00
Torkel Ödegaard
43b91ea0d6 ux(saas): renamed scss partial files to have underscore before 2016-02-15 17:07:46 +01:00
Torkel Ödegaard
83bf63641c ux(): mini light theme fix 2016-02-15 16:55:39 +01:00
Torkel Ödegaard
1e891f434d move to sass is starting to work 2016-02-15 16:44:23 +01:00
bergquist
746257710b fix(cli): align code with core grafana 2016-02-15 16:11:37 +01:00
Torkel Ödegaard
30ddfc7a28 ux(): fix for dashboard header 2016-02-15 16:09:05 +01:00
Torkel Ödegaard
5447bd007a ux(css): migrated from less to saas 2016-02-15 16:02:58 +01:00
Torkel Ödegaard
f8e233e400 commit(): saas changs 2016-02-15 15:27:41 +01:00
bergquist
9c50b89d64 feat(build): make build more generic for executables 2016-02-15 15:22:03 +01:00
bergquist
063b54aefe feat(cli): add grafana-cli to linux packages 2016-02-15 14:58:16 +01:00
Torkel Ödegaard
c961d6218d ux(less): removed normalize 2016-02-15 14:43:33 +01:00
Torkel Ödegaard
1176b68c6a ux(less): moved and consolidated remaining bootstrap stuff, now only grid system left 2016-02-15 14:24:51 +01:00
bergquist
5adac86b43 fix(cli): remove dev text values 2016-02-15 14:19:59 +01:00
Torkel Ödegaard
580cd510d5 ux(less): moved mixins out from bootstrap and removed unused mixins 2016-02-15 14:18:17 +01:00
bergquist
d59beec354 feat(cli): move cli into main repo 2016-02-15 14:09:34 +01:00
Torkel Ödegaard
c11322a016 ux(less): more less cleanup, restructuring 2016-02-15 13:51:56 +01:00
bergquist
fe4cdc59be fix(bra): fix bra runner 2016-02-15 13:19:03 +01:00
Torkel Ödegaard
35a1a04f50 ux(buttons): began work on buttons consolidation and cleanup / refactor 2016-02-15 11:50:31 +01:00
bergquist
6e7813f2f8 feat(build): move grafana into grafana-server 2016-02-15 11:15:38 +01:00
Torkel Ödegaard
7c9728df47 ux(less): refactoring and cleanup 2016-02-15 10:49:20 +01:00
bergquist
da8782a9d0 remove unused imports 2016-02-15 10:34:47 +01:00
bergquist
d523d45124 fix(playlist): dont swallow errors 2016-02-15 10:09:15 +01:00
bergquist
c4d6051477 add fig option for opentsdb 2016-02-15 07:52:34 +01:00
utkarshcmu
cd060c64d5 Merge branch 'master' of https://github.com/grafana/grafana into docs-refac 2016-02-14 22:52:10 -08:00
Carl Bergquist
f881ada45c Merge pull request #4032 from utkarshcmu/snap-bug
Fixing snapshot templating bug
2016-02-15 07:32:17 +01:00
utkarshcmu
b9b3b75c0c Fixing snapshot templating bug 2016-02-14 22:13:59 -08:00
Torkel Ödegaard
37b031afcf ux(css): more progress on css refactor / cleanup 2016-02-14 22:33:03 +01:00
Torkel Ödegaard
fcc3a7f6e4 ux(less): more less refactoring and cleanup, modals, and dropdowns 2016-02-14 22:13:06 +01:00
Torkel Ödegaard
5836a6ec4b ux(less): more less refactoring and cleanup, consolidating alerts 2016-02-14 21:50:06 +01:00
Torkel Ödegaard
9e0ed7bc8e ux(less): less cleanup of unused styles, restructuring and consolidating, part 2 2016-02-14 21:00:25 +01:00
Torkel Ödegaard
50c79df70f ux(less): less cleanup of unused styles, restructuring and consolidating 2016-02-14 20:44:41 +01:00
Torkel Ödegaard
f888716d81 ux(less): refactoring and restructuring less files 2016-02-14 20:05:22 +01:00
Torkel Ödegaard
5274f93db7 ux(less): began less / bootstrap less cleanup and restructuring 2016-02-14 18:02:53 +01:00
Torkel Ödegaard
e32ee9f02e ux(admin): admin pages overhaul 2016-02-14 17:37:05 +01:00
Torkel Ödegaard
48c936e9a9 Merge branch 'style-changes-bulletfactory' of github.com:grafana/grafana into style-changes-bulletfactory 2016-02-14 15:09:22 +01:00
Torkel Ödegaard
b77bce1961 Merge branch 'master' of github.com:grafana/grafana into style-changes-bulletfactory 2016-02-14 15:09:10 +01:00
Torkel Ödegaard
f3d277cbab ux(): general ux polish and experimental work on page header 2016-02-14 13:41:42 +01:00
Torkel Ödegaard
afa4ee9a28 Merge branch 'master' of github.com:grafana/grafana 2016-02-14 10:39:30 +01:00
Torkel Ödegaard
92f4442356 fix(influxdb): fixed annotations editor, broken recently in master due to plugin changes, fixes #4023 2016-02-14 10:39:20 +01:00
utkarshcmu
47b6f01c8b confirmation box added for user removal 2016-02-13 18:21:18 -08:00
utkarshcmu
68225d64aa Converted org_users_ctrl to typescript 2016-02-13 17:55:49 -08:00
Torkel Ödegaard
fa06040ed2 ux(): updated playlist, other other minor fixes 2016-02-13 22:12:15 +01:00
Torkel Ödegaard
eae4bb74dd ux(profile): update profile forms with new form markup and classes 2016-02-13 20:54:00 +01:00
Torkel Ödegaard
caa765ec32 ux(forms): major simplification of norm-form markup and css 2016-02-13 19:42:05 +01:00
Axel Voitier
e00f9611f4 Adding units volt-ampere (VA), kilovolt-ampere (kVA) and volt-ampere reactive (var). 2016-02-13 19:23:30 +01:00
Torkel Ödegaard
1004515bda ux(fix): fixed page header height without using fixed height, now 100% height works 2016-02-13 17:01:18 +01:00
Torkel Ödegaard
7d75e0e53c ux(): minor fixes and cleanup, fixes for white theme 2016-02-13 16:45:07 +01:00
Torkel Ödegaard
f7e3297a0f ux(): updated navbar on all pages to new style, no subnav/dropdown yet though 2016-02-13 14:32:20 +01:00
Torkel Ödegaard
14952de2ee Merge pull request #4009 from utkarshcmu/viewer-bug
Viewers restricted to edit panel
2016-02-13 10:30:02 +01:00
Trent White
f98dbd249e update navbar and elements on playlist snapshots and change apps to plugins 2016-02-12 17:20:58 -05:00
Torkel Ödegaard
b369b7e495 ux(): added page-dashboard body class 2016-02-12 18:55:45 +01:00
utkarshcmu
23167a0bb3 Viewers restricted to edit panel 2016-02-12 07:34:56 -08:00
Torkel Ödegaard
8c1195b277 refactor(): no change, only minor refactor, and update of fontsize to 14px 2016-02-12 15:00:47 +01:00
Torkel Ödegaard
6cdc1e4d37 feat(ux): minor tweaks and fixes, added hover submenu dropdowns 2016-02-12 11:21:42 +01:00
Torkel Ödegaard
e7a202fe4d Merge branch 'master' into style-changes-bulletfactory 2016-02-12 10:14:06 +01:00
Torkel Ödegaard
b5dc1727d2 fix(postgres): If password or user is empty use empty quotes for connection string, #3985 2016-02-12 10:10:07 +01:00
Torkel Ödegaard
53f5cb6553 fix(api): org name taken error now returns HTTP status code 409, closes 2016-02-12 10:01:52 +01:00
Torkel Ödegaard
f797b19825 fix(build): changed from postinstall script to regular grunt task for the copying of npm dependencies into public dir, fixes #4003 2016-02-12 09:58:00 +01:00
Torkel Ödegaard
814ca99e3d fix(google tag manager): fixed link to google tag manager, fixes #4005 2016-02-12 09:52:52 +01:00
Carl Bergquist
c483b2ff98 Merge pull request #3999 from mtanda/cloudwatch_custom_metrics_namespace
(cloudwatch) custom metrics namespace support
2016-02-12 09:47:42 +01:00
Carl Bergquist
2496202417 Merge pull request #3998 from utkarshcmu/ds-conf-box
Added DS deletion confirmation modal
2016-02-12 09:46:41 +01:00
Matt Toback
3c6fadb6f8 Merge pull request #4001 from mattttt/matt-updates-to-bulletactor
Matt updates to bulletactor
2016-02-11 15:55:32 -05:00
Matt Toback
055e5aff2a Merge branch 'style-changes-bulletfactory' of https://github.com/grafana/grafana into matt-updates-to-bulletactor 2016-02-11 15:47:50 -05:00
Matt Toback
692878b0c0 Checkbox fixes for light and dark themes, ready to hand over to trent for new images 2016-02-11 15:46:37 -05:00
Matt Toback
a6061ce555 Checkboxes working 2016-02-11 15:29:57 -05:00
Torkel Ödegaard
2ea548850e Merge branch 'master' into style-changes-bulletfactory
Conflicts:
	pkg/api/index.go
	public/less/sidemenu.less
2016-02-11 21:23:54 +01:00
Torkel Ödegaard
87fc83678c feat(imports): work on datasource dashboards 2016-02-11 21:02:01 +01:00
Trent White
d8b43a3d76 button size tweaks, user form tweaks 2016-02-11 14:41:21 -05:00
Trent White
6189208fa5 org and user form tweaks 2016-02-11 14:18:55 -05:00
Trent White
daf8db71a8 button spacing tweak. Dropdown hover color tweak, sexy pattern added 2016-02-11 13:00:36 -05:00
Trent White
c186d8b2be button text position to center text vertically 2016-02-11 12:27:32 -05:00
Trent White
cd40362d47 sidenav tweaks, creating a content channel for the main content on non-dashboard pages 2016-02-11 12:02:12 -05:00
Mitsuhiro Tanda
81ad469533 (cloudwatch) custom metrics namespace support 2016-02-12 00:30:33 +09:00
utkarshcmu
bb77070aab Merge branch 'master' of https://github.com/grafana/grafana into ds-conf-box 2016-02-11 07:03:04 -08:00
utkarshcmu
c051ff3eac Removed unused commented code 2016-02-11 07:01:45 -08:00
Trent White
ff913333a2 update sidebar 2016-02-11 09:53:48 -05:00
Torkel Ödegaard
ac5f7ecdea fix(img): fixed img link on signup 2016-02-11 15:49:55 +01:00
Torkel Ödegaard
4e33e80957 fix(): clicking on items in graphites add function menu did not work, now works again, broken in recent panel refactorings 2016-02-11 15:25:34 +01:00
Torkel Ödegaard
bf1b60564e fix(png rendering): fixed broken png rendering due to recent panel change 2016-02-11 14:34:15 +01:00
Torkel Ödegaard
50ddf7913a docs(): work on example app 2016-02-11 14:28:04 +01:00
Torkel Ödegaard
39bb9ce118 Merge branch 'master' of github.com:grafana/grafana 2016-02-11 13:42:33 +01:00
Torkel Ödegaard
2d8180fc9c fix(panels): restored panel name to edit mode 2016-02-11 13:42:18 +01:00
utkarshcmu
fac51d92c5 Added DS deletion confirmation modal 2016-02-11 00:06:04 -08:00
utkarshcmu
c3fc340c09 Merge branch 'master' of https://github.com/utkarshcmu/grafana into docs-refac 2016-02-10 23:12:41 -08:00
Trent White
581fb8ebfd dropdown.less added 2016-02-10 18:14:52 -05:00
Trent White
0fa0b3b256 style changes to forms, icons updates and new buttons 2016-02-10 18:14:26 -05:00
Torkel Ödegaard
3b21e9fcf0 Merge pull request #3991 from utkarshcmu/small-fix
Minor html fix
2016-02-10 20:43:41 +01:00
utkarshcmu
4c35c83b84 Minor html fix 2016-02-10 11:13:17 -08:00
Torkel Ödegaard
37c6a1ddf0 feat(app routes): worked on app routes, added unit test, changed Grafana-Context header to start with X to be standard compliant, got cloud saas queries to work via app route feature and header template 2016-02-10 16:43:35 +01:00
Torkel Ödegaard
9c0b89b9b0 Merge branch 'master' of github.com:grafana/grafana 2016-02-10 13:18:13 +01:00
Torkel Ödegaard
ae39ec8585 feat(plugins): changed so that plugins can load css async via util function exposed from app/plugins/sdk 2016-02-10 13:09:39 +01:00
bergquist
e37817285a docs(readme): declare code as bash 2016-02-10 12:08:04 +01:00
Torkel Ödegaard
dfe0e258cd feat(text and css): html partials and css can be loaded via systemjs 2016-02-10 11:54:17 +01:00
Torkel Ödegaard
eda23252e1 Merge branch 'master' of github.com:grafana/grafana 2016-02-10 11:03:26 +01:00
Torkel Ödegaard
257b824d4f feat(plugins): better logging and handling of loading plugins, try to create plugins dir if it does not exist, fixes #3974 2016-02-10 11:03:12 +01:00
bergquist
b469904c7f fix(login): hide divider if no oath
closes #3980
2016-02-10 10:41:43 +01:00
Torkel Ödegaard
509b37eb91 dependency(): upgraded angularjs to 1.5.1 2016-02-10 10:15:11 +01:00
Torkel Ödegaard
9dac382fbf dependency(): updated go lib go-xorm 2016-02-10 10:09:24 +01:00
Torkel Ödegaard
ddbdb54c04 Merge branch 'master' of github.com:grafana/grafana 2016-02-10 09:57:21 +01:00
Torkel Ödegaard
181a671bfb dependency(): upgraded go-sql-driver/mysql, fixes #3969 2016-02-10 09:56:58 +01:00
Torkel Ödegaard
1ce34ed907 Merge pull request #3968 from daniellee/issue3831
Fixes when panel repeat is removed by clearing the templating variables
2016-02-10 09:41:06 +01:00
Torkel Ödegaard
f9e7b14f2c cleanup(): removed old file 2016-02-10 08:32:16 +01:00
Torkel Ödegaard
dad394523f fix(build): fixed minor issue in systemjs builder, and added SystemJs cache buster 2016-02-10 06:50:17 +01:00
Torkel Ödegaard
1c50eb345c Merge pull request #3975 from mtanda/prometheus_fix_annotation
fix template url for prometheus annotation editor
2016-02-10 05:43:14 +01:00
Mitsuhiro Tanda
5c7689388d fix template url for annotation editor 2016-02-10 11:42:59 +09:00
Torkel Ödegaard
baff9b0267 feat(apps): lots of work making apps easier to develop, module paths are handled automatically 2016-02-09 22:10:36 +01:00
Torkel Ödegaard
fe2e6b8a80 feat(apps): began work on support for apps that contain data sources 2016-02-09 18:37:08 +01:00
Torkel Ödegaard
fb74ebb4ea :Merge branch 'master' of github.com:grafana/grafana 2016-02-09 18:17:43 +01:00
Torkel Ödegaard
8784be9a14 feat(plugins): made it possible to have relative plugin template urls 2016-02-09 18:17:32 +01:00
Torkel Ödegaard
fba3d7cb0f Merge pull request #3970 from raintank/appScreenShots
add support for screenshots in plugins.
2016-02-09 16:31:28 +01:00
woodsaj
f953033ba7 add support for screenshots in plugins.
Allow plugin creators to include screenshots of their plugin
in action. Primarily for use in Grafana.net info pages.
2016-02-09 22:36:42 +08:00
Daniel Lee
72415be2db fix(dashboard): fixes when panel repeat with templating removed
The original panel should clear all the templating variables and
    look like it did before repeat was selected. Fixes #3831. Also
cleans up after a row repeat is removed
2016-02-09 14:59:24 +01:00
Torkel Ödegaard
9653f43466 fix(): unit tests 2016-02-09 14:41:43 +01:00
Torkel Ödegaard
1acbd5b7d8 :merge branch 'app-pages'
Conflicts:
	examples/nginx-app/module.js
	examples/nginx-app/partials/stream.html
	examples/nginx-app/plugin.json
2016-02-09 14:22:08 +01:00
Torkel Ödegaard
f0ecbd3878 feat(apps): removed some on hover stuff from sidemenu to make it ready to merge to master 2016-02-09 14:20:41 +01:00
Torkel Ödegaard
9dcfe6dc39 feat(apps): more work on app pages and sidemenu subnav 2016-02-09 14:06:23 +01:00
Torkel Ödegaard
397e4e4766 fix(img): img link on login 2016-02-09 12:20:09 +01:00
Torkel Ödegaard
5b9ed82d29 feat(plugins): working on plugin examples 2016-02-09 12:20:09 +01:00
Torkel Ödegaard
0def04ad34 feat(apps): more progress on app pages 2016-02-09 12:10:59 +01:00
Daniel Lee
e9982bb27e Merge pull request #3952 from bergquist/table_html_escape
Escape html in table panel
2016-02-09 11:23:10 +01:00
Torkel Ödegaard
18eb9d6076 feat(apps): began work on app pages 2016-02-09 11:17:49 +01:00
bergquist
e7ff018487 feat(table): uses lodash to escape html 2016-02-09 11:16:07 +01:00
bergquist
6ba5471bd4 docs(changelog): add html encoding for table panel 2016-02-09 11:16:07 +01:00
bergquist
ddb1d0c684 fix(table): escape / chars as well 2016-02-09 11:14:08 +01:00
bergquist
7d89cf228c fix(table): remove html for htmlencoding option 2016-02-09 11:14:08 +01:00
bergquist
5775c0a341 feat(table): remove option to disable html encoding 2016-02-09 11:14:08 +01:00
bergquist
d750908e36 feat(table): escape html by default
closes #3673
2016-02-09 11:14:08 +01:00
bergquist
b1a648608b test(table): rewrite invalid tests 2016-02-09 11:14:08 +01:00
bergquist
b7147a8bd2 docs(changelog): add prometheus annotation support 2016-02-09 10:27:43 +01:00
Torkel Ödegaard
82d5d1b003 feat(plugins): working on plugin examples 2016-02-09 09:53:56 +01:00
Carl Bergquist
f4e90df406 Merge pull request #3472 from mtanda/prometheus_query_template
(prometheus) templating by query result
2016-02-09 08:26:52 +01:00
Mitsuhiro Tanda
2cce057df1 (prometheus) add query result template query 2016-02-09 01:37:43 +09:00
Torkel Ödegaard
dea2234b14 Merge branch 'master' of github.com:grafana/grafana 2016-02-08 16:57:41 +01:00
Torkel Ödegaard
99a053bbdd feat(): removed unused routes and minor fixes 2016-02-08 16:57:29 +01:00
bergquist
b7fd6bcf7d docs(changelog): add update about fixed height legend 2016-02-08 14:53:29 +01:00
Carl Bergquist
a3b6efdbfa Merge pull request #2883 from mtanda/prometheus_annotation_support
Prometheus annotation support
2016-02-08 14:51:59 +01:00
Torkel Ödegaard
3a1dff6636 fix(): karma now works again, broken in last commit 2016-02-08 14:39:57 +01:00
Torkel Ödegaard
cf92011fb9 Merge branch 'master' of github.com:grafana/grafana 2016-02-08 14:35:45 +01:00
Torkel Ödegaard
0106033293 refactor(): removed stuff 2016-02-08 14:35:34 +01:00
Carl Bergquist
4a43cc1df6 Merge pull request #3958 from bergquist/ux_login
Login: UX improvements
2016-02-08 13:05:05 +01:00
bergquist
0f52b4397f feat(login): minor ux improvements
make buttons bigger and introduce the login divider.

closes #3698
2016-02-08 11:18:41 +01:00
Torkel Ödegaard
9c0da733e8 Merge branch 'master' of github.com:grafana/grafana 2016-02-08 10:31:36 +01:00
Torkel Ödegaard
de90ad8967 feat(influxdb): escape influxdb tag values, fixes #3950 2016-02-08 10:31:26 +01:00
bergquist
2f3d1ec2ef Merge branch 'graph_legend_height' 2016-02-08 10:07:53 +01:00
bergquist
73bed3880f feat(graph): sets fixed height for right side legend
closes #1277
2016-02-08 09:49:53 +01:00
bergquist
edebdb166e fix(graph): add missing ctrl in variable 2016-02-08 09:24:30 +01:00
Torkel Ödegaard
7f83be3d0d ux(): mini fix! 2016-02-08 09:06:28 +01:00
Torkel Ödegaard
50920b1423 ux(forms): minor upgrade to new form design 2016-02-07 20:05:49 +01:00
Torkel Ödegaard
42b1c8c80d Merge branch 'master' into style-changes-mattttt 2016-02-07 19:47:14 +01:00
Torkel Ödegaard
a5d1e9ee43 fix(singlestat): fix for singlestat background and sparklines, fixes #3955 2016-02-07 18:37:07 +01:00
Torkel Ödegaard
ff4dbea19d ux(navbar): worked on responsive breakpoints for navbar 2016-02-07 12:28:06 +01:00
Matthew Toback
1bd58bc1c0 Added new file and removed change to .bra.toml 2016-02-06 17:38:36 -05:00
Matthew Toback
21b0945d08 Beginnings of form restyling, nowhere near merge yet 2016-02-06 17:37:33 -05:00
Torkel Ödegaard
89ef019b7c fix(): back to dashboard link fix 2016-02-06 10:32:07 +01:00
Torkel Ödegaard
801129530e feat(plugins): base clases are now in app/plugins/sdk 2016-02-05 18:08:21 +01:00
bergquist
23fa5fa1c7 Merge branch 'influxdb_global_interval' 2016-02-05 15:13:27 +01:00
bergquist
020277c045 style(panel): fix intendention issue 2016-02-05 15:10:55 +01:00
bergquist
f8b3c0a64c feat(influxdb): add default interval setting
closes #1552
2016-02-05 15:10:33 +01:00
Carl Bergquist
d03ae3bfe5 Merge pull request #3944 from doubledutch/github-api-url
Add github api_url to github auth docs
2016-02-05 14:13:17 +01:00
bergquist
6f9896c2fe docs(contributing): minor updates to old doc 2016-02-05 13:59:16 +01:00
Torkel Ödegaard
853cd16336 fix(search); fixes to dashboard search (using keyboard), and fix for singlestat in snapshot view 2016-02-05 13:48:10 +01:00
Torkel Ödegaard
0fab210ad2 feat(apps): changed edit apps view to use plugin-component for apps config view 2016-02-05 12:13:59 +01:00
Torkel Ödegaard
9fc0a83b83 Merge branch 'master' of github.com:grafana/grafana 2016-02-05 11:08:44 +01:00
Torkel Ödegaard
aa8bd044c5 fix(): various fixes to snapshots 2016-02-05 11:05:47 +01:00
utkarshcmu
0201b9769c Merged with grafana/master 2016-02-05 01:50:47 -08:00
utkarshcmu
4ff6748eb4 Linked docs from main nav 2016-02-05 01:47:34 -08:00
Carl Bergquist
59cb429d2d Merge pull request #3949 from bergquist/table_panel_thresholds
tablepanel: using two thresholds
2016-02-05 10:38:31 +01:00
Torkel Ödegaard
454ccb451b Merge branch 'master' of github.com:grafana/grafana 2016-02-05 10:37:23 +01:00
Torkel Ödegaard
273fbaac68 refactor(): minor changes 2016-02-05 10:37:14 +01:00
bergquist
8ff997594f fix(tablepanel): change to using two thresholds
fixes #3878
2016-02-05 10:30:46 +01:00
utkarshcmu
616a6bec38 Added api heading in the main menu 2016-02-05 01:15:09 -08:00
Carl Bergquist
a6c736b8a2 Merge pull request #3947 from utkarshcmu/route-fix
Fixed snapshot route
2016-02-05 09:51:00 +01:00
Carl Bergquist
5b02d63c89 Merge pull request #3948 from utkarshcmu/changelog
Added snapshot UI feature in Changelog
2016-02-05 09:50:30 +01:00
utkarshcmu
c1fc8995ce Added snapshot UI feature in Changelog 2016-02-05 00:41:54 -08:00
utkarshcmu
34f261588f Fixed snapshot route 2016-02-05 00:35:02 -08:00
Torkel Ödegaard
f188900379 Merge branch 'master' of github.com:grafana/grafana 2016-02-05 08:50:31 +01:00
Torkel Ödegaard
f80d5f8c03 refactor(): minor refactor 2016-02-05 08:50:15 +01:00
Torkel Ödegaard
fcc960e9a2 Merge pull request #3792 from utkarshcmu/snapshot-view
UI Review: Snapshot view
2016-02-05 08:49:23 +01:00
Torkel Ödegaard
db27bbb162 Merge pull request #3918 from utkarshcmu/metadata
Added metadata fields under Settings tab
2016-02-05 08:47:57 +01:00
Torkel Ödegaard
1bce8f6669 Merge pull request #3736 from mtanda/cloudwatch_custom_metrics_alpha
(cloudwatch) custom metrics support
2016-02-05 08:44:50 +01:00
Kevin Pike
15fb56e607 Add github api_url to github auth docs 2016-02-04 13:46:02 -08:00
Torkel Ödegaard
714129c8e3 fix(): package.json use local grunt in postinstall script 2016-02-04 22:44:25 +01:00
utkarshcmu
59a384b453 Merge branch 'master' of https://github.com/grafana/grafana into metadata 2016-02-04 13:34:32 -08:00
utkarshcmu
b5a5b7b912 Removed totalStats from PR 2016-02-04 13:34:23 -08:00
Torkel Ödegaard
a167eb4fa1 fix(row repeat): fix for row repeat where repeated row was added to the bottom and not next to the source row, fixes #2942 2016-02-04 22:33:53 +01:00
Torkel Ödegaard
660ce3a61d fix(row editor): row editor fix and cleanup of unused code 2016-02-04 22:19:46 +01:00
Torkel Ödegaard
edf5868c38 fix(panel timeshift): fixed so that panel time range works when dashboard time range does not end in now, like and , fixes #3941 2016-02-04 21:52:05 +01:00
Torkel Ödegaard
5588e7597c feat(inspector): minor fix for inspector making the error not clear when having dashboard refresh, fixes #3938 2016-02-04 15:31:54 +01:00
Torkel Ödegaard
68a5fb66ff ux(panel menu): changed remove icon to trash icon, closes #3939 2016-02-04 15:28:24 +01:00
Torkel Ödegaard
33dc9fdd76 fix(inspector): fixed broken panel error inspect 2016-02-04 15:23:40 +01:00
Torkel Ödegaard
316e1aac67 fix(build): minor fix 2016-02-04 15:12:44 +01:00
Torkel Ödegaard
2ed3cd7f1a Merge branch 'master' of github.com:grafana/grafana 2016-02-04 15:04:20 +01:00
Torkel Ödegaard
14cc771cbe feat(plugins): made panels loaded via plugin-componet directive 2016-02-04 15:04:07 +01:00
Torkel Ödegaard
2a8b96b680 feat(plugins): last refactoring of how panels are implemented, now the same way as plugin editors 2016-02-04 14:36:19 +01:00
Torkel Ödegaard
6f923ecd17 Merge pull request #3901 from bobrik/opentsdb-tag-name-suggestions
Show relevant tag name suggestions for OpenTSDB, closes #3610
2016-02-04 14:30:33 +01:00
Torkel Ödegaard
501f21b16c fix(dashlist): fix for entering dashboard list edit mode 2016-02-04 13:58:43 +01:00
Ivan Babrou
f4ad673b6d Show relevant tag name suggestions for OpenTSDB, closes #3610 2016-02-04 10:57:19 +00:00
Torkel Ödegaard
37ff432f9d fix(influxdb): fix for influxdb when using format as table and having group by time, fixes #2928 2016-02-04 09:48:17 +01:00
Mitsuhiro Tanda
20283a46f9 fix annotation editor error 2016-02-04 14:14:19 +09:00
Mitsuhiro Tanda
634699c8e2 fix prometheus datasource plugin 2016-02-04 14:10:27 +09:00
Mitsuhiro Tanda
7d97f381cf fix tslint error 2016-02-04 14:09:59 +09:00
Mitsuhiro Tanda
7a1326ff14 follow new plugin format 2016-02-04 14:06:01 +09:00
Mitsuhiro Tanda
ee84d4371b fix prometheus annotation, reflect API change 2016-02-04 14:05:51 +09:00
Mitsuhiro Tanda
f8b05e0f42 add prometheus annotation query 2016-02-04 14:05:44 +09:00
Mitsuhiro Tanda
a4e5b7ea37 fix cloudwatch test error 2016-02-04 13:21:29 +09:00
Mitsuhiro Tanda
a20443b577 (cloudwatch) refactor annotation query 2016-02-04 13:16:55 +09:00
Mitsuhiro Tanda
e96d72d669 reuse credentials 2016-02-04 13:16:55 +09:00
Mitsuhiro Tanda
defb15bea1 CloudWatch multiple alarm annotation support 2016-02-04 13:16:55 +09:00
Mitsuhiro Tanda
10016d9d38 add CloudWatch DescribeAlarms API support 2016-02-04 13:14:03 +09:00
Mitsuhiro Tanda
73ec486434 (cloudwatch) custom metrics support 2016-02-04 13:07:02 +09:00
Mitsuhiro Tanda
ccb063df06 (cloudwatch) add test for custom metrics 2016-02-04 13:07:02 +09:00
Mitsuhiro Tanda
b90a078be0 (cloudwatch) change implementation to testable 2016-02-04 13:07:02 +09:00
Torkel Ödegaard
80e15dd754 feat(css): minor css tweaks 2016-02-03 19:41:39 +01:00
Torkel Ödegaard
de394311e0 feat(datasources): minor fix for optimized build for the refactored query editors 2016-02-03 19:10:01 +01:00
Torkel Ödegaard
908765e0e7 feat(plugins): various fixes entering edit mode after adding a new panel 2016-02-03 18:49:36 +01:00
Torkel Ödegaard
c465e594d7 Merge branch 'master' of github.com:grafana/grafana 2016-02-03 18:27:39 +01:00
Torkel Ödegaard
0da733de9c feat(plugins): migrated opentsdb plugin 2016-02-03 18:25:39 +01:00
Torkel Ödegaard
2fc8da7a87 feat(plugins): migrated cloudwatch and fixed a bunch of issues with data source edit views 2016-02-03 17:01:53 +01:00
Torkel Ödegaard
0bea6aba63 feat(plugins): migrated elasticsearch to new plugin editor model, also minor fixes 2016-02-03 16:31:07 +01:00
Torkel Ödegaard
fe2c096166 Merge pull request #3929 from myokoym/patch-1
doc: fix a broken link
2016-02-03 16:29:21 +01:00
Masafumi Yokoyama
c90619c665 doc: fix a broken link 2016-02-03 23:10:48 +09:00
utkarshcmu
952e4dab3e Arranged http_api docs in a better way 2016-02-02 22:59:22 -08:00
Torkel Ödegaard
eecf844ca2 feat(plugins): migrated influxdb query editor to new plugin model 2016-02-02 22:58:37 +01:00
utkarshcmu
8952c7c9d1 Merge branch 'master' of https://github.com/grafana/grafana into metadata 2016-02-02 11:56:17 -08:00
utkarshcmu
c6ab63ec47 Calculated total stats in frontend 2016-02-02 11:50:01 -08:00
Torkel Ödegaard
05dfccbb74 feat(plugins): moved annotation editor to new plugin component loader 2016-02-02 18:16:30 +01:00
Torkel Ödegaard
fc829b32d9 feat(plugins): minor fixes to breaking out query editor row into reusable component 2016-02-02 16:57:05 +01:00
Torkel Ödegaard
f2700822e9 feat(plugins): extracted first plugin row to its own component 2016-02-02 16:32:36 +01:00
Torkel Ödegaard
21f6c07686 feat(plugins): more progress on plugin editors 2016-02-02 15:15:20 +01:00
Carl Bergquist
4bafb88720 Merge pull request #3915 from pra85/patch-1
Fix typo in docs
2016-02-02 15:02:29 +01:00
Prayag Verma
7c61ed99ae Fix typo in docs
Remove extra `of`
2016-02-02 17:47:06 +05:30
Torkel Ödegaard
356f7b9db6 feat(plugins): good progress on converting query editors, graphite's query ctrl is now working as is unit tests 2016-02-02 13:07:54 +01:00
Torkel Ödegaard
822c8f1575 feat(plugins): migrating graphite query editor to new model 2016-02-02 12:52:43 +01:00
Torkel Ödegaard
efdd4a6682 feat(plugins): more work on plugin editors,prometheus query editor is working 2016-02-02 10:19:15 +01:00
Torkel Ödegaard
eaaf9246b7 feat(plugins): more work on refining datasource editors 2016-02-02 09:12:58 +01:00
utkarshcmu
00a6efa15e Excluded total calculations from backend 2016-02-01 23:26:11 -08:00
utkarshcmu
c5377fb429 Merge branch 'master' of https://github.com/utkarshcmu/grafana into metadata 2016-02-01 23:12:36 -08:00
Torkel Ödegaard
0583ec0f93 feat(plugins): more work on plugin directives and isolation 2016-02-01 23:32:12 +01:00
Torkel Ödegaard
12f487e223 feat(plugin-editors): more work on plugin editor loading 2016-02-01 23:24:08 +01:00
Torkel Ödegaard
30a8a434a1 Merge branch 'master' into plugin-editors
Conflicts:
	public/app/features/panel/panel.ts
	public/app/features/panel/panel_directive.js
	public/app/plugins/datasource/grafana/module.ts
2016-02-01 21:37:36 +01:00
Torkel Ödegaard
79db997e8c login(): testing new login look on login page 2016-02-01 21:31:54 +01:00
Torkel Ödegaard
137ef1f781 ux(home dashboard): minor polish to home dashboard header 2016-02-01 21:17:18 +01:00
utkarshcmu
338afc80d5 Merge branch 'master' of https://github.com/grafana/grafana into metadata 2016-02-01 10:32:36 -08:00
Torkel Ödegaard
78598df96e fixes(): fixes for changed app -> public/app paths and fixes for optimized build 2016-02-01 19:00:40 +01:00
Torkel Ödegaard
e737dab5ca removed /app route, confusing when some assets use public/app/.. route and some use just app/... all public static assets should no use public route, app route is no more 2016-02-01 18:19:02 +01:00
Torkel Ödegaard
84609a4a3b fix(panel links): changed icon back 2016-02-01 17:18:39 +01:00
Torkel Ödegaard
0b25a29a9c Merge branch 'panelbase' 2016-02-01 17:11:08 +01:00
Torkel Ödegaard
b1bfd35968 feat(datasources): last fixes for data sources 2016-02-01 17:06:44 +01:00
Torkel Ödegaard
a053552fee fixes to data source query editors 2016-02-01 13:51:47 +01:00
Torkel Ödegaard
6886faa944 feat(plugins): fixed cloudwatch query editor 2016-02-01 13:30:20 +01:00
Torkel Ödegaard
c843637a6a more progress on some experimental stuff 2016-02-01 13:02:11 +01:00
Torkel Ödegaard
2f78584cdb poc(plugin editors): experimential test for plugin editors 2016-02-01 12:42:10 +01:00
Torkel Ödegaard
6b7491e111 Merge pull request #3903 from grafana/log-fixes
Log fixes
2016-02-01 11:02:14 +01:00
Torkel Ödegaard
2e20c680cb Merge pull request #3892 from pfischermx/master
Allow the use of auth and credentials in opentsdb
2016-02-01 11:01:15 +01:00
Pablo Fischer
f33de8e911 Fix lint/syntax (grunt test) 2016-02-01 09:29:57 +00:00
Dieter Plaetinck
fbc90e038c prevent needless cpu burning in unused levels. fix #3898 2016-02-01 17:49:37 +13:00
Dieter Plaetinck
bf943ddba3 actually make use of the LogLevel type
why else would it be defined?
and this is sane anyway.
2016-02-01 17:48:42 +13:00
Torkel Ödegaard
3f945e886b merge sync with master 2016-01-31 19:51:23 +01:00
Torkel Ödegaard
931d7cd039 Merge branch 'master' into panelbase 2016-01-31 16:57:04 +01:00
Torkel Ödegaard
3f5b33b060 css(): minor tweaks to navbar and timepicker margins/paddings 2016-01-31 11:38:38 +01:00
Torkel Ödegaard
fa63d26485 feat(timepicker): added validation to timepicker, and validation state to apply button, fixes #3870 2016-01-31 11:30:18 +01:00
Torkel Ödegaard
d617d029d2 fix(css): fixed issues introduced in recent sidemenu enhancements, fixes #3893, fixes #3894 2016-01-30 12:55:47 -05:00
Pablo Fischer
98082a940c Allow the use of auth and credentials in opentsdb 2016-01-30 01:09:55 +00:00
Torkel Ödegaard
12460af0ec Merge pull request #3830 from raintank/apiPlugin
Add secureJsonData field to appSettings model
2016-01-29 17:17:37 -05:00
bergquist
34eb5acee7 feat(dataproxy): remove 'SetCookie' from reponse
set cookie could potentialll leak information about the
datasource if in proxy mode.

closes #3845
2016-01-29 23:17:11 +01:00
Torkel Ödegaard
9ec3216ab0 Merge branch 'master' of github.com:grafana/grafana 2016-01-29 16:52:44 -05:00
Torkel Ödegaard
92c2f8d556 feat(pinned sidemenu): completed side menu pinned stuff 2016-01-29 16:52:30 -05:00
bergquist
eef506d8c4 tests(playlist): add more test for playlist ui 2016-01-29 22:31:53 +01:00
Daniel Lee
7f15e2c167 Merge pull request #3889 from grafana/dashboard-share-menu
New dropdown menu to surface the snapshot feature, basic styling in p…
2016-01-29 21:58:05 +01:00
Torkel Ödegaard
03aea09ce9 feat(pinned): updated 2016-01-29 15:49:13 -05:00
Daniel Lee
2897f618a6 Merge pull request #3880 from vitorboschi/fix3877
add default value for fill policy
2016-01-29 21:44:08 +01:00
Torkel Ödegaard
5f2aba6c5b feat(sidemenu): pinned state 2016-01-29 15:36:41 -05:00
Daniel Lee
21632d22ab Merge pull request #3882 from bergquist/playlist_tags
Add support for playlist based on tags
2016-01-29 21:32:58 +01:00
Matt Toback
f59f6a5486 Standardized on fa-link icon for Link instead of external-link, which generally means Open In New Window or Go Offsite 2016-01-29 15:27:42 -05:00
Torkel Ödegaard
32989f4cca Merge branch 'master' into pinned 2016-01-29 15:13:35 -05:00
Torkel Ödegaard
b5ef793ae4 feat(sidemenu): pinned work started 2016-01-29 15:12:56 -05:00
bergquist
d405176367 chore(playlist): remove commented code 2016-01-29 20:33:01 +01:00
Daniel Lee
74cb4b6590 Merge pull request #3891 from grafana/new-icon-font
New icon font
2016-01-29 20:27:13 +01:00
bergquist
15087251fb test(playlist): add test for playlist sqlstoretest(playlist): add test for playlist sqlstoretest(playlist): add test for playlist sqlstoretest(playlist): add test for playlist sqlstoretest(playlist): add test for playlist sqlstoretest(playlist): add test for playlist sqlstoretest(playlist): add test for playlist sqlstoretest(playlist): add test for playlist sqlstoretest(playlist): add test for playlist sqlstore 2016-01-29 20:24:19 +01:00
bergquist
73d6b95339 chore(playlist): remove unused code 2016-01-29 20:24:06 +01:00
Anthony Woods
c3032f7ba3 Merge pull request #3890 from daniellee/joinurlfragments
No added trailing slash if proxypath is empty in JoinUrlFragments
2016-01-29 14:11:43 -05:00
Trent White
339e73ee3d change file names to remove the rt reference in the icon files 2016-01-29 13:57:48 -05:00
bergquist
a2c00f1cc5 docs(playlist): add docs about tags in playlist 2016-01-29 19:44:02 +01:00
Trent White
6da3f87736 use svg icon instead of png file 2016-01-29 12:52:29 -05:00
Trent White
6ae464f33a add rt-fonts file and point refs to snapshot icon to it 2016-01-29 12:46:57 -05:00
Daniel Lee
74decb4bdc fix(dataproxy): no trailing slash if proxypath is empty
The JoinUrlFragments function adds a trailing slash if to the proxy url
if the proxy path is an empty string. This fix removes that trailing
slash. Fixes #3847
2016-01-29 18:44:33 +01:00
Anthony Woods
2e9272c778 Merge remote-tracking branch 'upstream/master' into apiPlugin 2016-01-30 01:38:01 +08:00
Matt Toback
6fe850e2c1 New dropdown menu to surface the snapshot feature, basic styling in place. Want to extend menu to include summary text of each feature 2016-01-29 11:48:57 -05:00
Vitor Boschi
bb3360e92a add default value for fill policy 2016-01-29 07:50:30 -02:00
Daniel Lee
f46eee96a9 Merge pull request #3885 from vitaliyf/patch-2
Update CHANGELOG.md
2016-01-29 05:52:14 +01:00
Vitaliy Fuks
3ed8870362 Update CHANGELOG.md
Minor grammar tweaks and formatting.
2016-01-28 22:02:29 -05:00
Daniel Lee
605f0fa24a Merge pull request #3884 from raintank/issue3883
fix sql query in GetAdminStats.
2016-01-29 02:47:55 +01:00
bergquist
5a4e48fa99 style(playlist_spec): rename to underscore standard 2016-01-29 02:42:23 +01:00
Anthony Woods
79e7ae4424 fix sql query in GetAdminStats. fixes #3883 2016-01-29 09:38:51 +08:00
bergquist
35071649e0 tests(playlist): refactor playlist edit ctrl 2016-01-29 02:37:07 +01:00
bergquist
d27bb4d3fb style(playlist): move dashboard access to dashboard.go 2016-01-29 01:41:23 +01:00
bergquist
64a18874e1 style(playlist): remove unused code 2016-01-29 01:23:51 +01:00
Torkel Ödegaard
05e8c576a2 feat(panels): updated influxdb editor to use panelCtrl 2016-01-28 19:07:53 -05:00
bergquist
ea7c2e73ad style(playlist): remove console logging 2016-01-29 00:38:50 +01:00
bergquist
b6f276265d style(playlist): remove semi colons for functions in TS 2016-01-29 00:13:29 +01:00
Torkel Ödegaard
3c3d3c9ec6 feat(): fixed share modal 2016-01-28 18:05:49 -05:00
bergquist
d66932a8a2 chore(playlist): extract playlist start into new file 2016-01-28 23:56:56 +01:00
Torkel Ödegaard
34141363ae feat(panels): fixed panel time 2016-01-28 17:17:56 -05:00
bergquist
3ccf7c8006 feat(playlist): improve the look of tag playlist items 2016-01-28 23:04:22 +01:00
Torkel Ödegaard
56c76f380b feat(panels): fixes 2016-01-28 16:48:37 -05:00
bergquist
f36ade2959 chore(playlist): cleanup some code 2016-01-28 22:43:54 +01:00
bergquist
85ad5f1d37 Merge branch 'master' into playlist_tags 2016-01-28 22:32:59 +01:00
bergquist
64fa9a6394 fix(singlestat): add ngInject for controller
fixes #3879
2016-01-28 22:27:17 +01:00
Torkel Ödegaard
a00231a1c2 updated gitignore 2016-01-28 14:38:55 -05:00
Torkel Ödegaard
9914714eeb removed npm frontend assets from repo, installed using npm install postinstall script 2016-01-28 14:37:24 -05:00
Torkel Ödegaard
600ffa727e feat(panels): fixes 2016-01-28 14:19:24 -05:00
bergquist
a7de2ceae4 feat(playlist): basic UI support for tags 2016-01-28 20:06:50 +01:00
utkarshcmu
972ac99b7c Added more metadata 2016-01-28 09:53:19 -08:00
Torkel Ödegaard
9bd3b417c4 feat(panels): upgraded table panel to latest plugin model 2016-01-28 12:48:43 -05:00
Torkel Ödegaard
a985f21d44 Merge pull request #3849 from pfischermx/master
Send OpenTSDB POST request as urlencoded
2016-01-28 09:53:16 -05:00
Torkel Ödegaard
7c005e8f0b Merge pull request #3871 from utkarshcmu/changelog
Update CHANGELOG.md
2016-01-28 09:50:54 -05:00
Torkel Ödegaard
6e886735a3 Merge pull request #3872 from utkarshcmu/stats
Fixed dashboard_tag query
2016-01-28 08:15:16 -05:00
utkarshcmu
b30dcce4bc Added dtos and UI for more metadata 2016-01-28 00:52:52 -08:00
utkarshcmu
58121d89fc Updated http_api docs 2016-01-27 22:02:33 -08:00
utkarshcmu
6a1192172d Api stores dashboard creator 2016-01-27 21:55:54 -08:00
utkarshcmu
8bd07287f8 Fixed dashboard_tag query 2016-01-27 17:41:23 -08:00
utkarshcmu
753fd164d7 Added createdBy in metadata ui and dashboard table 2016-01-27 17:11:21 -08:00
Torkel Ödegaard
307c86fc28 feat(panels): fixed singlestat tests 2016-01-27 19:16:33 -05:00
bergquist
72a64388b5 fix(tests): remove only in spec 2016-01-28 01:14:12 +01:00
bergquist
1210fca8e5 fix(singlestat): fix bug in threshold calculations 2016-01-28 01:11:52 +01:00
Torkel Ödegaard
97ac81aa9c feat(panels): upgradede singlestat panel 2016-01-27 19:07:39 -05:00
Utkarsh Bhatnagar
c8727db03b Update CHANGELOG.md 2016-01-27 14:47:58 -08:00
Torkel Ödegaard
57d22fb93f Merge remote-tracking branch 'origin/master' into panelbase 2016-01-27 17:33:33 -05:00
Torkel Ödegaard
f0f7da9ff0 feat(panels): fixing broken stuff 2016-01-27 17:16:00 -05:00
Daniel Lee
6c4791b48d Merge pull request #3868 from daniellee/circleci_triggerpacker
Triggers grafana packer CircleCI build after successful build of master branch
2016-01-27 21:03:00 +01:00
Torkel Ödegaard
9c1217cd2c updated 2016-01-27 14:32:19 -05:00
Daniel Lee
448437c342 feat(circleci): triggers grafana packer after successful build
Only triggers for main grafana repo (not forks) and when the
master branch is built.
2016-01-27 20:18:51 +01:00
Carl Bergquist
251bf7a2b4 Merge pull request #3840 from utkarshcmu/stats
Grafana stats view as mentioned in #3812
2016-01-27 19:41:10 +01:00
Torkel Ödegaard
f1efce56aa feat(panels): fixed duplicate and remove panel 2016-01-27 13:22:37 -05:00
Torkel Ödegaard
34b82caaa8 feat(panels): fixed unit tests 2016-01-27 12:51:01 -05:00
Carl Bergquist
a1b5aae958 Merge pull request #3866 from daniellee/issue3852
fix(graph): narrow panels shows correct date format on x-axis
2016-01-27 17:45:31 +01:00
Daniel Lee
70c42ddcff Merge branch 'sgarg7-master'. Closes #3864 2016-01-27 17:40:51 +01:00
sgarg7
75ab2e026d test(spelling): fix spelling/typo in string 2016-01-27 17:38:02 +01:00
Daniel Lee
f43e1ab2ff fix(graph): narrow panels shows right date format on x-axis
fixes #3852. The function that calculates the date format for
the x-axis on a panel takes the panel width into account and
can be wrong for certain date ranges if the panel is too
narrow. E.g. can show dates in format %m/%d %H:%M when it
should show it as %H:%M
2016-01-27 17:23:02 +01:00
bergquist
12dfee544f Merge branch 'master' into playlist_tags 2016-01-27 15:22:16 +01:00
Carl Bergquist
0ea651f1df Merge pull request #3856 from Gueust/elasticsearc_fix_error
Serialize an elasticsearch error previously printed as 'Object'
2016-01-27 15:08:00 +01:00
Torkel Ödegaard
8ed9e2e5cc Merge pull request #3860 from utkarshcmu/fix-tags
Fixed broken tags search
2016-01-26 21:58:20 -05:00
utkarshcmu
a352af5b9f Fixed broken tags search 2016-01-26 18:48:13 -08:00
Torkel Ödegaard
51a32a2bfa feat(panels): fixes 2016-01-26 18:08:08 -05:00
Torkel Ödegaard
e6013353d2 fix series overrides 2016-01-26 17:54:57 -05:00
Torkel Ödegaard
aac190eaa9 feat(panels): graph panel starting to work 2016-01-26 17:50:18 -05:00
Torkel Ödegaard
ebba7a0327 feat(graph): updating graph panel to new format progress 2016-01-26 17:28:07 -05:00
bergquist
13d993a836 fix(search): remove old search ctrl 2016-01-26 23:28:06 +01:00
bergquist
f384538959 fix(search): fixes broken esc button in search 2016-01-26 23:18:10 +01:00
Gueust
269583a6a1 Serialize an elasticsearch error previously printed as 'Object' 2016-01-26 23:15:54 +01:00
bergquist
0b05d39804 fix(search): fixes missing tags in result 2016-01-26 23:03:03 +01:00
bergquist
2ca7da06a3 Merge branch 'master' into playlist_tags 2016-01-26 22:36:06 +01:00
bergquist
4b59cee17a fix(search): add missing ctrl property in view 2016-01-26 21:12:20 +01:00
Daniel Lee
bf817281a5 Merge pull request #3855 from daniellee/docs_singlestat
Updates documentation for SingleStat thresholds
2016-01-26 21:07:24 +01:00
Daniel Lee
98982b7a74 docs(singlestat) updates threshold explanation
The implementation of thresholds changed after fixing #3248. Docs
updated to reflect and explain the change.
2016-01-26 21:00:13 +01:00
Daniel Lee
2114cbcf0b Merge branch 'circleci_npm' 2016-01-26 20:53:25 +01:00
Daniel Lee
979807feee fix(circleci): deletes node_modules before npm install 2016-01-26 20:52:18 +01:00
bergquist
add7078f66 tech(playlist): convert to typescript 2016-01-26 20:37:44 +01:00
Daniel Lee
ab4d020212 fix(circleci): updates npm before npm install
npm for node 4 on circleci is really old. This updates npm and will
hopefully make the build green again.
2016-01-26 20:33:00 +01:00
Torkel Ödegaard
aa251fc9ce feat(panels): upgraded dashlist panel to new format 2016-01-26 12:22:46 -05:00
bergquist
c105a07bab Merge branch 'playlist_tags' 2016-01-26 17:56:30 +01:00
bergquist
09de46e5ac tech(search): convert search to typescript 2016-01-26 17:54:19 +01:00
Torkel Ödegaard
cc375f48c7 feat(panels): minor fix 2016-01-26 11:34:58 -05:00
utkarshcmu
e59b0c0694 Fixed ts file comment 2016-01-25 18:10:48 -08:00
utkarshcmu
07fee0a810 Converted adminStatsCtrl to typescript 2016-01-25 17:49:39 -08:00
Pablo Fischer
29185eeef7 If OpenTSDB is 3rd-party hosted (or by another team) and does not support OPTIONS, send the request as POST (urlencoded) 2016-01-26 00:12:56 +00:00
Torkel Ödegaard
53dc21c69b feat(panels): minor fixes 2016-01-25 17:58:41 -05:00
Torkel Ödegaard
b0dd79cbfd feat(panels): MetricsPanelCtrl is starting to work 2016-01-25 17:51:18 -05:00
utkarshcmu
442db7fee1 Changed sql query for grafana_admin_count 2016-01-25 14:30:36 -08:00
Daniel Lee
be2e2577b8 fixes #3839
Uses width set to 800px for invite div instead of position fixed. It
looks the same for desktop and makes the button clickable on smaller
resolutions and mobile. Although it is not really responsive so the
text will be small on mobiles. Better that though than a non-clickable
button.
2016-01-25 22:59:48 +01:00
Anthony Woods
c8c337cead use PBKDF2 to esnure key is 23bytes. 2016-01-26 05:15:29 +08:00
bergquist
92cba94031 tech(fmt): remove unused code 2016-01-25 22:11:24 +01:00
Torkel Ödegaard
c30b1b126d feat(panels): minor progress 2016-01-25 15:58:24 -05:00
bergquist
52403ca17e feat(playlist): add usage statisics 2016-01-25 21:39:45 +01:00
Anthony Woods
05868bc1df fix typo 2016-01-26 04:24:44 +08:00
Anthony Woods
092bb69c41 instead of padding with 0's, cycle through the secret. 2016-01-26 04:18:44 +08:00
Anthony Woods
40d946a6e3 add drop table to ensure existing installs get new schema 2016-01-26 04:18:18 +08:00
Daniel Lee
5f1fe13530 Merge branch 'jimmyR-master' resolves #3741 2016-01-25 21:16:58 +01:00
jimmyR
d8bb7c3094 resolves #3741 merge conflict
After a refactoring the sidemenu-canvas css class disappeared so changed the code from #3741 to use the main-view class instead.
2016-01-25 21:15:54 +01:00
Torkel Ödegaard
9c6698e87b feat(panels): progress on new panel infrastructure, base classes 2016-01-25 15:09:37 -05:00
bergquist
1cac6ecedb tech(docker): update influxdb to use latest 2016-01-25 20:46:15 +01:00
bergquist
40088cd4fe tech(docker): add elastic fig 2016-01-25 20:30:25 +01:00
bergquist
b939a27a8d revert f3bc726001bfbc707597bce5fa169b46e992eb7ao
This change have caused alot of questions. So we revert
2016-01-25 18:40:28 +01:00
Torkel Ödegaard
73af4df96d feat(panels): upgraded text panel 2016-01-25 11:41:20 -05:00
Daniel Lee
70cd9265bf Merge pull request #3844 from bergquist/negative_single_stat_panel
Reduce the amount of thresholds values to two in singlestat panel
2016-01-25 16:44:37 +01:00
bergquist
cd1b2e2841 feat(singlestat): reduce max thresholds to two.
closes #3248
2016-01-25 16:27:58 +01:00
bergquist
b0a24ae4aa tech(singlestat): move singlestat test to plugin
and change to typescript
2016-01-25 16:13:45 +01:00
Torkel Ödegaard
11e35f7b68 Merge remote-tracking branch 'origin/master' into panelbase 2016-01-25 10:00:25 -05:00
Torkel Ödegaard
8f4cf6c797 feat(panels): updated text panel to new format 2016-01-25 09:56:17 -05:00
utkarshcmu
2190392e05 Added grafana_admins count 2016-01-25 00:39:31 -08:00
utkarshcmu
a621c0d273 Added docs for stats api 2016-01-25 00:02:05 -08:00
utkarshcmu
4c12703e0c Integrated angularjs with go api 2016-01-24 21:39:30 -08:00
utkarshcmu
da67afa51e Fixed api bugs, stats endpoint working 2016-01-24 21:18:17 -08:00
Torkel Ödegaard
3e14f8a0e5 feat(): panel refactoring 2016-01-24 18:44:21 -05:00
Torkel Ödegaard
a950ff9795 feat(panel): more panel base infrastructure 2016-01-24 17:58:08 -05:00
Torkel Ödegaard
4132cf12e3 feat(panels): more panel refactoring 2016-01-24 17:30:29 -05:00
Torkel Ödegaard
4f7fb40d9b feat(panel plugin): improving panel plugin model 2016-01-24 16:39:25 -05:00
utkarshcmu
c7fae5386d Added backend API for stats 2016-01-24 11:01:33 -08:00
bergquist
42802ac710 tech(singlestat): convert singlestat panel to typescript 2016-01-24 18:56:10 +01:00
bergquist
a85bda13db tech(docker-dev): update dev docker for graphite 2016-01-24 18:07:42 +01:00
Torkel Ödegaard
ecdc730de7 poc(): new panel system 2016-01-23 15:40:30 -05:00
Torkel Ödegaard
8927042421 more new panel stuff 2016-01-23 01:44:38 +01:00
Anthony Woods
32f78d465b add secureJsonData to appSettings model.
- adds the new column to the DB table.
- data stored in the DB is encrypted
- update appRouteHeaders templates to use the jsonData and
decrypted secureJsonData
2016-01-23 06:17:22 +08:00
Anthony Woods
ab3b586838 add encryption util functions 2016-01-23 03:15:39 +08:00
Torkel Ödegaard
94a7e9b185 poc(panel): experimental panel stuff 2016-01-22 19:59:36 +01:00
Torkel Ödegaard
1a708da155 Merge pull request #3821 from raintank/apiPlugin
merge apiPlugins with appPlugins
2016-01-21 19:42:28 +01:00
Anthony Woods
f94599cd29 merge apiPlugins with appPlugins 2016-01-22 01:15:04 +08:00
Torkel Ödegaard
d9d4e6c82f Merge pull request #3819 from bobrik/opentsdb-fill-policy
Support OpenTSDB 2.2 fill policies, closes #3802
2016-01-21 17:54:32 +01:00
Torkel Ödegaard
0796b2c0e3 poc(panel as isolated compoennts): experimental panel stuff 2016-01-21 17:46:57 +01:00
Ivan Babrou
bbfdbaf952 Support OpenTSDB 2.2 fill policies, closes #3802 2016-01-21 16:38:46 +00:00
Torkel Ödegaard
7b4fe824ec Merge branch 'master' into panelbase 2016-01-21 15:29:14 +01:00
bergquist
28fabadeae style: remove empty row 2016-01-21 15:13:06 +01:00
Carl Bergquist
37495dd1c6 Merge pull request #3815 from volter/playlist_sort
Fix dashboard sorting in playlists
2016-01-21 15:09:33 +01:00
Volker Fröhlich
e5e8e2021f Fix dashboard sorting in playlists 2016-01-21 14:58:15 +01:00
bergquist
dfd4fbc566 feat(hooks): improve symlinks script 2016-01-21 14:39:32 +01:00
bergquist
08f02397b6 fix(fileexport): tslint fix 2016-01-21 14:31:20 +01:00
bergquist
d3f90dcfcc style(fileexport): remove commented code 2016-01-21 14:26:31 +01:00
bergquist
ba65b89bbb feat(csv export): extract csv export into a new file 2016-01-21 14:22:39 +01:00
Torkel Ödegaard
3d353c7d6d fix(mixed datasource): fixed issue with mixed data source in optimized build 2016-01-21 13:14:25 +01:00
Torkel Ödegaard
bc05cc4977 fix(phantomjs): another fix for phantomjs rendering, #3804 2016-01-21 12:57:03 +01:00
Torkel Ödegaard
cbb5811d8b fix(cleanup): removed unused js file 2016-01-21 11:40:04 +01:00
Torkel Ödegaard
6461981aa4 build(): minor change 2016-01-21 11:40:04 +01:00
utkarshcmu
c260c319ee Started Grafana stats poc 2016-01-21 01:48:29 -08:00
Carl Bergquist
d13957cb72 Merge pull request #3803 from xadhoom/table_export_csv
add export to csv in table panel
2016-01-21 10:33:18 +01:00
Torkel Ödegaard
4a8f82ca9b fix(image rendering): fixed issue with image rendering, fixes #3804 2016-01-21 10:10:32 +01:00
matteo brancaleoni
cdcc7a7172 add export to csv in table panel 2016-01-21 10:02:23 +01:00
Torkel Ödegaard
f2ce8f266b Merge pull request #3810 from raintank/apiPlugin
ApiPlugin custom header support
2016-01-21 08:32:26 +01:00
Anthony Woods
dcde1422b7 add support for apiPlugin headers.
The header content uses text/Template.  If the apiPlugin is
bundled in an App, then the appSettings.JsonData is passed
to the header template.
2016-01-21 11:41:59 +08:00
Anthony Woods
423eca6e7d add support for fetching appSettings by appId 2016-01-21 11:41:02 +08:00
Anthony Woods
fd52320460 set includedAppId of apiPlugins 2016-01-21 11:39:51 +08:00
Anthony Woods
462608517b set pluginDir of apiPlugin object 2016-01-21 11:38:27 +08:00
Anthony Woods
9586493632 add apiPluginHeader support 2016-01-21 11:37:48 +08:00
Torkel Ödegaard
b150452db3 Merge pull request #3807 from raintank/apiPlugin
allow saving changes to appModel made by configView directive
2016-01-20 19:27:57 +01:00
Anthony Woods
1bca28ad12 include the jsonData in the AppSettings DTO 2016-01-21 02:23:24 +08:00
Anthony Woods
9e121ef0c8 add save button to config page
configView directives can update the appModel object.  We need
a save button to persist the updates.
2016-01-21 02:21:30 +08:00
Torkel Ödegaard
5f5fcc0e04 fix(submenu): added ngInject comment to dashboard submenu 2016-01-20 11:57:56 +01:00
utkarshcmu
a854f0c4d4 Switched snapshot ctrl to angularjs2 2016-01-20 02:35:24 -08:00
Torkel Ödegaard
1979143e7c fix(export): fix export dashboard to json, been broken in master for 2-3 weeks 2016-01-20 11:20:33 +01:00
Torkel Ödegaard
32ffedccda Merge pull request #3798 from mtanda/prometheus_doc_metrics
(prometheus) add explanation about incompatibility of metric find query
2016-01-20 10:43:37 +01:00
Torkel Ödegaard
4f7f03a28c fix(playlist): fix for memory leak when running playlist for a long period, fixes #3794 2016-01-20 10:39:58 +01:00
Mitsuhiro Tanda
d0074b25db (prometheus) add explanation about incompatibility of metric find query 2016-01-20 18:30:17 +09:00
Torkel Ödegaard
8dd118bd86 updated 2016-01-20 09:45:24 +01:00
Torkel Ödegaard
fb82425d3e Merge pull request #3797 from utkarshcmu/playlist-unused
Removed unused component from playlist code
2016-01-20 08:59:03 +01:00
utkarshcmu
aa1d28835d Fixed angularjs variable names 2016-01-19 23:23:44 -08:00
Torkel Ödegaard
f30df8bb57 Merge pull request #3795 from raintank/apiPlugin
get apiPlugins working again.
2016-01-20 07:42:36 +01:00
utkarshcmu
281ec60085 UI and backend working 2016-01-19 22:04:38 -08:00
utkarshcmu
09f5e6f4dc Merge branch 'master' of https://github.com/utkarshcmu/grafana into snapshot-view 2016-01-19 21:05:50 -08:00
utkarshcmu
e26cd21048 Converted ctrl to typescript 2016-01-19 21:04:53 -08:00
utkarshcmu
1c5be92259 Removed unused component from playlist code 2016-01-19 17:15:24 -08:00
utkarshcmu
6e99eed417 Moved snapshot route to core routes 2016-01-19 17:00:54 -08:00
Anthony Woods
92a085550e fix up imports 2016-01-20 06:17:48 +08:00
Anthony Woods
c4a0ec844c get apiPlugins working again. 2016-01-20 06:13:45 +08:00
Torkel Ödegaard
3e3b996963 feat(plugin): experimental work on plugin architecture 2016-01-19 21:57:58 +01:00
bergquist
36e99ac531 feat(tech): force create symlinks 2016-01-19 21:46:43 +01:00
Torkel Ödegaard
7a26d309b1 feat(apps): more work on apps and how apps can include panels 2016-01-19 18:18:53 +01:00
utkarshcmu
ca55d1f315 Minor bug fixes 2016-01-19 05:05:24 -08:00
utkarshcmu
41fd0ed467 Merge branch 'master' of https://github.com/grafana/grafana into snapshot-view 2016-01-19 05:05:03 -08:00
utkarshcmu
bcb44b7b31 UI and backend connectivity implemented 2016-01-19 05:02:22 -08:00
utkarshcmu
1ab1154010 Optimized backend queries 2016-01-19 04:09:57 -08:00
Torkel Ödegaard
6b85a6fd78 feat(apps): minor design update for apps view 2016-01-19 11:54:35 +01:00
utkarshcmu
8f067a5ed2 Added backend functionality for searching snapshots 2016-01-19 01:37:36 -08:00
Torkel Ödegaard
db1ba30df7 Merge pull request #3789 from utkarshcmu/snap-bug
Snapshot name is saved in DB now Fixes #3768
2016-01-19 10:34:04 +01:00
utkarshcmu
1952ebf7c4 Fixed failing gofmt tests 2016-01-19 00:33:30 -08:00
utkarshcmu
70481953fd Snapshot name is saved in DB now 2016-01-19 00:26:20 -08:00
Carl Bergquist
870775e863 Merge pull request #3788 from utkarshcmu/grunt-test
Fix failing circleci
2016-01-19 09:13:20 +01:00
utkarshcmu
54383a9a0c Fix failing circleci 2016-01-19 00:08:55 -08:00
Torkel Ödegaard
510a21195a feat(influxdb): support for policy selection in query editor, closes #2018 2016-01-18 18:38:36 +01:00
Torkel Ödegaard
3b5a583903 Merge branch 'master' into influxdb-policy-selector 2016-01-18 18:10:01 +01:00
Torkel Ödegaard
a9e05c77d1 Merge pull request #3780 from msambol/graphite_doc
Fix grammatical error in graphite datasource doc
2016-01-18 18:09:33 +01:00
Michael Sambol
3418db1dcd Fix grammatical error in graphite datasource doc
Replace "you" with "your".
2016-01-18 10:41:14 -06:00
bergquist
d94896cf10 feat(build): make symlink script executible 2016-01-18 17:31:53 +01:00
bergquist
eb8871a4bd fix(playlist): add nginject for prod build 2016-01-18 17:31:33 +01:00
Carl Bergquist
389dd12ab4 Merge pull request #3779 from bergquist/playlist_stop_playing
feat(playlist): clicks outside control stops playlist
2016-01-18 17:23:20 +01:00
bergquist
4a54edd8bb feat(playlist): clicks outside control stops playlist
fixes #3711
2016-01-18 17:17:13 +01:00
Torkel Ödegaard
1d4803cff0 fix(singlestat): fixed issue with singlestat and drilldown link introduced in recent commit, fixes #3777 2016-01-18 16:18:04 +01:00
Torkel Ödegaard
6fc972ab1e feat(playlists): merge sync with RP 2016-01-18 16:05:38 +01:00
Torkel Ödegaard
66eebd1ac3 refactor(playlist): refactor of playlist feature, and PR #3776 2016-01-18 16:01:14 +01:00
bergquist
568832c5af style(playlist): improves variable name 2016-01-18 14:58:46 +01:00
Torkel Ödegaard
4ff7b0f49b Merge branch 'playlist_reload' of https://github.com/bergquist/grafana into bergquist-playlist_reload 2016-01-18 14:51:54 +01:00
bergquist
c12aa0e8ce feat(hooks): add scripts for symlinking git hooks 2016-01-18 14:41:17 +01:00
bergquist
61a655f199 feat(hooks): add grunt test to pre commit 2016-01-18 14:37:53 +01:00
bergquist
88e9161e57 style(playlist): fixes some TS hint errors 2016-01-18 14:13:11 +01:00
bergquist
10adc57b3f style(playlist): fixes some TS hint errors 2016-01-18 14:05:48 +01:00
bergquist
62ae02bdd1 feat(playlist): reload all dashboards every cycle
closes #3706
2016-01-18 13:54:32 +01:00
bergquist
dca503bcbd feat(playlist): playlistsrv is now started by id 2016-01-18 13:40:51 +01:00
bergquist
bc21862661 tech(playlist): refactor playlistSrv to typescript 2016-01-18 13:21:48 +01:00
Torkel Ödegaard
1e06f3f5f4 Merge branch 'master' of github.com:grafana/grafana 2016-01-18 12:19:54 +01:00
Torkel Ödegaard
00802d035a refactor(): refactoring submenu to directive 2016-01-18 12:19:46 +01:00
Torkel Ödegaard
edcef7d078 fix(graph): fixed for graph series color selector popover, broken in recent 3.0-pre1 build, fixes #3774 2016-01-18 12:12:05 +01:00
bergquist
899a44a735 feat(units): add more data rate options 2016-01-18 10:02:46 +01:00
bergquist
6a95963c89 Revert "feat(units): add more data rate units"
This reverts commit a35bf497be.
2016-01-18 09:47:01 +01:00
bergquist
a35bf497be feat(units): add more data rate units
closes #3759
2016-01-18 09:26:24 +01:00
Carl Bergquist
9b42b33648 Merge pull request #3771 from bergquist/contant_time_comparison
fix(login): fix vulnerbility for timing attacks
2016-01-18 08:44:11 +01:00
bergquist
053868f593 fix(login): fix vulnerbility for timing attacks
closes #3760
2016-01-18 08:38:32 +01:00
Torkel Ödegaard
1adb7b286c updated 2016-01-18 07:28:01 +01:00
Torkel Ödegaard
30c19d525e ux(): minor page rename 2016-01-17 20:32:37 +01:00
Torkel Ödegaard
8161a0943d ux(password): minor fix for change password page 2016-01-17 20:16:39 +01:00
Torkel Ödegaard
a8e3f731b7 feat(influxdb): began work on influxdb policy selector 2016-01-17 17:53:38 +01:00
Torkel Ödegaard
0cb68b86fc refactor(): minor change 2016-01-17 17:24:10 +01:00
Torkel Ödegaard
723be4f612 refactoring(): unified dashboard top nav to a single dashnav component, uses new navbar component 2016-01-17 11:34:51 +01:00
Torkel Ödegaard
070af40487 refactor(): began refactoring topnav directive to be more like the new style of components, and also make it usable on all pages including dashboard 2016-01-16 23:26:29 +01:00
Torkel Ödegaard
0a58404584 fix(build): minor build script fix, fixes #3756 2016-01-16 19:16:49 +01:00
Torkel Ödegaard
c201f4c63e feat(sidemenu): added handling of click outside to hide sidemenu, also refactored grafana_ctrl to a more general grafana component 2016-01-16 18:55:13 +01:00
Torkel Ödegaard
317b5e6d86 fix(sidemenu): fixed issue with new sidemenu in optimized build, #3687 2016-01-16 16:17:29 +01:00
Torkel Ödegaard
38ddc88b20 fix(api): do not include null jsonData field in /api/datasources resource, closes #3755 2016-01-15 15:57:00 +01:00
Torkel Ödegaard
7ad72ba905 ux(): minor style fixes to pages 2016-01-15 15:51:30 +01:00
Torkel Ödegaard
36e8af05a2 ux(more style updates) 2016-01-15 15:05:13 +01:00
Torkel Ödegaard
2bfded3c5f ux(): general ux polish 2016-01-15 14:42:59 +01:00
Torkel Ödegaard
842a59535d feat(sidenav): more polish to new sidenamv 2016-01-15 13:20:32 +01:00
Torkel Ödegaard
d4e1a715eb fix(datasources): many datasources did not work in optimized build due to missing ngInject comment 2016-01-15 12:51:55 +01:00
Torkel Ödegaard
954c0e9fae Merge branch 'master' into new-nav 2016-01-15 11:23:22 +01:00
Torkel Ödegaard
f6a3b53fb5 fix(firefox): fixed js issue that made master build break in firefox 2016-01-15 11:23:08 +01:00
bergquist
01d47fb280 fix(plugins): fix for default plugin dif 2016-01-15 11:22:41 +01:00
Torkel Ödegaard
dfcb82d233 feat(sidenav): more work on new side nav 2016-01-15 11:13:02 +01:00
bergquist
83346a29aa fix(plugins): scans default plugin path 2016-01-15 11:01:56 +01:00
Torkel Ödegaard
317c5ba88d Merge pull request #3747 from utkarshcmu/api-docs
Added Orgs API docs
2016-01-15 07:51:42 +01:00
utkarshcmu
caa26f594e Added Orgs API 2016-01-14 14:40:12 -08:00
Torkel Ödegaard
aa9a92d2e0 poc(new nav): added new menu button to other pages that dashboard 2016-01-14 22:30:39 +01:00
Torkel Ödegaard
4f227ae92e poc(new sidenav/topnaav) 2016-01-14 22:26:41 +01:00
Torkel Ödegaard
cd0256d40d poc(new nav): beginings.... 2016-01-14 21:20:56 +01:00
Torkel Ödegaard
2ccc19185c fix(text panel): fix for text panel in optimized builds, introduced in recent commit due to plugin api changes 2016-01-14 19:14:02 +01:00
Torkel Ödegaard
b4d595e561 feat(plugins): updated changelog with notice about plugin api changes 2016-01-14 19:01:13 +01:00
Torkel Ödegaard
88a132b878 Merge branch 'dynamic-directives' 2016-01-14 18:57:34 +01:00
Torkel Ödegaard
b5726a8d5a feat(plugins): completed upgrade of all built in panels 2016-01-14 18:57:02 +01:00
Torkel Ödegaard
b7f4a5c198 Merge pull request #3744 from utkarshcmu/meta-changelog
Updating CHANGELOG.md
2016-01-14 18:32:57 +01:00
Torkel Ödegaard
1d9ad9be33 feat(plugins): upgraded singlestat to new plugin format 2016-01-14 17:20:50 +01:00
Utkarsh Bhatnagar
2b7a26dabd Update CHANGELOG.md 2016-01-14 07:53:42 -08:00
Torkel Ödegaard
a233570777 feat(plugins): upgraded opentsdb and prometheus to new plugin module return format 2016-01-14 16:01:17 +01:00
Torkel Ödegaard
6fae264222 feat(plugins): upgraded influxdb to new plugin format 2016-01-14 15:35:14 +01:00
Torkel Ödegaard
8699d49f93 feat(plugins): updated cloudwatch to new plugin style 2016-01-14 15:15:45 +01:00
Torkel Ödegaard
c4ce3293a2 feat(plugins): now solved all cases of loading plugin directives, now just have to upgrade all panels and data sources 2016-01-14 14:37:04 +01:00
Torkel Ödegaard
dbafc8c9db feat(plugins): work on plugin directive loading 2016-01-14 13:21:05 +01:00
Torkel Ödegaard
6c6c3a5081 feat(plugins): more work on how plugins expose directives 2016-01-14 12:35:31 +01:00
Torkel Ödegaard
d420cb38d1 feat(plugins): work on plugin directives loading 2016-01-14 11:21:56 +01:00
Torkel Ödegaard
b55f8215ec feat(apps): work on plugin directives loading 2016-01-13 22:31:29 +01:00
Torkel Ödegaard
08caf4bbde feat(tslint): more tslint work 2016-01-13 21:22:39 +01:00
Torkel Ödegaard
59c928acc2 feat(tslint): added more tslint rules 2016-01-13 21:07:57 +01:00
Torkel Ödegaard
e38e8c740f Merge pull request #3723 from schen59/master-schen
fix mismatch api path introduced by commit to issue #3600
2016-01-13 19:51:56 +01:00
Shaofeng Chen
4ceab4abc7 fix mismatch api path 2016-01-13 10:44:31 -08:00
Torkel Ödegaard
8ff48c126a fix(merge): minor merge fix 2016-01-13 15:51:47 +01:00
Torkel Ödegaard
6da3af5e89 Merge branch 'new_macaron' 2016-01-13 15:48:49 +01:00
Torkel Ödegaard
77c362af8d fix(sidemenu): added missing login link 2016-01-13 15:48:12 +01:00
Torkel Ödegaard
2cf0dc2cb2 fix(gofmt): fixed non formated go file 2016-01-13 15:43:32 +01:00
Torkel Ödegaard
bdb67d4909 fix(build): fixed dependency and build issue 2016-01-13 15:38:54 +01:00
bergquist
4fe72ebf69 feat(macaron): upgrades macaron version 2016-01-13 15:11:23 +01:00
Torkel Ödegaard
49fdf8427a fix(png rendering): removed --ssl-protocol=any phantomjs param 2016-01-13 15:07:03 +01:00
Torkel Ödegaard
534bc83173 temp work on dynamic directives 2016-01-13 14:03:50 +01:00
Torkel Ödegaard
87f6d7da11 Merge branch 'master' of github.com:grafana/grafana 2016-01-13 13:57:37 +01:00
Torkel Ödegaard
cdd341af64 feat(packaging): added Restart=on-failure to systemd service spec file 2016-01-13 13:57:22 +01:00
Torkel Ödegaard
f70252f013 Merge pull request #3661 from mtanda/prometheus_fill_null
(prometheus) fill null for missing data point
2016-01-13 11:03:34 +01:00
Torkel Ödegaard
ed989ecc8d Merge branch 'master' of github.com:grafana/grafana 2016-01-13 10:40:58 +01:00
Torkel Ödegaard
a147015e96 fix(playlists): fixed url in playlist view when using sub url, fixes #3711 2016-01-13 10:36:00 +01:00
Carl Bergquist
8cf7fb7f80 Merge pull request #3712 from schen59/master-schen
add get org by name api (issue #3600)
2016-01-13 08:40:44 +01:00
Mitsuhiro Tanda
c317149a08 add test for prometheus fill null 2016-01-13 15:59:59 +09:00
Mitsuhiro Tanda
ff8b25a50a fix, should fill null at end timestamp 2016-01-13 15:59:59 +09:00
Mitsuhiro Tanda
afa539368f fill null in Prometheus 2016-01-13 15:59:59 +09:00
Shaofeng Chen
dc427d5a2c add get org by name api 2016-01-12 13:50:56 -08:00
Torkel Ödegaard
a87b5f757d fix(datasources): minor fix to data sources after apps branch merge 2016-01-12 20:05:40 +01:00
bergquist
4db57cc0bb docs(playlists): add persisted playlists to changelog 2016-01-12 17:08:13 +01:00
Torkel Ödegaard
44f0242157 fix(build): fixed issue after merge 2016-01-12 15:45:55 +01:00
Torkel Ödegaard
e5b3f27a30 Merge branch 'apps' 2016-01-12 15:41:15 +01:00
Torkel Ödegaard
a15984b663 feat(apps): pages work 2016-01-12 15:39:29 +01:00
Carl Bergquist
f7fecdc6de Merge pull request #3655 from grafana/playlist
Persistable playlists

closes #515
closes #1137
2016-01-12 15:20:43 +01:00
bergquist
cabefa4fff fix(playlist): fix for timespan -> interval 2016-01-12 14:38:14 +01:00
bergquist
1ec97e5199 feat(playlist): shortens urls 2016-01-12 14:36:04 +01:00
bergquist
458d15063d fix(playlist): remove invalid logging 2016-01-12 14:28:19 +01:00
bergquist
e8786b0747 feat(playlist): renames timespan to interval 2016-01-12 13:56:47 +01:00
bergquist
d0bcd1d87c feat(playlist): move playlistSrv to playlist folder 2016-01-12 13:44:23 +01:00
bergquist
c8bd9fd6cc style(playlist): renames variable 2016-01-12 13:42:27 +01:00
Torkel Ödegaard
4c59e48cc2 feat(apps): worked on apps edit view styles 2016-01-12 12:25:07 +01:00
bergquist
85a463faab fix(playlist): remove only parameter to describe 2016-01-12 12:01:27 +01:00
bergquist
feca2871eb tests(playlist): adds ctrl test for playlist edit 2016-01-12 11:57:16 +01:00
Torkel Ödegaard
144c703c7b Merge pull request #3703 from mtanda/cloudwatch_seoul
(cloudwatch) add seoul region
2016-01-12 10:51:34 +01:00
Torkel Ödegaard
ae6cae0771 Merge branch 'master' of github.com:grafana/grafana 2016-01-12 10:32:49 +01:00
Torkel Ödegaard
2b99b64ec5 fix(table panel): fixed issue with table panel in optimized builds, closes #3702 2016-01-12 10:32:19 +01:00
Torkel Ödegaard
ffe1407217 feat(apps): minor progress 2016-01-12 10:20:04 +01:00
Mitsuhiro Tanda
7d8519f5f0 add seoul region 2016-01-12 18:15:29 +09:00
bergquist
b79f04493d style(playlist): abstract DTO creation 2016-01-12 08:36:25 +01:00
bergquist
7e7d9457ea Merge branch 'playlist_relation_table' into playlist 2016-01-12 08:18:03 +01:00
bergquist
07fdf6491c fix(playlist): new url for viewing playlist 2016-01-12 08:17:44 +01:00
bergquist
fb4bb7f53e fix(playlist): remove start button from edit page 2016-01-12 08:17:44 +01:00
bergquist
1da1849de6 fix(playlist): fixes broken search filter 2016-01-12 08:17:44 +01:00
bergquist
98dccb8641 feat(playlist): refactor FE to support playlistitems 2016-01-12 08:17:44 +01:00
bergquist
8a38991270 feat(playlist): changes to relation table
Also introduces an abstraction between playlist and dashboard.
This will make it possible to att search, and tag filtering to
playlists without any major refactoring
2016-01-12 08:17:44 +01:00
Torkel Ödegaard
2fe58461d5 feat(apps): minor fix for images 2016-01-11 22:51:40 +01:00
Torkel Ödegaard
16cd27282f Merge pull request #3686 from keis/phantomjs-dependency
Add missing peer dependency: phantomjs
2016-01-11 18:46:10 +01:00
Torkel Ödegaard
e081a5c5a0 feat(apps): worked on pinning apps 2016-01-11 18:03:08 +01:00
Carl Bergquist
0ea01f24a8 Merge pull request #3690 from utkarshcmu/recorded3
Update playlist.md
2016-01-11 16:56:13 +01:00
Torkel Ödegaard
882980ada7 changelog: updated with info about #3635 2016-01-11 16:39:22 +01:00
Torkel Ödegaard
66f7a2be15 Merge branch 'snapshot_annotation' of https://github.com/mtanda/grafana into mtanda-snapshot_annotation 2016-01-11 16:35:45 +01:00
Torkel Ödegaard
908b2d151f Merge pull request #3681 from byronmwong/master
Fix elasticsearch hourly indexes
2016-01-11 16:29:46 +01:00
Mitsuhiro Tanda
d3bc52278d annotation snapshot fix 2016-01-11 19:26:48 +09:00
Mitsuhiro Tanda
012d1378d4 snapshot annotation 2016-01-11 19:26:48 +09:00
Torkel Ödegaard
4da31291d2 feat(apps): minor progress to apps list 2016-01-11 10:44:04 +01:00
Torkel Ödegaard
c1e94e61d0 feat(apps): lots of more work on apps, changed app_plugin to app_settings in order to to confuse the app plugin model (definition) and app org settings 2016-01-10 21:37:11 +01:00
Torkel Ödegaard
ab79348af5 feat(plugins): minor fix for external plugins with staticRoot 2016-01-09 23:56:39 +01:00
Torkel Ödegaard
d83e24572a feat(plugins): more refactoring 2016-01-09 23:52:13 +01:00
Torkel Ödegaard
1ffcea1952 feat(plugins): major improvement in plugins golang code 2016-01-09 23:34:20 +01:00
Torkel Ödegaard
35f40b7312 feat(plugins): upgraded opentsdb 2016-01-09 21:54:03 +01:00
Torkel Ödegaard
b76449d151 feat(plugins): upgraded influxdb to new data source plugin model 2016-01-09 21:42:26 +01:00
Torkel Ödegaard
15546dd84e feat(plugins): added better error message when trying to load data source plugin module that is missing datasource constructor 2016-01-09 19:14:59 +01:00
Torkel Ödegaard
ca3405afc5 feat(plugins): moved http settings to directive instad of just ng-include partial 2016-01-09 19:03:03 +01:00
Torkel Ödegaard
36ebfc747a feat(plugins): more upgrading work 2016-01-09 18:44:13 +01:00
Torkel Ödegaard
bc328cbed7 feat(plugins): upgraded Cloudwatch to new plugin schema 2016-01-09 18:36:25 +01:00
Torkel Ödegaard
7ae81a2195 feat(plugins): annotations view work again for elasticsearch 2016-01-09 18:20:43 +01:00
Torkel Ödegaard
cf98a16db0 feat(plugins): made data source custom edit view into a directive instead of html path config in plugin.json 2016-01-09 18:07:42 +01:00
Torkel Ödegaard
f813b4c58f feat(plugins): converted graphite plugin to new format 2016-01-09 13:30:02 +01:00
Torkel Ödegaard
c5635f9c89 feat(plugins): changed what datasources should return, they should now return the datasource constructor 2016-01-09 13:21:16 +01:00
Torkel Ödegaard
d932653c7f feat(apps): minor progress on apps edit view 2016-01-09 11:07:34 +01:00
Utkarsh Bhatnagar
39aca0f038 Update playlist.md 2016-01-08 23:52:51 -08:00
Torkel Ödegaard
9943b9a226 feat(plugin): more work on plugin schema 2016-01-09 08:12:27 +01:00
Torkel Ödegaard
3bb20dbf2e feat(plugins): changed plugin schema, pluginType -> type, type -> id 2016-01-08 23:15:44 +01:00
Torkel Ödegaard
7a8b3c419b feat(apps): lots of progress 2016-01-08 20:57:58 +01:00
Torkel Ödegaard
60e7c6d150 Merge branch 'master' into apps
Conflicts:
	public/app/partials/sidemenu.html
2016-01-08 18:10:53 +01:00
Torkel Ödegaard
a9aaa5ad73 Merge branch 'master' of github.com:grafana/grafana 2016-01-08 18:01:20 +01:00
Torkel Ödegaard
6c1fee736b feat(sidemenu): improved user dropdown and sidemenu, will be improved further, #3687 2016-01-08 17:58:46 +01:00
Torkel Ödegaard
f81d2595f9 Merge branch 'sidebar-consolidation' of github.com:nchristus/grafana into sidebar-consolidation 2016-01-08 16:29:10 +01:00
David Keijser
1896bd0920 Add missing peer dependency: phantomjs 2016-01-08 16:27:43 +01:00
Torkel Ödegaard
183f32390c Merge pull request #3683 from mtanda/cloudwatch_reuse_credentials
(cloudwatch) reuse credentials
2016-01-08 16:25:27 +01:00
bergquist
455948ad14 fix(playlist): fix broken build. unused vars 2016-01-08 16:24:35 +01:00
bergquist
0918063c55 fix(playlist): move dashboard uri cration to Backend 2016-01-08 16:13:49 +01:00
bergquist
22c001c8a6 fix(playlist): implement api according to new standard 2016-01-08 14:21:30 +01:00
bergquist
d15b0bf4c4 fix(playlist): move backend code to ctrl
data loading should be done in the ctrl
2016-01-08 13:57:00 +01:00
bergquist
01a910fedc style(playlists): use backendsrv direct
There is no point resolving the playlists in the routes file.
Loading playlists is what the controller is suppose to do
2016-01-08 13:33:24 +01:00
bergquist
8c05067f88 style(playlist): rename files to match new format 2016-01-08 13:25:30 +01:00
Torkel Ödegaard
f67563e9ee feat(apps): moving things around 2016-01-08 12:45:12 +01:00
bergquist
d0841919ea docs(plugins): fixes typo 2016-01-08 10:55:22 +01:00
bergquist
a23e60ab69 docs(plugins): adds plugin page 2016-01-08 10:53:39 +01:00
Carl Bergquist
ab30297d02 Merge pull request #3679 from volter/colored-bolt
Color the annotation bolt (#3590)

closes #3590
2016-01-08 10:51:29 +01:00
Torkel Ödegaard
3362d6bc56 Merge branch 'docs-2.6' 2016-01-08 10:25:20 +01:00
Torkel Ödegaard
e5f391ab53 docs: minor change to docs make file 2016-01-08 10:24:58 +01:00
Torkel Ödegaard
19a5e425cf docs: fixed building from source go dependency verison 2016-01-08 10:22:57 +01:00
Torkel Ödegaard
69d0e82453 Merge branch 'master' into apps
Conflicts:
	pkg/services/sqlstore/migrations/migrations.go
2016-01-08 10:20:46 +01:00
Mitsuhiro Tanda
f84737d7d4 (cloudwatch) reuse credentials 2016-01-08 18:13:36 +09:00
Nick Christus
0ee0ea554d sidebar-consolidation: added new org menu to sidebar 2016-01-07 22:49:14 -06:00
Byron
40845578c6 Fix elasticsearch hourly indexes 2016-01-07 14:39:20 -08:00
Volker Fröhlich
f4e22e49b6 Color the annotation bolt (#3590)
Makes it easier to distinguish between annotations while
editing and using them; Uses the icon color.
2016-01-07 22:28:03 +01:00
Torkel Ödegaard
8a2af9b818 Merge branch 'v2.6.x' 2016-01-07 22:00:21 +01:00
Torkel Ödegaard
255901ca7c fix(graph panel): fixed bug in typeahead when adding series style override, fixes #3554 2016-01-07 21:59:55 +01:00
Torkel Ödegaard
52644bb28a fix(timepicker): fixed recent breaking of datetime picker when swithing from requirejs to systemjs 2016-01-07 20:52:48 +01:00
bergquist
7cad3c89d3 Merge branch 'hcooper-hover-order' 2016-01-07 18:10:42 +01:00
bergquist
bcdddfe4e8 style(tooltip): removed comment and extrated sort 2016-01-07 18:09:51 +01:00
bergquist
c4ca1444f9 Merge branch 'hover-order' of https://github.com/hcooper/grafana into hcooper-hover-order 2016-01-07 17:43:04 +01:00
bergquist
f5565d4814 docs(changelog): add note about ssl support for mysql 2016-01-07 17:39:25 +01:00
bergquist
f20ee6b482 Merge branch 'improbable-io-ssl-for-mysql' 2016-01-07 17:09:14 +01:00
bergquist
6c8d084664 Merge branch 'ssl-for-mysql' of https://github.com/improbable-io/grafana into improbable-io-ssl-for-mysql 2016-01-07 17:08:31 +01:00
Carl Bergquist
412e7bcdae Merge pull request #3664 from utkarshcmu/recorded
Improvized dashboard sorting UI
2016-01-07 10:19:13 +01:00
Carl Bergquist
3b65fc0107 Merge pull request #3665 from utkarshcmu/recorded2
Better heading
2016-01-07 10:14:40 +01:00
bergquist
5792a16222 fix(plugins): removes warnings for missing folder
Remove warnings when scanning for plugins in the default
catalog data/plugins

closes #3663
2016-01-07 08:51:31 +01:00
utkarshcmu
6a9f451091 Better heading 2016-01-06 22:50:25 -08:00
utkarshcmu
a559d59d80 Improvized dashboard sorting 2016-01-06 22:13:22 -08:00
Carl Bergquist
de20a8930e Merge pull request #3649 from nikita-graf/playlist-sort
Playlist dashboards sort
2016-01-06 13:38:50 +01:00
bergquist
9343b0378d feat(plugins): adds warn log for scanning folders
symlinks outside to plugin folder can cause problems.
This commit makes sure to warn about it in the logs
2016-01-06 11:57:17 +01:00
nikita-graf
3fabd2ea1b basic playlist dashboards sort support 2016-01-06 02:05:23 +03:00
bergquist
5de69b288f feat(singlestat): make sparkline height dynamic
closes #3553
2016-01-05 19:21:12 +01:00
Carl Bergquist
5eea02b17a Merge pull request #3634 from nikita-graf/dashboard-remove-playlist-sync
Playlist improvements
2016-01-05 10:07:48 +01:00
Carl Bergquist
5c0812ab6f Merge pull request #3636 from henridf/docs-es-filter-in-template
Docs: add example with filter in ES template
2016-01-05 08:58:26 +01:00
Henri DF
5af3fe93f2 Docs: add example with filter in ES template 2016-01-04 21:48:47 -08:00
nikita-graf
ee400df930 remove dashboard from playlist when its destroyed 2016-01-05 04:14:39 +03:00
Carl Bergquist
09b8401324 Merge pull request #3624 from mtanda/prometheus_link_fix
(prometheus) fix Prometheus link
2016-01-04 17:43:55 +01:00
bergquist
be1fb13162 feat(playlist): minor ux changes for playlists 2016-01-04 15:11:05 +01:00
bergquist
aa83dc15e2 feat(playlist): add search result count 2016-01-04 14:23:24 +01:00
bergquist
7c482064df feat(playlist): improve header 2016-01-04 10:16:00 +01:00
bergquist
c93a3ce227 feat(playlist): make default timespan placeholder 2016-01-04 09:17:47 +01:00
Carl Bergquist
03c10ef885 Merge pull request #3626 from aqnouch/patch-1
Updated copyright to 2016
2016-01-04 07:54:22 +01:00
AQNOUCH Mohammed
cc1ed98fc4 Updated copyright to 2016 2016-01-01 01:30:43 +00:00
Mitsuhiro Tanda
ebf0bd5fc9 fix end time of Prometheus link 2015-12-31 16:05:04 +09:00
Mitsuhiro Tanda
be48caf59f fix Prometheus link, expand template variable in expression 2015-12-31 16:05:04 +09:00
Qtax
c0cf0cb802 Added an option to set a min-width for the graphs side table/area. 2015-12-29 14:42:52 +01:00
Carl Bergquist
3d60d0dfa5 Merge pull request #3613 from utkarshcmu/recorded
Made Playlist UI user friendly
2015-12-29 11:33:19 +01:00
utkarshcmu
b68df56b03 Made Playlist UI user friendly 2015-12-28 04:24:38 -08:00
Carl Bergquist
6fbba13ab3 Merge pull request #3611 from utkarshcmu/recorded
Playlist enhancements
2015-12-28 10:40:52 +01:00
Carl Bergquist
311624beaa Merge pull request #3598 from eddawley/ISSUE-2818
Fixes #2818.  Adds support for mysql backends via unix sockets
2015-12-28 10:33:49 +01:00
utkarshcmu
ca5099f53b Fixed gofmt tests 2015-12-24 02:25:49 -08:00
utkarshcmu
5877e5e11a Merged with master, resolved conflicts 2015-12-24 02:24:59 -08:00
Torkel Ödegaard
69eb62c09f Merge pull request #3597 from eddawley/ISSUE-3461
Issue 3461: Session table is now created automatically
2015-12-24 09:59:34 +01:00
Ed Dawley
ec36e28368 Small typo in comment 2015-12-23 15:15:59 -06:00
Ed Dawley
4da56b65ab Fixes #2818. Adds support for mysql backends via unix sockets 2015-12-23 15:06:28 -06:00
utkarshcmu
71febeb71f Playlist can be run without saving too 2015-12-23 02:38:27 -08:00
utkarshcmu
a292aedd9c Made playlist URL clickable 2015-12-23 02:15:28 -08:00
utkarshcmu
b58e605b99 Added play button 2015-12-23 02:02:48 -08:00
utkarshcmu
7776803890 Removed unused components 2015-12-23 01:46:23 -08:00
Ed Dawley
cd23ab9955 Issue 3461: Session table is now created automatically 2015-12-23 01:33:46 -06:00
Torkel Ödegaard
aa32459bc2 feat(apps): mini update to apps config view 2015-12-22 17:00:21 +01:00
Torkel Ödegaard
41a0995db7 feat(apps): minor progress on app meta data 2015-12-22 16:32:17 +01:00
Daniel Low
3f9f0679ec gofmt 2015-12-22 13:10:34 +00:00
Torkel Ödegaard
d1145ed3fb Merge branch 'master' into apps 2015-12-22 13:59:25 +01:00
Torkel Ödegaard
f074c1eaff refactor(lodash): changed how lodash is referenced from typescript 2015-12-22 13:59:11 +01:00
Daniel Low
ea566fff24 Add TLS for mysql
Use ssl_mode for mysql and add docs
add docs for the new parameters in config

Tolerate ssl_mode without client authentication

Client cert is not necessary for a SSL connection. So we tolerate
failure if client cert is not provided.
Improve error message if missing server_cert_name and mode is not
skip-verify.
2015-12-22 12:42:52 +00:00
Torkel Ödegaard
b8cb5e0367 feat(apps): WIP progress app views 2015-12-22 13:42:48 +01:00
Torkel Ödegaard
7a87c900ee Merge branch 'master' into apps 2015-12-22 12:41:52 +01:00
Torkel Ödegaard
e95170e9fd tech(angularjs): upgrade to angularjs 1.5 2015-12-22 12:24:36 +01:00
Torkel Ödegaard
d0dead0a08 feat(apps): rewrote appsCtrl to app_list_ctrl and to typescript 2015-12-22 12:13:55 +01:00
Torkel Ödegaard
71d718a6e2 fix(systemjs): systemjs config fix for plugins 2015-12-22 11:46:41 +01:00
Torkel Ödegaard
ad94f99d57 refactor(apps): more WIP work on apps 2015-12-22 11:37:44 +01:00
utkarshcmu
bcaaedf2ff Resurrected nikita-graf's work and added playlistType for future use 2015-12-22 02:07:15 -08:00
Carl Bergquist
3dc3d363fd Merge pull request #3581 from bergquist/zoomout_on_doubleclick
Zoom out on double click in graphs
2015-12-22 10:04:28 +01:00
bergquist
690a6e1a59 feat(graphs): zoom out on double click 2015-12-22 09:56:24 +01:00
Torkel Ödegaard
eacc46da6d feat(plugins): WIP on new apps concept 2015-12-21 23:09:27 +01:00
woodsaj
0903d5541b Merge branch 'master' of github.com:grafana/grafana into externalPlugin
Conflicts:
	pkg/api/api.go
	pkg/api/api_plugin.go
	pkg/api/datasources.go
	pkg/api/frontendsettings.go
	pkg/api/index.go
	pkg/plugins/models.go
	pkg/plugins/plugins.go
2015-12-22 00:23:24 +08:00
Torkel Ödegaard
c19a2e5b45 fix(influxdb): systemjs fix 2015-12-21 16:48:12 +01:00
Torkel Ödegaard
10a764c4f2 fix(less): minor less fix 2015-12-21 16:42:28 +01:00
Torkel Ödegaard
0a9f705308 tech(systemjs): more fixes for optmized build 2015-12-21 16:34:18 +01:00
Torkel Ödegaard
dabd680d6b tech(systemjs): merged sync with master, all tests are passing 2015-12-21 16:13:24 +01:00
Torkel Ödegaard
4522b02925 tech(systemjs): almost all tests are passing 2015-12-21 16:00:58 +01:00
Carl Bergquist
fabaf5cc04 Merge pull request #3575 from piotr1212/no_username_in_render_logging
Fix empty username in http log for /render calls
2015-12-21 13:31:10 +01:00
Torkel Ödegaard
f7888886e9 tech(systemjs): working on getting tests to work 2015-12-21 11:10:16 +01:00
Torkel Ödegaard
dfd5413b10 tech(systemjs): worked on making optimized builds work with systemjs builder 2015-12-21 10:02:39 +01:00
carl bergquist
1b341f8000 fix(dashboard_settings): update css for last row 2015-12-20 21:13:44 +01:00
Carl Bergquist
af9b864b83 Merge pull request #3446 from utkarshcmu/new-columns
Displaying Last UpdatedBy as Metadata
2015-12-20 15:11:20 -05:00
Torkel Ödegaard
93e424de4c tech(systemjs): work on systemjs builder 2015-12-18 15:59:27 +01:00
woodsaj
e7a0ab76c3 change plugin to app in breadcrumb 2015-12-18 22:09:33 +08:00
utkarshcmu
d8b90721b3 Able to display login Id of the user in Last Updated By 2015-12-18 03:38:49 -08:00
utkarshcmu
cb5c1bd24d Removed created_by and fixed gofmt 2015-12-18 02:30:20 -08:00
utkarshcmu
af371249f9 Successfully displayed userdId in UI 2015-12-18 01:52:05 -08:00
Torkel Ödegaard
0dd7fb7361 tech(systemjs): most things work 2015-12-18 10:28:00 +01:00
utkarshcmu
22fd2aed02 Removed columns from snapshot table 2015-12-18 00:30:44 -08:00
utkarshcmu
c433167950 Merged with master, resolved conflicts 2015-12-18 00:23:08 -08:00
utkarshcmu
e0ffcda32e Added UI , DB settings 2015-12-18 00:20:23 -08:00
Torkel Ödegaard
d34ba416a6 tech(systemjs): more stuff is starting to work 2015-12-18 08:22:05 +01:00
woodsaj
3d15ee6d74 allow app menu items to be selectivly pinned to the left nav menu 2015-12-18 15:10:52 +08:00
woodsaj
48cf56b69a more renaming. also moved apps and datasource menus 2015-12-18 13:46:40 +08:00
Torkel Ödegaard
406ee43ae5 Merge pull request #3556 from xiaoping378/master
fixes #3555, path of table panel option error
2015-12-18 06:28:37 +01:00
xiaoping378
488165ec73 fixes #3555, path of table panel option error 2015-12-18 12:35:02 +08:00
Torkel Ödegaard
545c39356a tech(systemjs): starting work on systemjs bundling 2015-12-17 19:18:30 +01:00
woodsaj
42db1378e0 rename app config directive to grafana-app-* 2015-12-17 23:59:01 +08:00
woodsaj
c35b51a268 refactor.
Rename externalPlugin to apiPlugin
Rename bundle to app
Move js, css, menuItem and staticRoot to be properties os App
Add "app" field to panel, datasource and api plugin models. If populated
then the plugin is only enabled if the specific app is enabled for the Org.
If app is "", then the plugin is enabled for all orgs and can't be disabled.
2015-12-17 23:53:58 +08:00
Torkel Ödegaard
df1e52e394 tech(systemjs): more stuff is starting to work 2015-12-17 16:30:53 +01:00
carl bergquist
246b04f904 docs(sessions): add memcache support to changelog 2015-12-17 15:59:25 +01:00
Carl Bergquist
333f9101a0 Merge pull request #3458 from improbable-io/use-memcache-for-session
Add memcache as session provider
2015-12-17 15:56:15 +01:00
carl bergquist
24acea7261 refactoring(top_nav): move menu condition to controller 2015-12-17 14:41:10 +01:00
Carl Bergquist
08ca72399b Merge pull request #3051 from utkarshcmu/viewer
Removed export/view permission from a dashboard viewer
2015-12-17 14:40:42 +01:00
Piotr Popieluch
e29e3416db router logger did not show username in /render calls because cookies are
cleared in these call. Not just get username before the call is
executed. see #3405 for more info.
2015-12-17 14:28:11 +01:00
Torkel Ödegaard
83ce40191c tech(systemjs): ok, moving forward 2015-12-17 14:27:34 +01:00
Torkel Ödegaard
7c06b5cc22 tech(systemjs): minor change 2015-12-17 13:18:32 +01:00
Torkel Ödegaard
3b8e478a6a tech(systemjs): finally starting to get systemjs and typescript and runtime loading to work together in a manner that I want it to.. took forever 2015-12-17 11:46:10 +01:00
utkarshcmu
9498c78576 Merged with master, resolved conflicts 2015-12-17 01:46:34 -08:00
utkarshcmu
746e203f7b Admin can toggle editable checkbox 2015-12-17 01:44:05 -08:00
Torkel Ödegaard
a7d7f31e76 Merge branch 'master' of github.com:grafana/grafana 2015-12-17 10:13:40 +01:00
Torkel Ödegaard
16847fdb41 feat(elasticsearch): trim edges, minor refactoring of #3541 2015-12-17 10:13:23 +01:00
carl bergquist
28e7f0f74f Merge branch 'felixbarny-global_interval' 2015-12-17 10:01:40 +01:00
carl bergquist
80d757b371 feat(elasticsearch): move default query parameters to new table 2015-12-17 10:00:53 +01:00
carl bergquist
5bdf0cd136 Merge branch 'global_interval' of https://github.com/felixbarny/grafana into felixbarny-global_interval
Conflicts:
	public/app/plugins/datasource/elasticsearch/partials/config.html
2015-12-17 09:53:02 +01:00
carl bergquist
e498503428 fix(elastic): fixed typo 2015-12-17 09:05:01 +01:00
carl bergquist
26f70a5fd7 fix(settings): make headline more informative 2015-12-17 09:04:05 +01:00
Carl Bergquist
ef46b23250 Merge pull request #3133 from tdyas/add_pencil_to_graphite_ds
add pencil icon back to graphite data source
2015-12-17 08:48:03 +01:00
carl bergquist
39ccf1526f Merge branch 'addshore-graphiteSortByNameNatural' 2015-12-17 07:21:43 +01:00
carl bergquist
12889a9509 feat(graphite): make sortByName optional
fixes #3360
closes #3361
2015-12-17 07:17:39 +01:00
Torkel Ödegaard
c24935b519 minor progress 2015-12-16 17:01:34 +01:00
carl bergquist
3693473f40 Merge branch 'utkarshcmu-relative' 2015-12-16 16:34:56 +01:00
carl bergquist
2cb83cf19d style(graph.tooltip): moves checkdate logic inside each method.
I find it easier to follow and checkdate didnt do much.
2015-12-16 16:32:55 +01:00
carl bergquist
8c02a7bd6b Merge branch 'relative' of https://github.com/utkarshcmu/grafana into utkarshcmu-relative 2015-12-16 16:09:44 +01:00
Carl Bergquist
8ee0e5d11f Merge pull request #3307 from dennisdegreef/addCubicMeters
Add cubic meters to units
2015-12-16 16:04:20 +01:00
Carl Bergquist
c87b425639 Merge pull request #3542 from grafana/revert-3445-cloudwatch_sum_period
Revert "(cloudwatch) add "Divide Sum By Period" option"
2015-12-16 14:36:43 +01:00
Carl Bergquist
e320bd025f Revert "(cloudwatch) add "Divide Sum By Period" option" 2015-12-16 14:35:04 +01:00
Carl Bergquist
d465c445fc Merge pull request #3445 from mtanda/cloudwatch_sum_period
(cloudwatch) add "Divide Sum By Period" option
2015-12-16 14:07:52 +01:00
carl bergquist
dc30b9d37b feat(elastic): change concept to trim edges instead. 2015-12-16 13:50:56 +01:00
carl bergquist
37cfe2a3cb feat(elastic): shorten expression to target input 2015-12-16 13:29:54 +01:00
carl bergquist
26abce647d feat(elastic): isolate drop first and last logic 2015-12-16 13:27:35 +01:00
Torkel Ödegaard
ca84ef38f8 angular2 test 2015-12-16 12:21:13 +01:00
utkarshcmu
78fe588330 Removed NewAddColumnMigration via 3473 2015-12-16 02:46:20 -08:00
Torkel Ödegaard
ddf72fa53f Merge pull request #3535 from utkarshcmu/typos
Fixed typos
2015-12-16 11:41:29 +01:00
utkarshcmu
3a6e8a535c Fixed typos 2015-12-16 02:30:53 -08:00
carl bergquist
d882af9f94 Merge branch 'es_drop_first_last' of https://github.com/Qtax/grafana into Qtax-es_drop_first_last 2015-12-16 09:48:14 +01:00
carl bergquist
48539c851e feat(graphite): adds support for grep function
closes #1163
2015-12-16 09:45:28 +01:00
carl bergquist
a701bba839 Merge branch 'jmaitrehenry-feature/symlinks' 2015-12-16 09:24:37 +01:00
Mitsuhiro Tanda
c7ba60162b (cloudwatch) add Divide By Sum option 2015-12-16 17:23:13 +09:00
carl bergquist
d4e98cd9bc Merge branch 'feature/symlinks' of https://github.com/jmaitrehenry/grafana into jmaitrehenry-feature/symlinks
Conflicts:
	pkg/plugins/plugins.go

closes #2899
closes #2834
2015-12-16 09:21:52 +01:00
Torkel Ödegaard
05ec24e7b8 Merge pull request #3531 from mtanda/cloudwatch_fix_annotation
(cloudwatch) fix query editor
2015-12-16 09:08:30 +01:00
Mitsuhiro Tanda
e44ef7f823 fix cloudwatch query editor 2015-12-16 17:01:58 +09:00
Torkel Ödegaard
04ff97cd72 tech(systemjs): tricky mixing systemjs and requirejs, might need to migrate 2015-12-15 20:23:55 +01:00
Torkel Ödegaard
8e6fdf62fb tech(systemjs): things are starting to work 2015-12-15 19:27:04 +01:00
Torkel Ödegaard
74d7a946a7 tech(systemjs): work on moving to systemjs 2015-12-15 19:10:08 +01:00
Carl Bergquist
2b58b6b5d7 Merge pull request #3304 from utkarshcmu/info
Added metadata info panel
2015-12-15 18:02:29 +01:00
Torkel Ödegaard
7ee290cc57 tech(systemjs): systemjs and jspm work 2015-12-15 17:56:16 +01:00
carl bergquist
3868a796a4 Merge branch 'stesie-fix-formatter-stack-percentage' 2015-12-15 17:35:05 +01:00
carl bergquist
b99ea80b58 test(graph): validates that percentage is shown when using stack and percentage
fixes #2379
2015-12-15 17:34:37 +01:00
Stefan Siegl
ce2ae31950 Use percent-formatter for stack+percentage graph 2015-12-15 17:32:52 +01:00
carl bergquist
f355f36d09 rename(phantomjs): improve variable naming 2015-12-15 14:23:37 +01:00
Carl Bergquist
5aa11b4578 Merge pull request #3400 from counsyl/wait-for-dashboard-render
Wait for all panels to render in PhantomJS
2015-12-15 14:22:18 +01:00
carl bergquist
c48da9b5cf fix(tests): fix broken unittest due to merge conflict 2015-12-15 14:03:15 +01:00
carl bergquist
12d65bfdfa Merge branch 'xaka-patch-2' 2015-12-15 13:59:35 +01:00
Pavel Strashkin
cba471b09b ui(dashboard): delete empty rows without confirm 2015-12-15 13:58:38 +01:00
Torkel Ödegaard
f1b897b3de change(cloudwatch): minor change to editor 2015-12-15 13:57:20 +01:00
Torkel Ödegaard
0589134006 Merge branch 'master' of github.com:grafana/grafana 2015-12-15 13:53:15 +01:00
Torkel Ödegaard
6ed36e01ac fix(unit tests): moved kairosdb spec to it's plugin repo 2015-12-15 13:52:14 +01:00
Carl Bergquist
25d93d1041 Merge pull request #3066 from mtanda/cloudwatch_annotation
(cloudwatch) annotation support
2015-12-15 13:43:02 +01:00
Torkel Ödegaard
e28c9b3309 cleanup(KairosDB): removed kairosdb from main repo, can easily be installed via as plugin via its own plugin repo, https://github.com/grafana/datasource-plugin-kairosdb, closes #3524 2015-12-15 11:35:39 +01:00
Torkel Ödegaard
5335a6b636 Merge branch 'master' of github.com:grafana/grafana 2015-12-15 11:21:17 +01:00
Torkel Ödegaard
f83d5f4280 cleanup(influxdb_08): removed influxdb 0.8 data source as an built in official data source, moved it to an external plugin repo, https://github.com/grafana/datasource-plugin-influxdb-08, closes #3523 2015-12-15 11:21:00 +01:00
carl bergquist
28ec6b4d60 feat(graphite): add optional parameter for perSecond
closes #966
2015-12-15 11:10:13 +01:00
Torkel Ödegaard
27a0ef7ee8 Merge branch 'master' of github.com:grafana/grafana 2015-12-15 10:29:07 +01:00
Torkel Ödegaard
5eab5dc47b feat(plugins): removed external plugins and bundle code, not ready for master yet, will revert this commit in seperate branch 2015-12-15 10:28:52 +01:00
Torkel Ödegaard
2ec5bc77d7 Merge branch 'external-plugins' 2015-12-15 10:10:48 +01:00
carl bergquist
2f3587ee8a fix(jshint): fix jshint error ._. 2015-12-15 09:06:11 +01:00
carl bergquist
9ece45caa5 feat(top_nav): option to make dashboards editable again
closes #2587
closes #2554
2015-12-15 08:43:03 +01:00
Torkel Ödegaard
f163ceffd0 fix(elasticsearch): fixes spelling of lucene, #3519 2015-12-15 08:29:24 +01:00
Mitsuhiro Tanda
31de9faaf2 fix test 2015-12-15 11:32:24 +09:00
Mitsuhiro Tanda
d302c82c82 share cloudwatch query editor 2015-12-15 11:32:23 +09:00
Mitsuhiro Tanda
6fa5e681aa fix EC2RoleProvider parameter 2015-12-15 11:25:20 +09:00
Mitsuhiro Tanda
e631940d9e pkg/api/cloudwatch: fix api client construction against aws-sdk-go v0.10.2 2015-12-15 11:25:19 +09:00
Mitsuhiro Tanda
e22e20fa9d fix cloudwatch annotation, reflect API change 2015-12-15 11:25:18 +09:00
Mitsuhiro Tanda
79c8556927 style change annotation editor 2015-12-15 11:25:18 +09:00
Mitsuhiro Tanda
7d16307db4 parse string date format 2015-12-15 11:25:17 +09:00
Mitsuhiro Tanda
1626982a3a add CloudWatch Annotation 2015-12-15 11:25:16 +09:00
Mitsuhiro Tanda
6beb9be42c add CloudWatch Alarm API support 2015-12-15 11:25:15 +09:00
Qtax
bf41eb824d Added ES histogram setting to drop/ignore the first and last datapoints 2015-12-14 19:58:08 +01:00
Torkel Ödegaard
38f4cfb7a2 Merge branch 'v2.6.x' 2015-12-14 18:51:09 +01:00
Torkel Ödegaard
aca9d3965d feat(elasticsearch): added unit option to derivative metric, closes #3512 2015-12-14 18:49:53 +01:00
Torkel Ödegaard
4cc06ad779 Merge branch 'master' of github.com:grafana/grafana 2015-12-14 18:33:58 +01:00
Torkel Ödegaard
79d56f779d fix(graphite): minor fix to graphite query editor so it does not issue render requests for incomplete queries, fixes #3510 2015-12-14 18:33:44 +01:00
Carl Bergquist
280f9befae Merge pull request #2949 from shoonoise/master
Add option to hide raintank share button

Fixes #2727
2015-12-14 17:29:09 +01:00
Torkel Ödegaard
201f50b121 Merge branch 'master' into external-plugins
Conflicts:
	pkg/api/login.go
	public/app/core/routes/all.js
	public/app/core/table_model.ts
	public/app/panels/table/table_model.ts
	public/app/plugins/panels/table/editor.ts
	public/app/plugins/panels/table/table_model.ts
2015-12-14 17:28:57 +01:00
carl bergquist
1cfa523f49 style(sidemenu): rename signup method to signout 2015-12-14 17:19:26 +01:00
Carl Bergquist
548ee47aa7 Merge pull request #3122 from shoonoise/hide_signout
Disable sign out button in case of auth proxy enabled
2015-12-14 17:18:04 +01:00
Torkel Ödegaard
55448de92a updated master version to 3.0.0-pre1 2015-12-14 17:10:30 +01:00
Torkel Ödegaard
b63471ebe9 fix(windows): exclude syslog feature from windows builds 2015-12-14 16:16:36 +01:00
Torkel Ödegaard
33395d530d docs(): updated downloads for 2.6 and whats new in 2.6 article 2015-12-14 15:45:00 +01:00
Torkel Ödegaard
fcd3af30ec updated version to 2.6.0 2015-12-14 15:18:01 +01:00
Torkel Ödegaard
e334107c7d docs(): added whats new in 2.6 article 2015-12-14 15:15:56 +01:00
carl bergquist
f5eb54e595 feat(elasticsearch): only show pipeline agg for es version >= 2 2015-12-14 15:08:34 +01:00
Torkel Ödegaard
56c3dd3652 docs(influxdb): updated influxdb docs 2015-12-14 14:16:22 +01:00
Torkel Ödegaard
6ddd458402 docs(elasticsearch): updated elasticsearch with info about templating and pipeline metrics 2015-12-14 13:55:16 +01:00
Torkel Ödegaard
ee328667d0 docs(table): updated table docs 2015-12-14 13:40:06 +01:00
carl bergquist
bc2bc1f2ac Merge branch 'graphiteSortByNameNatural' of https://github.com/addshore/grafana into addshore-graphiteSortByNameNatural 2015-12-14 10:37:44 +01:00
Torkel Ödegaard
3dee75603c Merge pull request #3502 from mattttt/table-panel-doc
New table panel doc
2015-12-14 10:22:49 +01:00
Torkel Ödegaard
c7e3ed096f fix(postgres): fixes db migration issue with_credentials column for postgres, fixes #3505 2015-12-14 10:19:53 +01:00
Matt Toback
62fe5cdbaa New table panel doc 2015-12-11 14:20:21 -05:00
Torkel Ödegaard
10f66fa78f feat(elasticsearch): adds support for inline script and missing options to all elasticsearch metrics, closes #3500 2015-12-11 18:20:53 +01:00
Torkel Ödegaard
0cbc493113 Merge pull request #3499 from discordianfish/clarify-template-auto-interval-tooltip
Clarify template option auto interval in tooltip
2015-12-11 16:50:30 +01:00
Johannes 'fish' Ziemke
c30c9fbca9 Clarify template option auto interval in tooltip 2015-12-11 16:47:05 +01:00
carl bergquist
f4fd3f48f0 feat(changelog): adds info about merge PR 2015-12-11 16:26:11 +01:00
Carl Bergquist
4ee9e48e7c Merge pull request #3405 from piotr1212/master
Add more info in route logging
2015-12-11 16:23:59 +01:00
Carl Bergquist
55fab0493d Merge pull request #3393 from pepl/master
Fixed spelling error
2015-12-11 16:12:19 +01:00
carl bergquist
22c4e605cf Merge remote-tracking branch 'upstream/master' 2015-12-11 15:25:34 +01:00
carl bergquist
67737b1556 feat(changelog): add info about merge PR to changelog 2015-12-11 15:24:22 +01:00
carl bergquist
cdfd3449ed Merge branch 'tmonk42-ldap_login_hints' 2015-12-11 15:18:29 +01:00
carl bergquist
fab1062c0b Merge branch 'ldap_login_hints' of https://github.com/tmonk42/grafana into tmonk42-ldap_login_hints
Conflicts:
	conf/defaults.ini
	pkg/setting/setting.go

closes #2571
closes #2494
2015-12-11 15:16:57 +01:00
Torkel Ödegaard
766b9d5270 Merge branch 'master' of github.com:grafana/grafana 2015-12-11 14:40:18 +01:00
Torkel Ödegaard
023fa2b2cc fix(influxdb): minor fix to new editor, there were 5min as a selectable option in derivative function 2015-12-11 14:39:59 +01:00
carl bergquist
8910351f5c fix(changelog): add info about merged PR's 2015-12-11 14:38:50 +01:00
Torkel Ödegaard
1b42e3015e fix(timepicker): mini change, removed unneeded space 2015-12-11 14:34:56 +01:00
Torkel Ödegaard
4e9e18d4c0 Merge pull request #3498 from bergquist/always_show_refresh_button
feat(timepicker): always show refresh button
2015-12-11 14:33:50 +01:00
carl bergquist
ba5b127684 feat(timepicker): always show refresh button
closes #1628
closes #1208
2015-12-11 14:26:38 +01:00
Carl Bergquist
225e7a6a32 Merge pull request #3161 from mischief/syslog
syslog support closes #3160
2015-12-11 14:03:21 +01:00
Torkel Ödegaard
7e9963ae05 fix(elasticsearch): minor markup fix 2015-12-11 12:51:39 +01:00
Torkel Ödegaard
b7c0f3ea95 Merge branch 'master' of github.com:grafana/grafana 2015-12-11 12:45:01 +01:00
Torkel Ödegaard
a8e2610d7d updated changelog 2015-12-11 12:44:47 +01:00
Torkel Ödegaard
b934ace1fc Merge branch 'moving_avg_es_support' 2015-12-11 12:43:02 +01:00
Torkel Ödegaard
82cbfc9905 feat(elasticsearch): added pipeline aggregations feature to changelog 2015-12-11 12:42:55 +01:00
Torkel Ödegaard
9f294e3565 feat(elasticsearch): completed initial implementation of moving average and derivative pipleline aggregations, closes #3451 2015-12-11 12:41:40 +01:00
Torkel Ödegaard
68775182f0 Merge pull request #3494 from mtanda/cloudwatch_cleanup
remove aws-sdk-js require setting
2015-12-11 12:28:26 +01:00
Mitsuhiro Tanda
dc3e172eb4 remove aws-sdk-js require setting 2015-12-11 20:27:24 +09:00
Torkel Ödegaard
5bd128ba85 Merge pull request #3493 from bergquist/table_panel_color_invert_order
Table Panel: adds invert color order functionality
2015-12-11 12:05:35 +01:00
carl bergquist
1a8579cd6d feat(table_panel): adds invert color order functionality 2015-12-11 12:01:04 +01:00
Torkel Ödegaard
5921bb0589 Merge pull request #3490 from mtanda/cloudwatch_metric_update
(cloudwatch) update suggest metrics and dimensions
2015-12-11 11:09:45 +01:00
Mitsuhiro Tanda
c8e894e8f8 sort metrics and dimensions 2015-12-11 17:56:35 +09:00
carl bergquist
141f22bedf feat(elasticsearch): display more info in options 2015-12-11 09:44:37 +01:00
Mitsuhiro Tanda
d9844350fe update supported metrics and dimensions 2015-12-11 17:42:40 +09:00
Mitsuhiro Tanda
2d9d11a89c reorder supported metrics and dimensions 2015-12-11 17:19:56 +09:00
carl bergquist
4fa92198a0 feat(elasticsearch): add support for model setting 2015-12-11 09:19:05 +01:00
carl bergquist
662430d5db feat(elasticsearch): adds last class for derivatives 2015-12-11 09:14:40 +01:00
carl bergquist
139b19f9ac feat(elasticsearch): make series naming generic for pipeline aggs 2015-12-10 17:42:31 +01:00
carl bergquist
6e50e2412e feat(elasticsearch): remove pipeline aggs as possible sources 2015-12-10 17:18:22 +01:00
carl bergquist
005e14a060 refactor(elasticsearch): mavg naming -> pipeline agg 2015-12-10 17:12:52 +01:00
carl bergquist
c8c9e0a7e7 feat(elasticsearch): improve pipeline aggs structure 2015-12-10 17:05:23 +01:00
carl bergquist
0f65cb2b79 feat(elasticsearch): update pipeline aggs if type change
make it possible to switch between different pipeline
aggregates without causing problms in the ui
2015-12-10 17:01:29 +01:00
Carl Bergquist
85094fc74d feat(elasticsearch): add pipeline settings 2015-12-10 13:34:49 +01:00
Torkel Ödegaard
5227dc679d fix(invite): removed resend invite button, button logic was not implemented, fixes #3484 2015-12-10 13:31:24 +01:00
Torkel Ödegaard
77c510c364 fix(graph legend): fixed issue with escaping html text in graph legend, and in function param, fixes #3482 2015-12-10 13:27:57 +01:00
Carl Bergquist
2d2ad8b237 show pipeline agg source for derivative 2015-12-10 13:06:46 +01:00
Torkel Ödegaard
6ea00a4f7c fix(timpicker): another name change to make quick ranges nameing more consistent, fixes #3465 2015-12-10 13:01:41 +01:00
Torkel Ödegaard
1bb0530c69 feat(elasticsearch): metric options alignement 2015-12-10 12:15:11 +01:00
Torkel Ödegaard
b36f644628 feat(elasticsearch): added pipleline aggregation derivative 2015-12-10 11:46:19 +01:00
Torkel Ödegaard
2dee9c8d74 Merge branch 'moving_avg_es_support' of https://github.com/bergquist/grafana into bergquist-moving_avg_es_support 2015-12-10 11:19:39 +01:00
Carl Bergquist
9c6eb7736f move pipeline options outside main switch 2015-12-10 11:17:14 +01:00
Carl Bergquist
e86dfcf55c rename mavgoptions to more generic pipelineaggs 2015-12-10 10:43:00 +01:00
Torkel Ödegaard
d6311aefb7 Merge branch 'moving_avg_es_support' of https://github.com/bergquist/grafana into bergquist-moving_avg_es_support 2015-12-09 16:46:29 +01:00
carl bergquist
8e18f2c5d2 refactor es pipeline aggregation variables to match ES 2015-12-09 16:25:05 +01:00
carl bergquist
0644bfe27c improves timeseries naming for moving average series 2015-12-09 14:58:26 +01:00
carl bergquist
0b285845d1 adds spec for query builder 2015-12-09 14:21:48 +01:00
carl bergquist
d3ff4bf75e changes to using an array for mavg options 2015-12-09 13:55:06 +01:00
Torkel Ödegaard
aa4ac9fa05 fix(timerange): fixed broken unit tests 2015-12-09 13:38:53 +01:00
Torkel Ödegaard
0339a5ad01 fix(graph): removed experimental mockup code that was accidently merged master 2015-12-09 13:36:15 +01:00
Torkel Ödegaard
bffb217d37 fix(panel): removed accidentally commited test markup 2015-12-09 13:08:47 +01:00
Torkel Ödegaard
40f85e5ca3 refactor(http data source options): #3473 2015-12-09 13:05:05 +01:00
Torkel Ödegaard
2dba2f4a95 Merge branch 'with_credentials' of https://github.com/mtanda/grafana into mtanda-with_credentials 2015-12-09 12:54:00 +01:00
Torkel Ödegaard
70542fb730 refactor(table views): #3466 2015-12-09 12:04:51 +01:00
Mitsuhiro Tanda
cd742979b1 add withCredentials checkbox 2015-12-09 19:43:59 +09:00
Torkel Ödegaard
736d58e35f Merge branch 'updated-list-views' of https://github.com/nchristus/grafana into nchristus-updated-list-views 2015-12-09 10:43:51 +01:00
Torkel Ödegaard
64138bd424 fix(timepicker): changed name of Day so far -> Today so far, Week to date > Week so far, closes #3465 2015-12-09 10:35:39 +01:00
carl bergquist
f51d74fa68 change the way options are added 2015-12-09 09:47:56 +01:00
carl bergquist
78c6ce842e revert elastic response parser 2015-12-09 09:10:50 +01:00
carl bergquist
ad79df9b74 changes implementation direction
moving average will now be based on another metric
instead of having moving average on itself
2015-12-09 09:04:48 +01:00
carl bergquist
b4763290de move target extraction logic to query def 2015-12-09 09:00:06 +01:00
Mitsuhiro Tanda
8264c76642 add separate datasource parameter withCredentials 2015-12-09 14:44:28 +09:00
Mitsuhiro Tanda
6edd6c8f03 add with_credentials to datasource model 2015-12-09 14:44:28 +09:00
Torkel Ödegaard
f1bc87133d Merge branch 'cloudwatch_aws-sdk-go-v1.0.0' of https://github.com/mtanda/grafana into mtanda-cloudwatch_aws-sdk-go-v1.0.0 2015-12-08 18:09:40 +01:00
Carl Bergquist
dd7a13930f adds null check for response parser 2015-12-08 18:04:30 +01:00
Carl Bergquist
8ad10149ab adds basic support for moving avg in es queries 2015-12-08 18:04:30 +01:00
Carl Bergquist
0731064375 adds support for moving avg support in es queries 2015-12-08 18:04:30 +01:00
Torkel Ödegaard
e194461420 feat(grunt watch): optimized grunt watch, now only operates on changed files 2015-12-08 17:56:02 +01:00
Daniel Low
b97b23647e memcache files in godep 2015-12-08 16:32:27 +00:00
Daniel Low
7bdeceff36 add memcache as godep 2015-12-08 16:18:40 +00:00
Torkel Ödegaard
45c69fa638 fix(influxdb): fixed issue where Group By label was only showed on first query, fixes #3453 2015-12-08 16:40:41 +01:00
Daniel Low
d7f3869959 gofmt 2015-12-08 14:59:54 +00:00
Torkel Ödegaard
cdc36dd171 Updated version 2015-12-08 15:41:34 +01:00
Daniel Low
ed16914715 Add memcache as session provider 2015-12-08 13:35:09 +00:00
Torkel Ödegaard
a1d66d98dc Merge pull request #3448 from utkarshcmu/tips
Fixed closing tags
2015-12-08 12:10:05 +01:00
Torkel Ödegaard
dd3295da60 Merge pull request #3449 from EricSmekens/patch-1
Cleaned up jquery.flot.events.js
2015-12-08 12:09:47 +01:00
Nick Christus
282aaa5cf0 Merge branch 'master' into updated-list-views 2015-12-07 16:30:02 -06:00
Nick Christus
462a939438 Merge branch 'master' of github.com:grafana/grafana 2015-12-07 16:29:51 -06:00
Nick Christus
030f902ca5 removed redundant labels 2015-12-07 16:26:18 -06:00
Eric Smekens
58093941c0 Cleaned up jquery.flot.events.js
_lastRange was confused with lastRange. This declared '_lastRange' somewhere globally.

Was also not used, so removed both.

(I know this is a library, but it was heavily adjusted anyway.)
2015-12-07 20:16:52 +01:00
utkarshcmu
005271d24b Fixed missing closing tag 2015-12-07 05:41:18 -08:00
utkarshcmu
2b263bcb5d Fixed closing tag 2015-12-07 05:06:52 -08:00
utkarshcmu
79d0f47ee7 Added columns in dashboard_snapshot 2015-12-07 04:24:29 -08:00
Torkel Ödegaard
1ebb18ae57 Merge pull request #3432 from toni-moreno/add_rpm_deb_separate_commands
add option pkg-rpm and pkg-deb to create separately both packages #3407
2015-12-07 11:46:00 +01:00
Torkel Ödegaard
fad4875f11 Merge pull request #3436 from utkarshcmu/templating
Removed if condition to fix 3370
2015-12-07 11:45:32 +01:00
utkarshcmu
42d1205260 Fixed gofmt checks 2015-12-06 23:59:58 -08:00
utkarshcmu
3d90340446 Added new columns to dashboard table 2015-12-06 23:51:43 -08:00
Torkel Ödegaard
d68e1fd308 Merge pull request #3444 from mtanda/cloudwatch_fix_period
(cloudwatch) fix period overwrite
2015-12-07 06:43:33 +01:00
Mitsuhiro Tanda
217d5df276 (cloudwatch) fix period overwrite 2015-12-07 13:40:54 +09:00
Mitsuhiro Tanda
d1ccf83236 (cloudwatch) use paging 2015-12-06 21:35:20 +09:00
Mitsuhiro Tanda
28968144d6 update aws-sdk-go v1.0.0 2015-12-06 21:35:19 +09:00
Torkel Ödegaard
4c5cfd51d7 fix(metric_editors): Fixes clicking timing issue for typeahead auto dropdown option, fixes #3428 2015-12-06 10:13:47 +01:00
utkarshcmu
b6044910ec Removed if condition to fix 3370 2015-12-05 06:34:03 -08:00
Torkel Ödegaard
5aa90eb086 Merge branch 'master' of github.com:grafana/grafana 2015-12-05 14:22:54 +01:00
Torkel Ödegaard
ce58486850 fix(html): removed unneeded tag 2015-12-05 14:22:39 +01:00
toni-moreno
7e63978a3f fix formatting for CircleCI test 2015-12-04 22:55:23 +01:00
toni-moreno
c9674f84e8 add option pkg-rpm and pkg-deb to create separately both packages #3407 2015-12-04 22:36:38 +01:00
woodsaj
0697274695 I add plugin dependency check.
This check ensures that all of the plugins required by a bundle
are loaded.
2015-12-05 01:20:42 +08:00
Torkel Ödegaard
654d1f939e Merge pull request #3424 from grafana/code-tag
add variable for codeTagBackground to control look for both themes.
2015-12-04 18:17:24 +01:00
Trent White
477b876a1f add variable for codeTagBackground to control look for both themes. Fixes #3399 2015-12-04 11:55:20 -05:00
woodsaj
523cf21b4a tune pluginConfig directive 2015-12-05 00:34:48 +08:00
Torkel Ödegaard
df0a5cf52f updated appveyor again 2015-12-04 16:56:37 +01:00
Torkel Ödegaard
caa6337952 updated appveyor 2015-12-04 16:48:35 +01:00
Torkel Ödegaard
700a3f9f84 Merge branch 'master' of github.com:grafana/grafana 2015-12-04 15:45:06 +01:00
Torkel Ödegaard
f9b13791de change(table panel): changed default transform mode 2015-12-04 15:38:49 +01:00
Torkel Ödegaard
7886318341 Merge pull request #3417 from mtanda/cloudwatch_dimension_filter_fix
(cloudwatch) null check of dimension
2015-12-04 12:30:13 +01:00
woodsaj
3c13901695 add ui elements for plugins.
This includes support for cusom plugin config directives.
2015-12-04 19:21:33 +08:00
Mitsuhiro Tanda
573632012e cloudwatch dimension null check 2015-12-04 20:16:31 +09:00
Torkel Ödegaard
002455da07 fix(table): minor fix to table panel and transform time series to aggregations 2015-12-04 12:15:42 +01:00
Torkel Ödegaard
e9e6ac64bd minor change to build script 2015-12-04 11:21:38 +01:00
Torkel Ödegaard
36ab8ae19c fix(table): minor fix for table panel 2015-12-04 10:44:17 +01:00
Torkel Ödegaard
df366da721 updated version to 2.6.0-beta1 2015-12-04 10:39:50 +01:00
Torkel Ödegaard
67dc761344 fix(security): do not print ENV config values when they are passwords, fixes #3337 2015-12-04 10:38:27 +01:00
Torkel Ödegaard
0b4552a8e7 fix(timerange): fix handling of invalid dates in from/to url parameters, fixes #3345 2015-12-04 10:32:23 +01:00
Torkel Ödegaard
2345b41a74 feat(elasticsearch): added min_doc_count option for date histogram, closes #3416 2015-12-04 10:06:44 +01:00
Torkel Ödegaard
141e395489 polish(influxdb): minor improvements to influxdb editor raw query editor 2015-12-04 09:20:29 +01:00
Nick Christus
91139672cc merge with master, conflicts fixed 2015-12-03 20:34:05 -06:00
Nick Christus
3d178c8eb6 Merge branch 'master' of github.com:grafana/grafana 2015-12-03 20:21:15 -06:00
Nick Christus
c9bd45ba13 removed filters and actions for now 2015-12-03 20:20:54 -06:00
Torkel Ödegaard
db9c288050 fix(elasticsearch): refactoring of #3321 2015-12-03 18:30:36 +01:00
Torkel Ödegaard
f1cb8f2f25 Merge branch 'keep_es_version' of https://github.com/replay/grafana into replay-keep_es_version 2015-12-03 18:08:26 +01:00
Torkel Ödegaard
7ec2c09249 Merge branch 'master' of github.com:grafana/grafana 2015-12-03 18:05:19 +01:00
Torkel Ödegaard
354bfcea15 Merge branch 'master' of https://github.com/skbkontur/grafana 2015-12-03 18:03:55 +01:00
Torkel Ödegaard
891d7c134c Merge pull request #3205 from mtanda/cloudwatch_suggest_fix
(cloudwatch) fix dimension value suggestion
2015-12-03 17:17:07 +01:00
Mitsuhiro Tanda
eb5822bc7c update cloudwatch docs 2015-12-04 01:04:50 +09:00
Mitsuhiro Tanda
154d70e4e2 remove dimensionPart 2015-12-04 01:02:25 +09:00
woodsaj
c4a0fe0234 add pluginBundle backend api methods and SQL storage 2015-12-03 23:43:55 +08:00
Torkel Ödegaard
0011beb654 Merge branch 'master' of github.com:grafana/grafana 2015-12-03 16:32:58 +01:00
Torkel Ödegaard
419251ed35 fix(elasticsearch): fixed issue with default state of elasticsearch query, result in error before query controller could set defaults, moved defaults to query builder, also removed raw query mode as it is pretty broken, fixes #3396 2015-12-03 16:32:35 +01:00
Torkel Ödegaard
bd850d8158 Merge pull request #3410 from bergquist/ignore_npm_log
add npm-debug.log to gitignore
2015-12-03 15:56:38 +01:00
carl bergquist
d7c7f27207 add npm-debug.log to gitignore 2015-12-03 15:29:28 +01:00
Torkel Ödegaard
0fb95297a2 Merge branch 'master' of github.com:grafana/grafana 2015-12-03 15:10:23 +01:00
Torkel Ödegaard
cf1f43dc9d feat(influxdb): support for table queries, closes #3409, #3219 2015-12-03 15:09:39 +01:00
Alexey Larkov
d6935847b4 Web. Fix double slash 2015-12-03 17:36:29 +05:00
Alexey Larkov
0715ba3e5e Merge pull request #1 from grafana/master
Merge with original source
2015-12-03 17:29:00 +05:00
Torkel Ödegaard
efbbb31370 Update README.md 2015-12-03 12:03:06 +01:00
Piotr Popieluch
207c1a20ee router logger, log username taken from cookie 2015-12-03 11:05:50 +01:00
Piotr Popieluch
579bc1c2c8 Add more info in route logging
- Add remote address
 - Add method
 - Add protocol
 - Add response size
 - Use consistent unit for response time (us)
2015-12-03 09:28:42 +01:00
woodsaj
bd4cb549d6 add pluginBundle support
A plugnBundle is meta plugin that has a set of dependent plugins
to enable.  This commit includes a plugin.json for a default
"core" bundle that enables all of the shipped panels and datasources.
2015-12-03 15:52:37 +08:00
woodsaj
fd392a2422 Merge remote-tracking branch 'upstream/external-plugins' into externalPlugin
Conflicts:
	public/views/index.html
2015-12-03 12:47:58 +08:00
woodsaj
13864853a8 support separate css files for light/dark themes. 2015-12-03 12:29:57 +08:00
Nick Christus
d86b2c4fb4 Merge branch 'master' of github.com:grafana/grafana 2015-12-02 21:33:06 -06:00
Greg Look
a1f103576a Wait for all panels to render in PhantomJS. 2015-12-02 15:13:02 -08:00
Torkel Ödegaard
aa766e3e18 Merge branch 'external-plugins' of github.com:grafana/grafana into external-plugins 2015-12-02 18:31:05 +01:00
Torkel Ödegaard
ee0e4d2b69 Merge branch 'master' into external-plugins
Conflicts:
	public/app/plugins/panels/table/editor.ts
	public/views/index.html
2015-12-02 18:30:48 +01:00
Torkel Ödegaard
8eb3e48bc7 fix(build): fixed build issues with concat not including require_config 2015-12-02 18:22:47 +01:00
utkarshcmu
384292b647 Removed metadata from dropdown, included in settings 2015-12-02 04:15:50 -08:00
Michael Kröll
1bb1ddcd29 Fixed spelling error 2015-12-02 11:14:28 +01:00
Torkel Ödegaard
24324939e1 Merge branch 'fix_refresh_variable_from_url' of https://github.com/toni-moreno/grafana into toni-moreno-fix_refresh_variable_from_url 2015-12-01 15:28:48 +01:00
Torkel Ödegaard
2436cda7ac fix(graph panel): minor spelling change 2015-12-01 15:28:34 +01:00
Torkel Ödegaard
75b83af08f refactoring(ui): minor ui improvement to graph axis tab 2015-12-01 14:04:44 +01:00
Torkel Ödegaard
82d8e3c2b6 feat(graph panel): refactoring of hide zero option, #3336 2015-12-01 13:34:42 +01:00
Torkel Ödegaard
c351f46e47 Merge branch 'hide-zero' of https://github.com/utkarshcmu/grafana into utkarshcmu-hide-zero 2015-12-01 13:08:37 +01:00
Torkel Ödegaard
fb9e8d2166 feat(table panel): fixed issue with column selection for new table panel 2015-12-01 10:16:11 +01:00
Torkel Ödegaard
3668cb6dd4 fix(readme): minor readme update 2015-12-01 09:23:30 +01:00
Torkel Ödegaard
93f3e30cac fix(log): removed logging accidentlally checked in 2015-12-01 09:19:22 +01:00
Torkel Ödegaard
52af346ec8 Merge pull request #3375 from hartfordfive/issue-3374
Add flag option to display app version (Issue 3374)
2015-12-01 09:18:37 +01:00
Torkel Ödegaard
8e0bba4f99 fix(templating): minor fix to default property name, fixes #3378 2015-12-01 09:01:44 +01:00
Torkel Ödegaard
4cc61d10ff fix(docs): fixed typo in installing docs fixes #3379 2015-12-01 08:59:30 +01:00
Al Lefebvre
8deb6d9246 Updated README 2015-11-30 13:09:29 -05:00
Al Lefebvre
20eb6df9e8 Removed comment line 2015-11-30 12:24:14 -05:00
Al Lefebvre
a921eeb5e2 Merge branch 'master' of github.com:hartfordfive/grafana into issue-3374 2015-11-30 12:20:47 -05:00
Al Lefebvre
f3f34e1835 Merge pull request #1 from grafana/master
Updating forked copy from official Grafana master
2015-11-30 12:20:32 -05:00
Al Lefebvre
4a29d459da Added flag to display version number and exit 2015-11-30 12:10:47 -05:00
Torkel Ödegaard
0f867a3484 Merge pull request #3230 from utkarshcmu/time-units
Added currency units, time units, tests
2015-11-30 17:29:51 +01:00
Torkel Ödegaard
6eeddaa564 Merge pull request #3369 from matschaffer/cw/alias-fix
Use of `<dimension name>` seems to confuse angular so changing to DIMENSION_NAME
2015-11-30 17:28:41 +01:00
Torkel Ödegaard
d80458ef81 Merge branch 'refresh' of https://github.com/utkarshcmu/grafana into utkarshcmu-refresh 2015-11-30 17:23:50 +01:00
Torkel Ödegaard
ad15df7222 Merge branch 'influxdb_editor_v3' 2015-11-30 16:29:20 +01:00
Torkel Ödegaard
98f7febed1 feat(influxdb): added all functions 2015-11-30 16:28:56 +01:00
Torkel Ödegaard
4f04eaec3a feat(influxdb): moved query builder tests 2015-11-30 15:27:38 +01:00
Torkel Ödegaard
5a2b9b1f44 feat(influxdb): worked on schema upgrade for new influx query editor 2015-11-30 15:09:18 +01:00
Torkel Ödegaard
721b37a08e feat(influxdb): new editor now supports field and tag lookup again 2015-11-30 10:14:42 +01:00
Torkel Ödegaard
b3d494d4c8 feat(influxdb): minor fixes to new editor 2015-11-30 08:40:11 +01:00
Mat Schaffer
85ec70e92b Use of <dimension name> seems to confuse angular so changing to DIMENSION_NAME 2015-11-30 15:55:07 +09:00
Torkel Ödegaard
e2f0ff9e88 Merge pull request #3367 from utkarshcmu/orgs
Fixed #3357
2015-11-30 07:40:07 +01:00
utkarshcmu
0dbd7d0e17 Fixed #3357 2015-11-29 03:28:07 -08:00
utkarshcmu
8cdaa044e1 Removed repeating test 2015-11-29 03:14:26 -08:00
utkarshcmu
712a420217 Fixed refresh setting for absolute time 2015-11-29 03:12:48 -08:00
addshore
b38dc70c71 Add graphtie sortByName natural param
Introduced in graphite 0.9.15

Fixes #3360
2015-11-28 00:16:42 +01:00
Torkel Ödegaard
72d9fcdcb4 feat(influxdb): progress with new influxdb editor 2015-11-27 16:35:40 +01:00
Torkel Ödegaard
5a6981e7af Merge pull request #3354 from raintank/externalPlugin
Merge changes to external-plugins branch
2015-11-27 10:21:35 +01:00
woodsaj
79d29db18b really fix unit tests. 2015-11-27 17:17:27 +08:00
woodsaj
4f6a52503d fix plugin unit test 2015-11-27 17:04:43 +08:00
woodsaj
1b5c40dd1f add role access limitions for menu items.
This allows external-plugin menu items to conditionally
be added to the UI depending on the logged in users
current role.
2015-11-27 16:27:14 +08:00
woodsaj
700b77c450 implement role access checks on external-plugin routes. 2015-11-27 16:26:30 +08:00
woodsaj
8449017592 Add plugin type field to externalPlugin model 2015-11-27 15:21:57 +08:00
shoonoise
5cf3425b93 Disable sign out button in case of auth proxy enabled 2015-11-26 17:56:45 +03:00
Torkel Ödegaard
aa13a80d83 fix(influxdb): fixed issue with metric segment component that caused double events 2015-11-26 09:28:59 +01:00
Torkel Ödegaard
9e2ef543ed Merge pull request #3343 from mtanda/cloudwatch_fix_credential_check
(cloudwatch) fix EC2RoleProvider parameter
2015-11-26 08:20:50 +01:00
Mitsuhiro Tanda
2aabb387b1 fix EC2RoleProvider parameter 2015-11-26 16:01:33 +09:00
Mitsuhiro Tanda
f972863f49 add credential setting to handleDescribeInstances 2015-11-26 13:21:38 +09:00
Torkel Ödegaard
f00320c8b9 feat(influxdb): query editor is starting to work, can now add group by parts 2015-11-25 14:27:22 +01:00
utkarshcmu
1f57cf08a7 Added an option to hide zero values 2015-11-25 04:38:54 -08:00
utkarshcmu
0ff5ff5dbe Enabled refresh interval for absolute time range 2015-11-25 04:05:40 -08:00
Torkel Ödegaard
5ba19144d5 feat(influxdb): more work on query editor 2015-11-25 12:30:56 +01:00
Torkel Ödegaard
c9ba856c52 feat(influxdb): more work on influxdb editor 2015-11-25 10:22:20 +01:00
Mauro Stettler
a30ceefa6b add tests for elastic search versioning in query builder and make es version 2 default 2015-11-25 16:23:28 +09:00
Torkel Ödegaard
31e2a8b8e9 feat(influxdb): more work onnew influxdb editor 2015-11-24 17:01:18 +01:00
Torkel Ödegaard
9b4150509c feat(influxdb): minor progress on new editor 2015-11-24 11:02:49 +01:00
Torkel Ödegaard
c68cd7d19a Merge branch 'master' into influxdb_editor_v3 2015-11-24 10:06:06 +01:00
Torkel Ödegaard
85382dc2e0 fix(table): fixed table height alignment 2015-11-24 10:04:01 +01:00
Torkel Ödegaard
7315a0ecec Merge pull request #3319 from VibyJocke/master
Fixed some broken HTML.
2015-11-24 09:45:13 +01:00
Torkel Ödegaard
411bd55cd4 Merge pull request #3318 from utkarshcmu/validated-responses
Validated HTTP responses
2015-11-24 09:31:23 +01:00
Joakim Lahtinen
9c0141e84e Fixed some broken HTML.
Simplified some control flow.
2015-11-24 07:29:52 +01:00
utkarshcmu
ca5d0496ee Validated HTTP responses 2015-11-23 19:19:26 -08:00
Torkel Ödegaard
24b9bc1e55 fix(missing files): added missing files, oops 2015-11-23 18:20:12 +01:00
Torkel Ödegaard
cf1e167430 feat(table panel): table panel can now show nested object data, closes #3263 2015-11-23 16:10:32 +01:00
Torkel Ödegaard
a1afd2328d fix(elasticsearch): made interval template variable appear in group by time interval dropdown, fixes #3241 2015-11-23 14:19:10 +01:00
Mauro Stettler
ada9bfcae8 keep track of elastic search version and generate query according to version 2015-11-22 21:39:56 +09:00
utkarshcmu
f88588db90 Added close button 2015-11-21 19:36:27 -08:00
utkarshcmu
5930dc6354 Removed info icon, Included metadata feature 2015-11-21 16:37:15 -08:00
Dennis de Greef
9c64da4323 Add cubic meters to units 2015-11-21 21:04:08 +01:00
utkarshcmu
c863ea4aa1 Shortened info details to use less space 2015-11-21 06:43:45 -08:00
utkarshcmu
e1432f4339 Function name makes sense now 2015-11-21 06:20:13 -08:00
utkarshcmu
890c527ae5 Added info dropdown 2015-11-21 06:16:28 -08:00
Torkel Ödegaard
1fa8b74595 Merge pull request #3303 from utkarshcmu/db-update
Return correct updated+created timestamps to frontend
2015-11-21 14:10:50 +01:00
utkarshcmu
5559ad1238 Return correct updated+created timestamps to frontend 2015-11-21 05:03:00 -08:00
Torkel Ödegaard
bd8f5e9bfd fix(build): fixed build after change that made panels into proper plugins 2015-11-21 13:53:33 +01:00
Torkel Ödegaard
29f6283eab Merge branch 'master' into external-plugins 2015-11-21 13:48:31 +01:00
Torkel Ödegaard
396f53d20e fix(tests): removed it.only accidentally cecked in 2015-11-21 13:48:12 +01:00
Torkel Ödegaard
4a69de1f30 feat(plugins): made panels work as plugins 2015-11-21 13:46:43 +01:00
Torkel Ödegaard
bd6e2d6ca4 Merge branch 'master' into external-plugins 2015-11-21 12:57:33 +01:00
Torkel Ödegaard
fc78e42a78 Merge pull request #3297 from utkarshcmu/db-update
Fixed created & updated columns update in dashboard table
2015-11-21 10:25:29 +01:00
Torkel Ödegaard
9d1906d333 fix(elasticsearch): fixed issue with disabling (hiding) query, fixes #3300 2015-11-21 10:22:59 +01:00
Torkel Ödegaard
4a3f50cef7 fix(docs): minor fix to http docs, fixes #3301 2015-11-21 10:07:33 +01:00
Torkel Ödegaard
4751e4b94e feat(elasticsearch): a lot of work to support aggregation queries without date_histogram, queries that return metric aggregations now work with the table panel (json data type), #3219 2015-11-20 16:26:44 +01:00
utkarshcmu
1b7f4f31ca Tired of gofmt 2015-11-20 04:52:50 -08:00
utkarshcmu
ca01604b43 Added statements in constructor 2015-11-20 04:37:24 -08:00
utkarshcmu
93f9a0c39c Fixed created & updated columns in dashboard table 2015-11-20 03:10:24 -08:00
Torkel Ödegaard
93977316ce revert #3288 for now since it breaks Elasticsearch 1.7 2015-11-20 10:48:10 +01:00
Torkel Ödegaard
7e49bdf5a8 revert #3288 for now since it breaks Elasticsearch 1.7 2015-11-20 10:45:48 +01:00
Torkel Ödegaard
df0bc7bbc4 feat(external_plugin): lots of refactoring for side menu link extensions and view data, #3185 2015-11-20 09:43:10 +01:00
Torkel Ödegaard
63b50ab9b1 Merge branch 'master' into external-plugins 2015-11-20 08:29:46 +01:00
Torkel Ödegaard
c0beef7572 Merge pull request #3252 from alechenninger/avg-ignore-null
Ignore nulls unless 'null as zero' for series.stats.avg
2015-11-20 08:27:45 +01:00
Torkel Ödegaard
5ec448861d Merge pull request #3284 from mtanda/prometheus_null_point
(prometheus) support null point mode
2015-11-20 08:27:36 +01:00
Torkel Ödegaard
7d4326a397 Merge pull request #3292 from mtanda/cloudwatch_null_pointmode
(cloudwatch) fix null point mode
2015-11-20 08:24:51 +01:00
Torkel Ödegaard
cc43b94864 Merge pull request #3293 from jmcfarlane/prometheus-fix-step-calibration
[prometheus] Fix step calibration
2015-11-20 08:24:35 +01:00
Torkel Ödegaard
57a31828f8 fix(templating): very minor markup/css change 2015-11-20 08:18:03 +01:00
Torkel Ödegaard
0c7fccdcbe Merge pull request #2812 from utkarshcmu/master
Duplicate button for template variables
2015-11-20 08:14:20 +01:00
Mitsuhiro Tanda
a1fcd3c5b6 import fix step calibration 2015-11-20 15:37:31 +09:00
John McFarlane
c4048f8f22 [prometheus] Fix step calibration
The step interval is (correctly) being converted to seconds, but the
unit of measure suffixed onto the end is preventing the subsequent
step calibration. Because the query upstream defaults to seconds as
the unit of measure, the suffix can simply be removed and everything
works as intended.

patchset 01: Also fix the spec.
2015-11-19 21:20:07 -08:00
Mitsuhiro Tanda
15dc30edf6 if there isn't enough datapoint, add null data point 2015-11-20 13:24:49 +09:00
Mitsuhiro Tanda
4254aa5f5a (cloudwatch) fix null point mode 2015-11-20 13:06:35 +09:00
Nick Christus
09ff042986 updated-list-views: added new table layout to additional pages 2015-11-19 21:02:38 -06:00
Torkel Ödegaard
924ecce2c3 Merge pull request #3288 from replay/fix_time_format
specify date format in elastic search query
2015-11-19 18:53:59 +01:00
Torkel Ödegaard
69daede583 feat(external plugins): worked on supporting external plugins better 2015-11-19 18:44:07 +01:00
Mauro Stettler
a6e8d61e8e specify date format in elastic search query 2015-11-20 02:11:48 +09:00
Torkel Ödegaard
65a7fa320a feat(plugins): made plugins that live outside public work 2015-11-19 16:50:17 +01:00
Torkel Ödegaard
be5e6d55fc Merge pull request #3285 from ckrybus/patch-1
Fix recommended graphite version for better performance
2015-11-19 14:01:07 +01:00
Christoph Krybus
b0c01369c5 Fix recommended graphite version for better performance
There is no 0.9.13 graphite release, only 0.9.14.
2015-11-19 13:44:46 +01:00
Torkel Ödegaard
f6772bb896 feat(plugins): began work on supporting having plugins outside grafana, for example in grafana data dir, next step is to be able to easily specify what plugins you waant to install 2015-11-19 12:55:13 +01:00
Torkel Ödegaard
b21fa2daa0 Merge branch 'externalPlugin' of https://github.com/raintank/grafana into external-plugins 2015-11-19 11:05:27 +01:00
Torkel Ödegaard
730d4857ba feat(elasticsearch): added caret arrow for metric / group by collapse/expand options 2015-11-19 11:04:21 +01:00
Torkel Ödegaard
0e1c12e65f Merge pull request #3279 from mtanda/override_null
override null point mode
2015-11-19 08:42:01 +01:00
Mitsuhiro Tanda
37b125ca98 override null point mode 2015-11-19 15:20:34 +09:00
Torkel Ödegaard
2e9303cb6c dependency(aws): updated aws go lib dependency 2015-11-18 17:26:35 +01:00
Torkel Ödegaard
7db38c80fc Merge branch 'aws-sdk-go' of https://github.com/mischief/grafana into mischief-aws-sdk-go 2015-11-18 17:16:42 +01:00
Torkel Ödegaard
aad824a562 feat(tablepanel): completed work on time series aggregations table transform, #3219 2015-11-18 17:05:21 +01:00
Torkel Ödegaard
f0087c93b8 fix(admin settings view): always censor provider_config for system info view, fixes #3268 2015-11-18 15:55:45 +01:00
Mitsuhiro Tanda
ae7e7e9656 remove getDimensions() 2015-11-17 22:49:46 +09:00
Torkel Ödegaard
e008473e47 Merge pull request #3249 from mtanda/cloudwatch_null_pointmode
(cloudwatch) support null point mode
2015-11-17 14:03:48 +01:00
Torkel Ödegaard
79313aa268 Merge pull request #3253 from mtanda/cloudwatch_ecs
(cloudwatch) support ECS suggestion
2015-11-17 14:00:31 +01:00
toni-moreno
1c35d4b26b removed autoupdate on variabe refresh, don't needed if working interactive and fix #2722 2015-11-16 21:55:23 +01:00
Torkel Ödegaard
a56f657fb1 Merge pull request #3254 from utkarshcmu/user-id
/api/admin/users returns user ID in JSON response
2015-11-16 17:47:11 +01:00
utkarshcmu
f5db9950f8 fixed gofmt tests 2015-11-16 07:28:38 -08:00
utkarshcmu
e5931e264b Updated http_api docs 2015-11-16 06:56:46 -08:00
utkarshcmu
9485e8cfee /api/admin/users returns user ID 2015-11-16 06:55:02 -08:00
Mitsuhiro Tanda
22b139d9f8 (cloudwatch) support ECS suggestion 2015-11-16 23:21:43 +09:00
Alec Henninger
2a600b25e7 Ignore nulls unless 'null as zero' for series.stats.avg 2015-11-16 08:43:41 -05:00
Mitsuhiro Tanda
393891d6ea (cloudwatch) fill null if the datapoint missing 2015-11-16 18:23:12 +09:00
Mitsuhiro Tanda
1bbd056797 fix templating 2015-11-16 16:51:03 +09:00
Mitsuhiro Tanda
add5bb47d5 add dimensions() to CloudWatch templating query 2015-11-16 16:50:53 +09:00
Torkel Ödegaard
305f8d6982 Merge pull request #3234 from utkarshcmu/opentsdb-ui
Made opentsdb query editor consistent and tags are editable now
2015-11-16 06:29:02 +01:00
Torkel Ödegaard
93851a9a0f feat(tablepanel): added time series aggregations transform mode, #3219 2015-11-13 17:36:11 +01:00
utkarshcmu
8a184e9d30 Made tags editable in opentsdb query 2015-11-13 04:01:55 -08:00
utkarshcmu
3a66d7c453 Made opentsdb query editor consistent 2015-11-13 03:08:48 -08:00
Torkel Ödegaard
00a479de6f feat(tablepanel): renamed some table panel schema things 2015-11-13 10:32:01 +01:00
Torkel Ödegaard
32f9f8fcce fix(http api): correct return status code for /api/datasources/:id so it eturns 404 when not found, fixes #3217 2015-11-13 09:43:25 +01:00
Torkel Ödegaard
e4208441b3 fix(inspector): added close button to inspector modal, fixes #3213 2015-11-13 09:36:52 +01:00
Torkel Ödegaard
ee5ebe2e81 Merge pull request #3224 from mattttt/patch-6
Updating singlestat article to include troubleshooting
2015-11-13 09:32:42 +01:00
Torkel Ödegaard
a71b681e80 fix(docs): minor docs fix 2015-11-13 09:32:16 +01:00
Torkel Ödegaard
2cbc62d6c0 fix(elasticsearch): fixed elasticsearch issue, ghost docs series, fixes #3223 2015-11-13 09:30:28 +01:00
Torkel Ödegaard
cc125f5fd7 change(shortcuts): changed CTRL+F search shortcut to just F 2015-11-13 09:25:31 +01:00
utkarshcmu
7f9c8a1935 Added hours, days units and tests for all 2015-11-12 23:56:24 -08:00
utkarshcmu
3c54d14460 Added UI for time units, minute scalability 2015-11-12 20:26:59 -08:00
utkarshcmu
c5b39a5100 Added currency units 2015-11-12 09:56:46 -08:00
Matt Toback
7888c1c614 Update singlestat.md 2015-11-12 12:35:45 -05:00
Matt Toback
b43315c36d Update singlestat.md 2015-11-12 12:07:09 -05:00
Matt Toback
fbd6417c8a Updating singlestat article to include troubleshooting 2015-11-12 12:03:33 -05:00
Torkel Ödegaard
850ad1c0fb fix(tablepanel): fixed width fix for page2+, #3219 2015-11-12 16:30:15 +01:00
Torkel Ödegaard
dbe35bfed1 change(elasticsearch): changed min_doc_count to zero in query to get buckets for missing values, fixes #3131 2015-11-12 16:06:10 +01:00
Torkel Ödegaard
f1caae126e feat(build): fixed build issues 2015-11-12 14:28:35 +01:00
Torkel Ödegaard
bad6a40a12 updated readme 2015-11-12 13:50:57 +01:00
Torkel Ödegaard
5bc194e1f0 Merge branch 'master' of github.com:grafana/grafana 2015-11-12 13:47:25 +01:00
Torkel Ödegaard
d315ff2b96 changelog: updated master version to 2.6 and merged develop branch 2015-11-12 13:47:12 +01:00
Torkel Ödegaard
163b45cf37 feat(tablepanel): minor fix 2015-11-12 13:41:53 +01:00
Torkel Ödegaard
87c718f549 feat(tablepanel): worked on issues and improving defaults 2015-11-12 12:39:16 +01:00
Torkel Ödegaard
e04678f33c feat(dasbboard): fix to issues when setting fullscreen/edit state for panel that have yet to get a scope 2015-11-12 12:01:44 +01:00
Torkel Ödegaard
bbdf75bdfa feat(dashboard): Automatically go into panel edit mode after adding a new panel to the dashboard 2015-11-12 11:49:07 +01:00
Torkel Ödegaard
5c0cf9f5d7 feat(tablepanel): worked on more display options for table panel 2015-11-12 11:36:16 +01:00
Torkel Ödegaard
8a61ec4b4e feat(tablepanel): paging is starting to work 2015-11-11 16:40:36 +01:00
Torkel Ödegaard
874a6e86fd Merge pull request #3113 from utkarshcmu/custom
Added All Value support for custom type templating
2015-11-11 12:29:04 +01:00
Mitsuhiro Tanda
ef4bec1c6d fix CloudWatch dimension value suggestion 2015-11-11 20:15:30 +09:00
Torkel Ödegaard
4da99d14e6 Merge pull request #3204 from mtanda/cloudwatch_ebs_fix
CloudWatch EBS Templating fix
2015-11-11 12:09:15 +01:00
Mitsuhiro Tanda
cc80191cd1 CloudWatch ebs templating fix 2015-11-11 19:48:10 +09:00
Torkel Ödegaard
3cdb3f0d54 Merge pull request #3196 from utkarshcmu/custom-time
Timepicker display fixed for now-*
2015-11-11 11:28:55 +01:00
woodsaj
437b957be1 remove external_plugin from models package. 2015-11-11 17:45:38 +08:00
utkarshcmu
9f17e4ee2c Added unit tests to verify time range fix 2015-11-11 01:34:53 -08:00
utkarshcmu
509c3dc715 Fixed time range when using NOW from and to 2015-11-11 01:34:24 -08:00
Torkel Ödegaard
4051f04e66 Merge pull request #3202 from mtanda/cloudwatch_sort
sort CloudWatch suggestion region and namspace
2015-11-11 09:42:51 +01:00
woodsaj
d503c5d83d refer to plugins are ExternalPlugin instead of thirdParty 2015-11-11 14:30:07 +08:00
Mitsuhiro Tanda
02a37d670c sort namespaces by alphabetical order 2015-11-11 14:23:43 +09:00
Mitsuhiro Tanda
a7deca1df5 sort regions by alphabetical order 2015-11-11 14:23:38 +09:00
Torkel Ödegaard
1bec6c2aae feat(tablepanel): made annotations transform work 2015-11-10 16:15:23 +01:00
Torkel Ödegaard
a66825c71f Merge branch 'master' into develop 2015-11-10 15:26:02 +01:00
Torkel Ödegaard
0fb110a4af Merge pull request #3190 from utkarshcmu/three-hours
added now-3h option
2015-11-10 15:02:34 +01:00
utkarshcmu
167c02d773 Timepicker display fixed for now-* 2015-11-10 04:53:42 -08:00
utkarshcmu
0c50a7437b missed an S at the end 2015-11-10 02:29:02 -08:00
utkarshcmu
5339ec66b7 added now-3h option 2015-11-10 02:22:15 -08:00
Torkel Ödegaard
2371dcf694 Merge pull request #3188 from mtanda/template_error_report
Fix templating error dialog for Prometheus
2015-11-10 11:21:26 +01:00
Mitsuhiro Tanda
65bc194c42 fix templating error dialog for Prometheus 2015-11-10 19:01:37 +09:00
Torkel Ödegaard
99ee38cea3 feat(tablepanel): minor change 2015-11-10 08:38:34 +01:00
Torkel Ödegaard
5d8a51c307 Merge pull request #3129 from utkarshcmu/validity
Default AWS Region selection from dropdown
2015-11-09 22:25:30 +01:00
utkarshcmu
6325635fce Corrected the frontend filename 2015-11-09 12:31:35 -08:00
utkarshcmu
7612e47aee Select AWS region from dropdown 2015-11-09 12:08:40 -08:00
Torkel Ödegaard
d06b9401ea feat(tablepanel): added support for column sorting 2015-11-09 17:58:02 +01:00
Torkel Ödegaard
ecb1552c10 Merge pull request #3172 from utkarshcmu/aws-bug
Test specified AWS Region and not hardcoded us-east-1
2015-11-09 13:54:20 +01:00
utkarshcmu
9f066d01b1 Check specified AWS Region and not us-east-1 2015-11-09 03:35:51 -08:00
Torkel Ödegaard
673ae1edc0 Merge branch 'tablepanel2' into develop 2015-11-09 11:26:06 +01:00
Torkel Ödegaard
b25b31e4a0 Merge branch 'master' into develop 2015-11-09 11:25:22 +01:00
Torkel Ödegaard
f65fde8bb7 Merge pull request #3148 from utkarshcmu/units
Added throughput units.
2015-11-09 10:14:02 +01:00
Torkel Ödegaard
0a04b135ca Merge pull request #3158 from dthapa/master
use [auth.github] -> api_url property; supports git enterprise
2015-11-09 10:12:57 +01:00
Torkel Ödegaard
88d27fe649 log(color): disabled console log formating by default 2015-11-09 09:48:02 +01:00
Torkel Ödegaard
5d166dc8cb feat(tablepanel): added new renderer spec 2015-11-09 09:46:49 +01:00
Torkel Ödegaard
8f81c97aaa Merge pull request #3170 from utkarshcmu/opentsdb-ctrl
Fixed opentsdb queryctrl uncheck Rate UI bug
2015-11-09 09:43:25 +01:00
Torkel Ödegaard
b5f35261a0 Merge pull request #3171 from utkarshcmu/aws-regions
Added missing AWS Regions
2015-11-09 09:41:57 +01:00
utkarshcmu
f55e24cd12 Added missing AWS Regions 2015-11-09 00:28:16 -08:00
utkarshcmu
efc0b60d41 Fixed opentsdb queryctrl uncheck Rate UI bug 2015-11-08 21:44:58 -08:00
Hereward Cooper
f3bc726001 Dynamically reorder hovercard 2015-11-08 01:03:02 -08:00
Nick Owens
60e797ccc4 pkg/setting: integrate syslog logger settings 2015-11-07 18:35:57 -08:00
Nick Owens
20b553461b conf: add syslog logging defaults 2015-11-07 18:35:52 -08:00
Nick Owens
0bff097afb pkg/log: implement syslog logger 2015-11-07 18:34:55 -08:00
Nick Owens
b0cb6d6d4c pkg/api/cloudwatch: fix api client construction against aws-sdk-go v0.10.2 2015-11-07 18:17:05 -08:00
Don Thapa
b345c7cf46 gofmt happiness 2015-11-07 11:32:06 -06:00
Torkel Ödegaard
56e2082205 Merge pull request #3157 from utkarshcmu/postgres
Fixed user deletion in Postgres SQL
2015-11-07 15:37:28 +01:00
utkarshcmu
fe2d8f1ea0 Used dialect for postgres 2015-11-07 05:21:22 -08:00
Don
e16bbc660d use [auth.github] -> api_url property; supports git enterprise 2015-11-07 00:06:15 -06:00
utkarshcmu
2676f24e0a Fixed user deletion in Postgres SQL 2015-11-06 20:17:27 -08:00
Torkel Ödegaard
b8e6fcfeae feat(tablepanel): worked on cell / value threshold coloring 2015-11-06 13:16:17 +01:00
utkarshcmu
b5f18561ab Added unit tests to verify units 2015-11-05 23:13:53 -08:00
utkarshcmu
22c3ec2d63 Made the units more readable 2015-11-05 22:57:05 -08:00
utkarshcmu
b678daa744 Added throughput units. 2015-11-05 22:31:33 -08:00
Torkel Ödegaard
e1433ebb41 feat(tablepanel) more refactoring 2015-11-05 12:42:47 -05:00
Torkel Ödegaard
1b83742e3e feat(tablepanel): began refactorin out table row html generation to write unit tests for it 2015-11-05 15:55:42 +01:00
Torkel Ödegaard
90cca93951 feat(tablepanel): lots of work on table panel 2015-11-05 13:13:13 +01:00
Torkel Ödegaard
4e37290a7f feat(tablepanel/elasticsearch): extended elasticsearch data source and query editor to support document queries 2015-11-05 09:56:19 +01:00
Torkel Ödegaard
7d3146ed8d feat(tablepanel): fixed header, and pagination styling 2015-11-05 08:36:51 +01:00
Torkel Ödegaard
0a1af65a4c feat(tablepanel): more column style rules 2015-11-05 07:43:06 +01:00
utkarshcmu
4de9ac133a Set default AWS region from dropdown now 2015-11-04 17:21:34 -08:00
Torkel Ödegaard
60c7bfe9a7 feat(tablepanel): work on table panel options 2015-11-04 22:44:08 +01:00
Tom Dyas
9bafc4fea1 add pencil icon back to graphite data source
The input needed to be wrapped in a span set to display:block in order to prevent it
from moving to the next line. See http://stackoverflow.com/questions/773517/style-input-element-to-fill-remaining-width-of-its-container
2015-11-04 11:36:55 -05:00
Torkel Ödegaard
7387f2e490 feat(tablepanel): fixed header, and pagination styling 2015-11-04 17:23:16 +01:00
Torkel Ödegaard
93b4f3fac8 feat(tablepanel): minor progress on table panel 2015-11-04 12:56:53 +01:00
utkarshcmu
fdeeb73587 AWS Region as a mandatory field 2015-11-04 02:27:35 -08:00
Torkel Ödegaard
6062930f9a feat(tablepanel): added more unit tests for table transforms 2015-11-04 09:41:03 +01:00
Torkel Ödegaard
867b838053 feat(tablepanel): work on table panel 2015-11-03 16:19:51 +01:00
Nick Christus
58dc282ca0 updated-list-views: updating table layout for org users 2015-11-03 08:24:10 -06:00
Torkel Ödegaard
d7ee7cb88f Merge pull request #3119 from utkarshcmu/docs
Dashboard JSON Docs
2015-11-03 13:33:15 +01:00
Torkel Ödegaard
da9c792ca2 feat(tablepanel): minor progress 2015-11-03 08:18:35 +01:00
Torkel Ödegaard
8171cd51c4 feat(tablepanel): minor progress on table panel 2015-11-02 20:51:49 +01:00
Utkarsh Bhatnagar
74b10a42ee Fixed broken links in the doc page 2015-11-02 10:29:42 -08:00
Utkarsh Bhatnagar
f14ef22bb6 Fixed doc links 2015-11-02 10:25:33 -08:00
Utkarsh Bhatnagar
e8c9b0806a Added templating, timepicker, panel docs 2015-11-02 10:15:40 -08:00
Torkel Ödegaard
36c4d01ef8 feat(tablepanel) began work on new table panel 2015-11-02 17:00:47 +01:00
Torkel Ödegaard
e51d403420 rename: moved test file 2015-11-02 15:14:35 +01:00
Utkarsh Bhatnagar
f54615ed46 Included rows JSON and TODO headers 2015-11-02 00:21:59 -08:00
utkarshcmu
4c1b6f3059 Fixed a typo 2015-11-01 23:55:03 -08:00
Utkarsh Bhatnagar
ada641090f Explained basic JSON fields 2015-11-01 23:53:24 -08:00
Torkel Ödegaard
eb6c8a3521 Merge pull request #3118 from utkarshcmu/angular-native
Removed unnecessary components.
2015-11-02 08:23:02 +01:00
utkarshcmu
3a021a87a1 Added JSON of new dashboard 2015-11-01 23:17:23 -08:00
utkarshcmu
5100339604 Initialized dashboard JSON doc. 2015-11-01 22:58:14 -08:00
utkarshcmu
8448e3970b Removed unnecessary components. 2015-11-01 09:48:27 -08:00
Torkel Ödegaard
dbed679904 Merge pull request #3116 from vitaliyf/patch-1
Fixed typo in OpenTSDB's "metasync" documentation
2015-11-01 14:47:28 +01:00
Vitaliy Fuks
acb5340ffb Fixed typo in OpenTSDB's "metasync" documentation 2015-10-31 18:07:24 -04:00
Torkel Ödegaard
6a01cd56ca Merge pull request #3085 from mtanda/cloudwatch_template_doc
Add templating explanation to CloudWatch docs.
2015-10-31 11:37:01 +01:00
Torkel Ödegaard
ae38705bed Merge pull request #3112 from utkarshcmu/docs
Update opentsdb.md
2015-10-31 11:35:30 +01:00
Torkel Ödegaard
db083c43dd Merge pull request #3111 from felixbuenemann/fix-npm-3-phantomjs-build-failure
Fix npm 3 build failure in phantomjs task
2015-10-31 11:35:17 +01:00
utkarshcmu
c5435596ad Added All Value support for custom type templating 2015-10-30 22:34:40 -07:00
Utkarsh Bhatnagar
03130e1217 Update opentsdb.md
As we merged, changes with auto suggestions in the master branch. Update docs respectively.
2015-10-30 22:11:17 -07:00
Felix Bünemann
2ca6acc1e9 Fix npm 3 build failure in phantomjs task
npm v3.0+ by default dedupes node modules and stores them in a flat
tree, which means the hardcoded path to the location.js will no longer
be nested under the karma-phantomjs-launcher module.

This fixes issue #2999.
2015-10-31 05:36:35 +01:00
Torkel Ödegaard
d8f68eb118 refactoring: moving and renaming things 2015-10-30 16:06:29 +01:00
Torkel Ödegaard
97697b93ed refactoring: moving and renaming things 2015-10-30 15:58:20 +01:00
Torkel Ödegaard
152b484eb5 refactoring: moved app/controllers -> app/core/controllers 2015-10-30 15:16:05 +01:00
Torkel Ödegaard
97de8c1cc2 refactoring: move moving stuff around 2015-10-30 15:04:27 +01:00
Torkel Ödegaard
6cf46b1635 refactoring: more moving stuff around 2015-10-30 14:44:40 +01:00
Torkel Ödegaard
1665cb4282 refactoring: moving components -> core 2015-10-30 14:24:04 +01:00
Torkel Ödegaard
1113081aab refactoring: moving components -> core 2015-10-30 14:19:02 +01:00
Torkel Ödegaard
39bc3cb532 refactoring: moving stuff around 2015-10-30 14:04:25 +01:00
Torkel Ödegaard
0a0a0776e4 Merge pull request #3088 from utkarshcmu/suggest-opentsdb
Tag suggestions fixed for v2.1.1 & above by using Suggest Api.
2015-10-30 10:34:44 +01:00
Torkel Ödegaard
59d199a148 Merge pull request #3098 from utkarshcmu/typos
Fixed some more typos in docs
2015-10-30 10:32:51 +01:00
utkarshcmu
8b9d13491f Fixed some more typos in docs 2015-10-30 02:07:08 -07:00
Torkel Ödegaard
4dcd2ceb01 fix(graph): fixed for color picker layout issue when right side legend was used, fixes #3093 2015-10-30 09:31:04 +01:00
Torkel Ödegaard
6004ba6554 Merge pull request #3095 from itsmrwave/correct_object_key_typo
Correct object key typo
2015-10-30 09:15:27 +01:00
King'ori Maina
f1847d4501 Correct object key typo
Should be ‘message’ not ‘messsage’.
2015-10-30 09:52:33 +02:00
Nick Christus
e63ff167a7 updated-list-views: added filter controls, updated tables on API Keys and Data Sources 2015-10-29 21:09:21 -05:00
utkarshcmu
a27186e34f Cleaned the codebase :D 2015-10-29 11:28:38 -07:00
utkarshcmu
2a8904f844 Fixed queryCtrl to use suggest API 2015-10-29 11:13:38 -07:00
Torkel Ödegaard
59fc72d37e Merge branch 'prometheus-fix_step_calculation' of https://github.com/dan-cleinmark/grafana into dan-cleinmark-prometheus-fix_step_calculation 2015-10-29 16:50:18 +01:00
Torkel Ödegaard
34e3683ded fix(cloudwatch): fixed limiting of cloudwatch period so it works for long time ranges in all cases, fixes #3086 2015-10-29 16:46:58 +01:00
Torkel Ödegaard
13760b1bdd fix(influxdb): fixed handling of relative time ranges like last x years, or last x months, fixes #3067 2015-10-29 15:53:15 +01:00
Mitsuhiro Tanda
8a252774ce Update cloudwatch.md, add explanation about templating 2015-10-29 23:51:27 +09:00
Dan Cleinmark
963f9fdf40 Ensure Promtheus step interval is always < 11000
Using a 2 week window (1209600 seconds) and a 60s step, Math.floor()
recalculates a step of 109 and results in 11097 data points in the
Prometheus query (> the 11000 max set by Prometheus). Math.ceil()
returns a step of 110 and 10996 data points.
2015-10-29 07:24:42 -07:00
shoonoise
b4a2b96e32 Add options to manage snapshot publishing 2015-10-29 16:40:03 +03:00
Torkel Ödegaard
299a2457cd Merge branch 'master' of github.com:grafana/grafana 2015-10-29 14:05:19 +01:00
Torkel Ödegaard
3de4707c98 feat(elasticsearch): Annotation queries now use the daily index patterns defined in data source options, for old annotations that have an index property that will be used, so will not break existing dashboard/annotation configs, closes #3061 2015-10-29 14:05:05 +01:00
Torkel Ödegaard
603ec65e91 Merge pull request #3059 from mtanda/cloudwatch_template_fix
fix panel repeat for cloudwatch
2015-10-29 12:38:22 +01:00
Torkel Ödegaard
cdcffcd31e fix(css): restored tooltip background to dark for white theme #3079 2015-10-29 12:32:32 +01:00
Torkel Ödegaard
f8a1c7c8a1 docs(cloudwatch): updated docs with info about #3080 2015-10-29 12:22:01 +01:00
Torkel Ödegaard
5d64568f3e refactoring: some minor refactoring and changes to AWS profile PR #3053 2015-10-29 11:44:34 +01:00
Torkel Ödegaard
374fbad06d Merge branch 'master' into peekeri-support_aws_profiles 2015-10-29 11:19:15 +01:00
Torkel Ödegaard
aa31336c64 Merge pull request #3072 from utkarshcmu/tooltip
Added tooltip for cloudwatch datasource
2015-10-29 11:18:24 +01:00
Torkel Ödegaard
135ba68ff5 Merge branch 'support_aws_profiles' of https://github.com/peekeri/grafana into peekeri-support_aws_profiles 2015-10-29 11:14:04 +01:00
utkarshcmu
d3ee81bb5a Added tooltip for cloudwatch datasource 2015-10-28 10:18:44 -07:00
utkarshcmu
e0b585779d Added relative time by default, removed checkbox 2015-10-28 08:52:46 -07:00
Torkel Ödegaard
4729bea1a2 fix(dashboard): fix for collapse row by clicking on row title, fixes #3065 2015-10-28 15:04:58 +01:00
Torkel Ödegaard
e1393f9780 changelog: updated and marked 2.5 as released 2015-10-28 14:46:47 +01:00
Torkel Ödegaard
ad7e66cdae Merge pull request #3062 from utkarshcmu/templates
Fixed typos in 2.5v doc
2015-10-28 13:00:22 +01:00
utkarshcmu
2f09ef2970 Fixed typos in 2.5v doc 2015-10-28 04:27:51 -07:00
Torkel Ödegaard
6ea2c08ecb docs(): minor docs fix 2015-10-28 11:50:22 +01:00
Mitsuhiro Tanda
b82f1edd63 fix panel repeat for cloudwatch 2015-10-28 19:36:49 +09:00
Torkel Ödegaard
1685e7cea4 docs(): update to install docs and whats new in 2.5 2015-10-28 11:08:12 +01:00
Torkel Ödegaard
287d8ca367 fix(changelog): minor spelling fix to changelog 2015-10-28 09:43:28 +01:00
Torkel Ödegaard
6397b8c1ef docs(): updated version to 2.5.0 2015-10-28 09:31:57 +01:00
Torkel Ödegaard
89eedd59a8 Merge pull request #3008 from mtanda/prometheus_link
Revert prometheus graph view link
2015-10-28 09:29:07 +01:00
ubhatnagar
af65a81d5b Added relative time in tooltip 2015-10-27 23:18:38 -07:00
ubhatnagar
03e2f25adb Added relative time func and code refactoring 2015-10-27 22:04:43 -07:00
Nick Christus
aa9093bcf6 updated-list-views: added filter-table less component, updating styles for data sources table 2015-10-27 23:26:11 -05:00
ubhatnagar
dc4f347ae1 Added relative checkbox 2015-10-27 13:40:50 -07:00
Jari Sukanen
23599814a3 cloudwatch: add support for defining AWS profile for CloudWatch datasource
Add support for defining AWS profile for CloudWatch datasource to support
pulling information from multiple different AWS accounts to single dashboard.

With this change, it is possible to define multiple AWS credentials in
~/.aws/credentials file and connect different data sources to different
AWS accounts.
2015-10-27 17:00:02 +02:00
Torkel Ödegaard
89ce1a5159 fix(dashlist): minor fix to dashlist panel, and some minor html markup fixes 2015-10-27 13:17:28 +01:00
Torkel Ödegaard
22a4ef42fc version change to 2.5-pre2 2015-10-27 12:22:30 +01:00
Torkel Ödegaard
358ba395ac fix(invite): minor fix to invite partials markup 2015-10-27 12:09:14 +01:00
Torkel Ödegaard
e7d5ea8a6c fix(build): revert some build script changes to make building on go 1.4 work again 2015-10-27 12:08:56 +01:00
Torkel Ödegaard
a36711e640 fix(changelog): fixed link in changelog 2015-10-27 10:26:44 +01:00
ubhatnagar
2b6df412b7 Removed export/view permission from a dashboard viewer 2015-10-26 23:20:47 -07:00
Torkel Ödegaard
6fabff4769 Merge pull request #3049 from utkarshcmu/docs
Fixed typos in cloudwatch docs
2015-10-27 07:14:41 +01:00
ubhatnagar
6af86152e6 Removed typos in cloudwatch docs 2015-10-26 21:02:04 -07:00
Torkel Ödegaard
06d97c78c8 Merge pull request #3044 from mattttt/patch-5
Updates to timepicker docs for 2.5 release
2015-10-26 21:22:22 +01:00
Matt
da31fffb16 Update timerange.md 2015-10-26 14:05:44 -04:00
Matt
c97e3ec7ae Updates to timepicker docs for 2.5 release
Updated images to be in separate PR.
2015-10-26 14:03:26 -04:00
Torkel Ödegaard
09b3433e32 change(dashboards): made home dashboard and json file dashboards editable unless otherwise specified in json file, closes #2567 2015-10-26 18:54:32 +01:00
Torkel Ödegaard
323e84375b refactoring: minor refactoring and handling of known data source plugins 2015-10-26 16:37:45 +01:00
Torkel Ödegaard
3b67a6a222 changelog: updated changelog with details of #2928 2015-10-26 16:23:29 +01:00
Torkel Ödegaard
da3d5375b8 feat(ldap): refactoring of PR #2928 updated docs 2015-10-26 16:21:03 +01:00
Torkel Ödegaard
38bd0d1aec Merge branch 'ldap-improvements' of https://github.com/abligh/grafana into abligh-ldap-improvements 2015-10-26 15:56:21 +01:00
Torkel Ödegaard
59bd029e46 docs(cloudwatch): minor cloudwatch fix 2015-10-26 15:51:34 +01:00
Torkel Ödegaard
1dbf0ad976 docs(cloudwatch): initial cloudwatch docs, closes #2900 2015-10-26 15:44:14 +01:00
Torkel Ödegaard
3b4c095b49 Merge branch 'time-independent-prometheus-metrics' of https://github.com/arthurdandrea/grafana into arthurdandrea-time-independent-prometheus-metrics 2015-10-26 14:35:17 +01:00
Torkel Ödegaard
2e155bdeda fix(dashboard): minor function name fixes, removed insert row above/below because it did not work, #2909 2015-10-26 14:33:55 +01:00
Torkel Ödegaard
8305fd0451 Merge branch 'master' of github.com:grafana/grafana 2015-10-26 14:21:49 +01:00
Torkel Ödegaard
7477667df1 docs(elasticsearch): initial elasticsearch docs, closes #2862 2015-10-26 14:21:38 +01:00
Torkel Ödegaard
a066d7ddcb Merge pull request #2909 from utkarshcmu/title
Added move row to top and bottom and insert row capability.
2015-10-26 14:15:42 +01:00
Torkel Ödegaard
a5c742cee5 docs(elasticsearch): began work on elasticsearch docs #2862 2015-10-26 13:36:00 +01:00
Torkel Ödegaard
cac142b134 Merge pull request #2937 from mtanda/scripted_datemath
Use dateMath in ScriptedDashboard
2015-10-26 12:51:09 +01:00
Torkel Ödegaard
da7ae2b0ab fix(build/aws): updated aws dependency and fixed minor build issue, fixes #3026 2015-10-26 12:48:30 +01:00
Torkel Ödegaard
052c9aca15 Merge branch 'master' of github.com:grafana/grafana 2015-10-26 12:16:13 +01:00
Felix Barnsteiner
e4fecb48e3 Add ability to set a global time interval
The interval is configurable in the data source.
This commit only adds the ability to Elasticsearch datasources
2015-10-26 08:47:46 +01:00
Torkel Ödegaard
b0e975bfce Merge pull request #3025 from utkarshcmu/docs
Added OpenSuse documentation
2015-10-26 08:22:52 +01:00
Torkel Ödegaard
d4664507f1 Merge pull request #3029 from mlbarrow/patch-1
Fix small typo in docs for InfluxDB (influxdb.md)
2015-10-26 08:22:34 +01:00
mlbarrow
21f3f859b9 Update influxdb.md
Typo fix
2015-10-24 20:58:19 -07:00
Utkarsh Bhatnagar
54be4c5e2c Made installation doc consistent 2015-10-23 23:21:00 -07:00
ubhatnagar
45cdbe0a18 Rearranged installation docs for OpenSuse 2015-10-23 23:03:58 -07:00
ubhatnagar
6c76e9728e Added OpenSuse installation command 2015-10-23 22:53:30 -07:00
Arthur D'Andréa Alemar
0a6a3f9ab7 fix(prometheus): use time independent API to list metrics and labels names
Using the "/api/v1/query" endpoint to extract information about metrics
and labels are limited to the metrics available at the time parameter
(that is set to current time), this can lead to labels not showing
because they have no value in the current time even when the dashboard
is displaying historic data.

On the other hand "/api/v1/series" returns results including every
metric and label known to Prometheus, independent of time and value.
2015-10-23 17:18:34 -02:00
Torkel Ödegaard
bad8ab232d Merge pull request #3020 from utkarshcmu/docs
Fixed 3014
2015-10-23 17:40:29 +02:00
Torkel Ödegaard
91a814d295 Merge pull request #3017 from volter/master
"No limit" was not effective for ES terms aggregation
2015-10-23 17:39:44 +02:00
ubhatnagar
7205cf8ce1 Fixed 3014 2015-10-23 07:29:15 -07:00
Torkel Ödegaard
6fe6a33da3 Merge pull request #3019 from sathieu/patch-2
Fix LimitNOFILE in RPM systemd unit
2015-10-23 16:17:45 +02:00
Torkel Ödegaard
9b59fc1c94 Merge pull request #3018 from sathieu/patch-1
Fix LimitNOFILE in Debian systemd unit
2015-10-23 16:17:28 +02:00
Mathieu Parent
e7834b885a Fix LimitNOFILE in RPM systemd unit 2015-10-23 15:13:41 +02:00
Mathieu Parent
4ec6691ea9 Fix LimitNOFILE in Debian systemd unit 2015-10-23 15:12:52 +02:00
Volker Fröhlich
6b9b08da30 Remove declaration of unused variable size 2015-10-23 12:00:20 +02:00
Volker Fröhlich
184307816f "No limit" was not effective for ES terms aggregation
This may belong to #2827
2015-10-23 11:40:40 +02:00
Mitsuhiro Tanda
c1d592b72c fix, call linkToPrometheus() directly 2015-10-23 09:58:42 +09:00
Torkel Ödegaard
2d23251da9 spelling: fixed selling in influxdb annotation partial, fixes #3012 2015-10-22 18:24:43 -04:00
Torkel Ödegaard
5b01e9ec97 fix(elasticsearch): minor fix to elasticsearch unit tests so that they work in any timezone, fixes #3010 2015-10-22 16:58:31 -04:00
Torkel Ödegaard
8526230b59 fix(influxdb_08): fixed influxdb 08 query editor issue, fixes #3009 2015-10-22 16:53:34 -04:00
Torkel Ödegaard
9d04a4c4f0 Merge branch 'master' of github.com:grafana/grafana 2015-10-22 16:23:31 -04:00
Torkel Ödegaard
ae93f2b936 fix(elasticsearch): fixed proper json escaping for lucene query, fixes #2981 2015-10-22 16:23:21 -04:00
Mitsuhiro Tanda
fcaecf4782 revert prometheus link 2015-10-23 01:35:34 +09:00
Torkel Ödegaard
0b28db7fae Merge pull request #3005 from felixbarny/elastic_ds_min_interval
Ability to set a low limit for Elasticsearch date histogram interval
2015-10-22 12:35:23 -04:00
Torkel Ödegaard
87715d6231 fix(solo panel): fixed solo panel view gray bottom for rendered image and embedd iframe scenarios, fixes #3004 2015-10-22 12:33:42 -04:00
Torkel Ödegaard
3228c4f41a changelog: updated with info about new units PR #2955 2015-10-22 12:27:22 -04:00
Torkel Ödegaard
ce5b4089b5 Merge branch 'new-units' of https://github.com/counsyl/grafana into counsyl-new-units 2015-10-22 12:19:21 -04:00
Torkel Ödegaard
0903aa4596 Merge pull request #2980 from tdyas/linkSrv_fix_query_string_appending
fix appending query strings in linkSrv
2015-10-22 12:18:27 -04:00
Torkel Ödegaard
26a45c8dc0 Merge pull request #3000 from utkarshcmu/docs
Fixed docs typos
2015-10-22 12:14:06 -04:00
Torkel Ödegaard
62c908a905 fix(build): fixed partials so they are included in optimized js file, fixes #2997 2015-10-22 10:02:29 -04:00
Felix Barnsteiner
eb8c2d9053 Ability to set a low limit for Elasticsearch date histogram interval
closes #2901
2015-10-22 13:16:36 +02:00
ubhatnagar
1e2e4ba3ad Fixed other docs typos 2015-10-21 22:09:07 -07:00
ubhatnagar
aaf4b1a399 Fixed typos in guides. 2015-10-21 21:13:39 -07:00
ubhatnagar
a5e3d7a94b Fixed datasources docs typos 2015-10-21 20:58:04 -07:00
Torkel Ödegaard
58497ed596 feat(panel): performance improvement for loading panels, closes #2994 2015-10-21 11:22:53 -04:00
Torkel Ödegaard
ae81fbdffe Merge branch 'master' of github.com:grafana/grafana 2015-10-21 10:59:17 -04:00
Torkel Ödegaard
fc0705e87c fix(elasticsearch): fix for daily pattern when getting index for today, is now using utc, fixes #2913 2015-10-21 10:59:02 -04:00
Torkel Ödegaard
c489d806dc Merge pull request #2995 from peekeri/fix_influxdb_annotation_query
influxdb: fix influxdb annotation query
2015-10-21 10:34:29 -04:00
Jari Sukanen
f3ecdc5af4 influxdb: fix influxdb annotation query 2015-10-21 14:31:06 +03:00
Torkel Ödegaard
6fecb4bf3e fix(http route): fixed dashboard-solo route to not return 404, fixes #2979 2015-10-20 10:02:56 -04:00
Tom Dyas
867ac5df67 fix appending query strings in linkSrv
When linkSrv appends parameters to a URL's query string, it would blindly
add a ? to the URL even if the URL already contained a ? or the string
to add was empty. This change fixes that behavior and some other edge cases.

Includes a unit test to verify expected behavior.
2015-10-19 13:11:34 -04:00
Torkel Ödegaard
1ff3c3be84 Merge pull request #2952 from Krinkle/fixup
docs(): Fix changelog link in whats-new-in-v2-1
2015-10-17 12:44:09 -04:00
Torkel Ödegaard
1cb9de07a6 Merge pull request #2962 from damm/docs_spellcheck
I noticed a typo when I was reviewing the docs ...
2015-10-17 12:41:25 -04:00
Torkel Ödegaard
43ca50ebbe fix(build): anonther minor build script fix 2015-10-16 13:03:20 -04:00
Torkel Ödegaard
b70b730cb9 fix(build): minor fix for build script to make latest copy for rpm when version is pre release version 2015-10-16 12:26:30 -04:00
Torkel Ödegaard
dbc1a9cf82 fix(influxdb_0.8.x): fixed issue with new timepicker ranges like The day so far, fixes #2936 2015-10-16 12:07:35 -04:00
Torkel Ödegaard
c95a991cb3 fix(panel/common): fix for query letters when importing old dashboards, fixes #2943 2015-10-16 11:58:44 -04:00
Torkel Ödegaard
c320e9d583 fix(annotations): fixed graphite annotations, broken by recent time handling changes, fixes #2947 2015-10-16 11:07:15 -04:00
Torkel Ödegaard
e507afc3d5 fix(panel): fix for firefox and placing cursor in text inputs when in panel fullscreen edit mode, fixes #2957 2015-10-16 10:10:39 -04:00
Scott M. Likens
bd77fd92bb I'm not sure what a dashboard is ... 2015-10-15 19:45:40 -07:00
Greg Look
882a988143 Add currency units from #1910. 2015-10-15 12:48:48 -07:00
Greg Look
0b3e33e226 Shorten percent unit labels. 2015-10-14 15:40:04 -07:00
Greg Look
524f5d45ec Add test for unit menu structure. 2015-10-14 14:51:42 -07:00
Greg Look
85887ad1cf Add mile, fix menu values. 2015-10-14 14:51:33 -07:00
Greg Look
d94b6635af Add temperature and pressure units, split submenus. 2015-10-14 14:50:45 -07:00
Greg Look
3c7a483f5c Add length and volume units. 2015-10-14 14:14:25 -07:00
Greg Look
dc5c3a3939 Implement decibel and percentunit units.
Add tests to exercise new units as well.
2015-10-14 14:02:29 -07:00
ubhatnagar
9185c94a2d Added insert row option in the row menu. 2015-10-14 13:45:47 -07:00
Greg Look
70269c8196 Reformat unit menu definition. 2015-10-14 13:34:48 -07:00
Greg Look
51a589f5a6 Change formatFuncCreator to scaledUnits builder.
Abstract out both decimal and binary SI prefixes into builders using
scaledUnits.
2015-10-14 13:18:02 -07:00
Anthony Woods
cf89b565a6 initial import of thirdParty route support 2015-10-15 04:14:09 +08:00
Greg Look
7d24c5fda2 Add fixedUnit format builder. 2015-10-14 13:07:34 -07:00
Greg Look
0bc85d27f8 Group rounding and fixed number functions. 2015-10-14 12:56:31 -07:00
Greg Look
43c2ca2d7d Group value formats by type. 2015-10-14 12:51:59 -07:00
Greg Look
e3e21a251f Group helper functions in kbn.js. 2015-10-14 12:41:20 -07:00
Timo Tijhof
267417d6a8 docs(): Fix changelog link in whats-new-in-v2-1
The quotes turn the value into a title attribute rather than href attribute,
thus on http://docs.grafana.org/guides/whats-new-in-v2-1/ this link was
rendered as <a href title="https://github.com/...">CHANGELOG.md</a>
which when clicked goes back to itself (not to GitHub).
2015-10-14 14:00:25 -04:00
Alex Bligh
e8256f0ad7 Add support for POSIX LDAP schema
In the POSIX LDAP schema, there is no 'memberOf' attribute returned
in relation to which groups a person is a member of. Rather, it is
necessary to query the group objects which have the people as members.
This commit adds an additional filter, which if specified explicitly
searches for groups, rather than relying on the 'memberOf' attribute.
This enables Grafana to work with LDAP POSIX schema (e.g. OpenLDAP
etc.)

Signed-off-by: Alex Bligh <alex@alex.org.uk>
2015-10-13 19:51:59 +01:00
Alex Bligh
458e6da700 Allow user specified CA certs
Signed-off-by: Alex Bligh <alex@alex.org.uk>
2015-10-13 19:47:24 +01:00
Alex Bligh
a906fa178a Support multiple space-separated LDAP hosts
Signed-off-by: Alex Bligh <alex@alex.org.uk>
2015-10-13 19:46:53 +01:00
Mitsuhiro Tanda
4588c5a19a pass dateMath to ScriptedDashboard script 2015-10-13 12:29:42 +09:00
Nick Christus
23404decea added global alerts list stub and styles 2015-10-11 16:59:40 -04:00
Torkel Ödegaard
e873574e8c fix(logging): fixed so that router_logging = true actually logs all http requests, fixes #2902 2015-10-10 17:55:15 -04:00
Torkel Ödegaard
d09bff9039 fixed failing jshint 2015-10-10 15:11:58 -04:00
Torkel Ödegaard
c0da52aac8 fix(share): fixed share panel image url, did not generate correct url when domain name contained word dashboards, fixes #2916 2015-10-10 14:38:22 -04:00
Nick Christus
7e2f653bc7 added alerting tab stub and styles 2015-10-10 14:17:07 -04:00
Torkel Ödegaard
c831369974 fix(influxdb): influxdb data source did not use right http abstraction for metric queries, fixes #2919 2015-10-10 11:46:00 -04:00
Torkel Ödegaard
f0a13b2a0d Merge pull request #2914 from anryko/master
Fixed configuration example for Github OAuth team_ids.
2015-10-10 16:26:28 +02:00
anryko
b68987dcde Fixed configuration example for Github OAuth team_ids. 2015-10-09 17:05:46 +02:00
Torkel Ödegaard
c1f77eeaea Merge branch 'master' of github.com:grafana/grafana 2015-10-09 08:28:48 +02:00
Torkel Ödegaard
9b5a0a54cf minor docs fix 2015-10-09 08:28:33 +02:00
ubhatnagar
14f3a68215 Added move row to top and bottom. 2015-10-09 03:06:52 +05:30
Torkel Ödegaard
bf25b9f443 Merge pull request #2896 from garymcleanhall/fix-grafana-on-microsoft-edge
Removed spurious `</div>`, fixes Edge on Windows
2015-10-08 21:29:23 +02:00
Torkel Ödegaard
3435aaea45 fixed failing unit test 2015-10-08 17:39:06 +02:00
Torkel Ödegaard
9fc91b7aa1 fixed gofmt issue 2015-10-08 17:30:13 +02:00
Torkel Ödegaard
04eefb8480 fix(timepicker): fixed issue with timepicker and auto refresh and entering manual time when timepicker dropdown is open, fixes #2897 2015-10-08 15:35:17 +02:00
Torkel Ödegaard
8789be7671 Merge branch 'master' of github.com:grafana/grafana 2015-10-08 13:30:11 +02:00
Torkel Ödegaard
fe46410c31 Merge branch 'cloudwatch' 2015-10-08 13:09:27 +02:00
Torkel Ödegaard
aef644bd21 feat(cloudwatch): final polish to the cloudwatch editor, closes #684 2015-10-08 13:09:15 +02:00
Torkel Ödegaard
df4d5ea8a6 Merge pull request #2898 from zachm/ztm_patch_missing_downsample
Fix missing downsampling name in kairos plugin
2015-10-08 12:05:20 +02:00
Torkel Ödegaard
c34c3ac845 feat(cloudwatch): refactoring and editor improvements, #684 2015-10-08 11:37:47 +02:00
Julien Maitrehenry
4bb656b704 #2834 - follow symlink 2015-10-08 00:22:09 -04:00
Zachary Musgrave
a94720878b Fix missing downsampling name in kairos plugin 2015-10-07 16:43:40 -07:00
Gary McLean Hall
59a2042a31 Removed spurious </div>, fixes Edge on Windows 2015-10-08 00:14:00 +01:00
Torkel Ödegaard
f680c15283 fix(snapshot): fixed issue with timepicker / time display when viewing snapshot, fixes #2892 2015-10-07 13:07:30 +02:00
Torkel Ödegaard
f11785001c docs: minor fix 2015-10-06 17:51:22 +02:00
Torkel Ödegaard
106fe4854f Merge branch 'prometheus' of github.com:grafana/grafana
Conflicts:
	pkg/models/datasource.go
	public/app/plugins/datasource/prometheus/datasource.js
	public/app/plugins/datasource/prometheus/partials/query.editor.html
	public/app/plugins/datasource/prometheus/queryCtrl.js
2015-10-06 16:36:58 +02:00
Torkel Ödegaard
44d377b810 feat(prometheus): refactoring and polish of the prometheus editor removing unused/uneeded code 2015-10-06 14:34:44 +02:00
Torkel Ödegaard
a2bf3e056d Merge branch 'prometheus' 2015-10-06 14:10:06 +02:00
Torkel Ödegaard
2d722e26de fix(cloudwatch): fixed test datasource, broken due to some function name changes 2015-10-06 14:08:48 +02:00
Torkel Ödegaard
182e079d25 Merge branch 'master' into cloudwatch 2015-10-06 14:08:10 +02:00
Torkel Ödegaard
318af9b418 small docs structure change, moved build from source into install section and CLA into project, and about into project 2015-10-06 10:38:19 +02:00
Torkel Ödegaard
0bcda4a2eb minor elasticsearch fix 2015-10-05 11:17:53 +02:00
Ivan Babrou
0dc0e03c4c Add suggest_tagk() and suggest_tagv() to OpenTSDB datasource (#2840) 2015-10-04 12:54:43 +01:00
Torkel Ödegaard
0db2d07a1a Merge pull request #2871 from mtanda/prometheus_time_fix
fix prometheus time conversion
2015-10-03 12:50:05 +02:00
Torkel Ödegaard
3d52095765 feat(cloudwatch): restored dimension keys lookup 2015-10-02 20:25:28 +02:00
Torkel Ödegaard
0912cec0e5 feat(cloudwatch): contining work on moving hard coded stuff to backend and cleaning up code, #684 2015-10-02 11:54:35 +02:00
Torkel Ödegaard
180ba33ac8 feat(cloudwatch): refactoring and cleanup of backend code, started moving hard coded stuff in the frontend to the backend, changed name of metricFind queries region() -> regions() , and namespace() -> namespaces() to be more consistent with the others, #684 2015-10-02 11:10:21 +02:00
Torkel Ödegaard
04f4454974 feat(cloudwatch): lots of code refactoring and cleanup, #684, dimension values lookup works but seems to return all dimension values no matter what dimension key you select, removed strange formating of template dimension values query, should not return key value pair but only the dimension value 2015-10-02 09:04:46 +02:00
Torkel Ödegaard
91285baea5 feat(cloudwatch): fixed failing unit tests 2015-10-02 07:32:21 +02:00
Torkel Ödegaard
875d80aa72 feat(cloudwatch): refactoring cloudwatch datasource code, #684 2015-10-02 07:25:54 +02:00
Mitsuhiro Tanda
5e19fdb492 fix prometheus time conversion 2015-10-02 12:10:11 +09:00
Torkel Ödegaard
bddcc6491a Merge pull request #2870 from ctdk/strip-format
Add config option to strip (most) colors from console logs
2015-10-01 22:31:21 +02:00
ctdk
d37e18fdcf Add config option to strip (most) colors from console logs 2015-10-01 13:16:23 -07:00
Torkel Ödegaard
af8d12124a feat(cloudwatch): code refactoring and cleanup, trying to rewrite so the code uses promises instead of ccallbacks, #684 2015-10-01 21:20:52 +02:00
Torkel Ödegaard
5e34823e7c Merge pull request #2858 from mtanda/prometheus
fix unmatched tag
2015-10-01 18:47:21 +02:00
Torkel Ödegaard
f44eaae88a Merge pull request #2867 from juliusv/fix-prometheus-link
Fix "Link to Prometheus" button for proxied Prometheus sources.
2015-10-01 18:43:19 +02:00
Julius Volz
3cc69112c1 Fix "Link to Prometheus" button for proxied Prometheus sources. 2015-10-01 18:23:29 +02:00
Torkel Ödegaard
205d4232b9 feat(cloudwatch): only support proxy mode, can remove frontend aws-sdk lib 2015-10-01 17:38:55 +02:00
Torkel Ödegaard
3c6a06a327 feat(cloudwatch): moved specs into plugins dir 2015-10-01 17:00:41 +02:00
Torkel Ödegaard
057b533a39 Merge branch 'master' into cloudwatch 2015-10-01 16:46:59 +02:00
Torkel Ödegaard
b774b91b92 Merge branch 'cloudwatch' of https://github.com/mtanda/grafana into cloudwatch
Conflicts:
	public/test/specs/cloudwatch-datasource-specs.js
2015-10-01 16:41:54 +02:00
Torkel Ödegaard
7dc923a292 fix(timepicker): fixed displaying of customk time ranges, #2861 2015-10-01 16:36:38 +02:00
Torkel Ödegaard
ef2094f817 feat(influxdb): minor progress on #2802 2015-10-01 15:48:45 +02:00
Torkel Ödegaard
f0f791d226 Merge pull request #2859 from tmonk42/graphite_multiplySeries
add graphite multiplySeries function
2015-10-01 08:39:22 +02:00
Haneysmith, Nathan
7ca261e33e add graphite multiplySeries function 2015-09-30 11:18:47 -07:00
Torkel Ödegaard
228aac2d48 Merge pull request #2857 from jimmidyson/prometheus-datasource
Prometheus fixes
2015-09-30 18:33:55 +02:00
Mitsuhiro Tanda
d0b744387b fix unmatched tag 2015-10-01 01:33:13 +09:00
Jimmi Dyson
7cadb9012a Switch to png image 2015-09-30 16:45:38 +01:00
Jimmi Dyson
0c222c4e8c Fix Prometheus test connection 2015-09-30 16:44:24 +01:00
Torkel Ödegaard
83052352dc feat(influxdb editor): lots of work on new editor, #2856 2015-09-30 17:16:34 +02:00
Torkel Ödegaard
73516c0c97 Merge pull request #2856 from jimmidyson/prometheus-datasource
Further Prometheus unit tests
2015-09-30 16:59:45 +02:00
Jimmi Dyson
b90e4057ba Convert prometheus specs to typescript 2015-09-30 15:52:15 +01:00
Jimmi Dyson
67f253830f Add Prometheus metricFindQuery unit tests 2015-09-30 14:20:58 +01:00
Jimmi Dyson
59dbe45784 Fix typo in docs 2015-09-30 14:20:58 +01:00
Torkel Ödegaard
f053b41645 feat(influxdb editor): more progress 2015-09-30 14:37:27 +02:00
Torkel Ödegaard
84615ad299 Merge pull request #2855 from jimmidyson/prometheus-datasource
Prometheus docs & better template queries
2015-09-30 13:50:11 +02:00
Jimmi Dyson
2e291d73aa jshint fixes 2015-09-30 12:46:44 +01:00
Jimmi Dyson
055efa3904 Add prometheus docs 2015-09-30 12:42:48 +01:00
Jimmi Dyson
daee7970f3 Add label_values query to get labels on a particular metric 2015-09-30 12:29:53 +01:00
Torkel Ödegaard
2dc8fcd3be poc(influxdb v3 editor): more testing of new influxdb editor approach 2015-09-29 21:32:15 +02:00
Torkel Ödegaard
2f55c18d56 Merge pull request #2847 from jimmidyson/prometheus-datasource
Add Prometheus datasource
2015-09-29 18:23:12 +02:00
Jimmi Dyson
cf0748895e Prometheus template params fixes 2015-09-29 17:07:11 +01:00
Jimmi Dyson
6e66b8a0fa Add prometheus datasource 2015-09-29 17:07:11 +01:00
Torkel Ödegaard
e70b99a706 poc: influxdb editor v3 test 2015-09-29 18:00:15 +02:00
Torkel Ödegaard
42e7a70d99 Merge pull request #2845 from sbouchex/master
Missing carriage return in init script when displaying usage
2015-09-29 16:43:52 +02:00
Torkel Ödegaard
ee85eb2779 Updated prometheus config 2015-09-29 16:22:41 +02:00
sbouchex
6c1adf9187 Missing carriage return when displaying usage 2015-09-29 16:06:40 +02:00
Torkel Ödegaard
81a660eae4 fix(phantomjs binary): fixed PR #2832 so that it works on linux, now phantomjs based server side rendershould work on mac and linux, maybe even windows 2015-09-29 15:36:13 +02:00
Torkel Ödegaard
8b029388a5 Merge branch 'phantomjs' of https://github.com/fg2it/grafana into fg2it-phantomjs 2015-09-29 15:22:37 +02:00
Torkel Ödegaard
c816ed2527 feat(usage stats): added data source count stats 2015-09-29 13:47:56 +02:00
Torkel Ödegaard
866ea7f942 added prometheus docker block 2015-09-29 08:16:26 +02:00
Torkel Ödegaard
d9d3da4def Merge branch 'prometheus-datasource' of https://github.com/jimmidyson/grafana into prometheus 2015-09-29 08:06:16 +02:00
Mitsuhiro Tanda
be6cb24e10 fix cloudwatch test 2015-09-29 13:26:04 +09:00
Mitsuhiro Tanda
1a63d9eb3b reactivate cloudwatch test 2015-09-29 12:37:34 +09:00
Jimmi Dyson
bf98cfeadc Add prometheus datasource 2015-09-28 23:15:33 +01:00
Torkel Ödegaard
8a39b32b5c refactor: moved elasticsearch specs to plugin folder and to typescript 2015-09-28 16:28:19 +02:00
Torkel Ödegaard
7d2646f60a refactor: moved influxdb specs to plugins folder 2015-09-28 15:51:02 +02:00
Torkel Ödegaard
1a8bc1dd60 fix(dashbard save as): fixed wonky behavior in save as modal, cursor to the end randomly, fixes #2837 2015-09-28 15:26:56 +02:00
Torkel Ödegaard
7e434fc019 refactor: moved graphite specs into plugins directory 2015-09-28 15:23:53 +02:00
Torkel Ödegaard
49d57cf596 feat(cloudwatch): uncommented tests, but they do not seemt to execute 2015-09-28 14:16:03 +02:00
Torkel Ödegaard
8dfbc55851 Merge branch 'cloudwatch' of https://github.com/mtanda/grafana into cloudwatch 2015-09-28 13:44:30 +02:00
Torkel Ödegaard
3cbfe21b2c Merge branch 'master' into cloudwatch 2015-09-28 13:43:03 +02:00
Torkel Ödegaard
cb7424ce5e fix(playlist ui): minor polish / fix to playlist ui, fixes #2831, other minor css / markup fixes 2015-09-28 11:53:49 +02:00
Torkel Ödegaard
a567939f78 fix(elasticsearch): quote variable value in lucene variable mulit format, fixes #2828 2015-09-28 11:28:08 +02:00
Torkel Ödegaard
a3748d4b97 fix(singestat): fixed missing sparklines, caused by recent changes to time range handling, fixes #2815 2015-09-28 09:28:43 +09:00
Torkel Ödegaard
b80dc92ca5 Merge branch 'master' of github.com:grafana/grafana 2015-09-27 12:09:45 +02:00
Torkel Ödegaard
57dee76c88 feat(elasticsearch): templating terms query should have size set to zero to return all terms, fixes #2827 2015-09-27 12:09:12 +02:00
fg2it
2513639499 fix for relative path 2015-09-26 11:38:37 +02:00
Mitsuhiro Tanda
9ae6ac25f5 refactor dataproxy_cloudwatch 2015-09-26 02:33:53 +09:00
Mitsuhiro Tanda
01ec8d0bcb fix cloudwatch time error 2015-09-26 02:33:52 +09:00
Mitsuhiro Tanda
d09e8a12b4 fix jshint error 2015-09-26 02:33:52 +09:00
Mitsuhiro Tanda
5dd64b97d2 refactor 2015-09-26 02:33:52 +09:00
Mitsuhiro Tanda
9600b1f103 add ebs_volume_ids() for templating 2015-09-26 02:33:51 +09:00
Mitsuhiro Tanda
ca9861e749 fix cloudwatch config editor 2015-09-26 02:33:51 +09:00
Torkel Ödegaard
38bf07f4da Merge pull request #2817 from utkarshcmu/axes
Single stat panel throws warning on multiple series result.
2015-09-25 10:23:10 +02:00
fg2it
189796891e adding phantomjs task to default and build 2015-09-25 01:19:49 +02:00
fg2it
8134905a86 new grunt task for setting phantomjs binary 2015-09-25 00:56:56 +02:00
fg2it
45fb760a35 removing default phantomjs binary 2015-09-25 00:51:54 +02:00
ubhatnagar
026fffa19f Singlestat Panel Error in InspectCtrl. 2015-09-24 23:13:05 +05:30
Torkel Ödegaard
9da5ef3cbf fix(singestat): fixed missing sparklines, caused by recent changes to time range handling, fixes #2815 2015-09-24 11:36:25 +02:00
ubhatnagar
ea7fe0c761 Single stat panel throws warning on multiple series result. 2015-09-24 09:40:09 +05:30
Torkel Ödegaard
25d7b8d08d feat(cloudwatch): resumed work on cloudwath datasource, #684, #2445 2015-09-23 21:13:19 +02:00
Torkel Ödegaard
f467cb8cd2 Merge branch 'master' of github.com:grafana/grafana 2015-09-23 20:57:50 +02:00
Torkel Ödegaard
f4e3c0a2e4 Revert "poc: some tests for new influxdb editor"
This reverts commit 075d01820c.
2015-09-23 20:57:29 +02:00
ubhatnagar
9cdf0601eb Removed unnecessary statement. 2015-09-23 22:20:38 +05:30
ubhatnagar
28ef972c9f Added duplicate feature for variable. 2015-09-23 22:13:38 +05:30
Torkel Ödegaard
c66476f6b6 Merge pull request #2810 from tuxinaut/master
Fix changelog formatting
2015-09-23 11:42:29 +02:00
Denny Schäfer
3f90220208 Fix changelog formatting 2015-09-23 11:35:20 +02:00
Torkel Ödegaard
81ebaae12e feat(opentsdb): templating, added default match format option, now new variables with opentsdb datasource will automatically use the new pipe format, #2808 2015-09-23 11:18:56 +02:00
Torkel Ödegaard
71984b25e9 Merge pull request #2808 from utkarshcmu/master
Implemented Opentsdb MultiSelect Templating.
2015-09-23 11:16:01 +02:00
Torkel Ödegaard
4100c9881a fix(panel): fixed selecting text in fullscreen edit mode 2015-09-23 10:03:30 +02:00
Torkel Ödegaard
075d01820c poc: some tests for new influxdb editor 2015-09-23 09:58:36 +02:00
ubhatnagar
6f43cbf665 Added unit tests for all and multi format options. 2015-09-23 13:24:59 +05:30
ubhatnagar
866f48f92d Added pipe in All Format list. 2015-09-23 13:12:35 +05:30
Torkel Ödegaard
2790e4e819 change(influxdb): removed derivative functions from aggregator list 2015-09-23 09:40:53 +02:00
Torkel Ödegaard
8bb2b5e290 fix(influxdb): have alias field visible when using raw query mode, fixes #2803 2015-09-23 09:34:05 +02:00
Torkel Ödegaard
63290d0f5d changelog: added OpenTSDB enhancement fetch aggregators from OpenTSDB to the changelog, #1646 2015-09-23 09:19:21 +02:00
Torkel Ödegaard
5c55617585 refactor: polishing OpenTSDB related PR #1646, added caching of aggregators request so only one call is made 2015-09-23 09:17:37 +02:00
Torkel Ödegaard
0e0caabf7d Merge branch 'master' of https://github.com/mxk1235/grafana into mxk1235-master 2015-09-23 09:08:29 +02:00
ubhatnagar
024a319512 Implemented Opentsdb MultiSelect Templating. 2015-09-23 11:22:57 +05:30
Torkel Ödegaard
f632b3b029 feat(elasticsearch): added new templating all format and muli format named , also added automatic setting of correct all and multi format depending on data source, closes #2696 2015-09-22 14:29:41 +02:00
Torkel Ödegaard
b37f9a7db0 fix(graphite): minor fix to query editor when using summarize function with no metric segments, only series ref, fixes #2788 2015-09-22 13:32:28 +02:00
Torkel Ödegaard
6f9c306260 fix(singlestat): fixed usage of template variable in drilldown link for singlestat, fixes #2787 2015-09-22 12:48:03 +02:00
Torkel Ödegaard
c369350ca7 Merge branch 'master' of github.com:grafana/grafana 2015-09-22 09:32:13 +02:00
Torkel Ödegaard
bc3c394210 feat(elasticsearch): worked on elasticsearch templating support, #2696 2015-09-22 09:31:58 +02:00
Torkel Ödegaard
e9df31b650 Merge pull request #2799 from utkarshcmu/master
Fixed #2798. Removed unused components.
2015-09-22 08:50:00 +02:00
ubhatnagar
e49bb1ccc0 Fixed #2798. Removed unused components. 2015-09-22 12:16:10 +05:30
Torkel Ödegaard
0ef8e086a2 fixed(share modal): fixed issue with sharemodal introduced with recent change to time handling, #2791 2015-09-22 07:32:47 +02:00
Torkel Ödegaard
63665dccae fix(grafana datasource): fixed the built in test data source, fixes #2795 2015-09-22 07:12:36 +02:00
Torkel Ödegaard
792b194d0e feat(elasticsearch): finished work on adding support for filters aggregate, you can now split series by query using group by filters, closes #2785 2015-09-21 20:29:05 +02:00
Torkel Ödegaard
e694a74c9d feat(elasticsearch): work on supporting filters aggregate, #2785 2015-09-21 19:23:18 +02:00
Torkel Ödegaard
9de016bfe3 feat(elasticseach): alias and lucene query fields are now visible/usable when using raw json query, #1034 2015-09-21 12:07:03 +02:00
Torkel Ödegaard
3eddfc028e Merge branch 'patch-2' of https://github.com/cagdascirit/grafana 2015-09-21 11:32:36 +02:00
Torkel Ödegaard
2125648798 Merge branch 'master' of https://github.com/tuxinaut/grafana 2015-09-21 11:31:25 +02:00
Torkel Ödegaard
24bff6e04d ui(dashboard cog icon): minor change to PR #2772 that adds tooltip to cog icon 2015-09-21 11:29:14 +02:00
Torkel Ödegaard
cdab0d208e Merge branch 'master' of https://github.com/utkarshcmu/grafana into utkarshcmu-master 2015-09-21 11:16:50 +02:00
Torkel Ödegaard
20f04ab352 fix(build): fixed requirejs optimized build 2015-09-21 09:36:17 +02:00
Torkel Ödegaard
7f1af24318 fix(ldap): fixed ldap org roles sync, did only add one new role per login, now all roles are added, fixes #2766 2015-09-21 09:19:50 +02:00
Torkel Ödegaard
8d87db58c6 docs(): added link to external install tutorial / article 2015-09-21 09:04:59 +02:00
Torkel Ödegaard
feae4c6c8b fix(ldap): fixed syncing of email and name from ldap, fixes #2765 2015-09-21 09:02:52 +02:00
ubhatnagar
00c89b8354 Removed .jshintrc statement, implemented manage dashboard tooltip. 2015-09-21 08:09:34 +05:30
Torkel Ödegaard
fb767f5680 change: removed drilldown links from extended panel menu 2015-09-19 15:59:29 +02:00
Torkel Ödegaard
c7d22aafd2 feat(drilldown link): better access to drilldown links directly by clicking the external link icon in panel header, fixes #1575 2015-09-19 15:53:48 +02:00
Torkel Ödegaard
b5f237a69b fix(graph): minor fix for hover tooltip when combined with a single series using stepped lines, fixes #2754 2015-09-19 15:20:53 +02:00
Torkel Ödegaard
b4093ccf59 fix(graphite): minor fix to editor, add function dropdrop extended above page, fixes #1152 2015-09-19 14:58:52 +02:00
Torkel Ödegaard
a23217cc6f fix(influxdb): clear existing Authorization header when proxying request to InfluxDB, fixes #2778 2015-09-19 12:32:35 +02:00
Torkel Ödegaard
f4f7f47901 changelog: updated changelog with info about timepicker feature 2015-09-19 12:26:21 +02:00
Torkel Ödegaard
2f68687de9 feat(timepicker2): temporarily removed the the option to define custom quick range, will have to be part of future issue, closes #2761 2015-09-19 12:20:24 +02:00
Torkel Ödegaard
86f4907cc4 feat(panel fullscreen): completly changed how the fullscreen view/edit works, no longer uses css fixed position, yay, closes #2779 2015-09-19 11:40:51 +02:00
Torkel Ödegaard
bffb795d7a feat(timepicker): small style change for timepicker 2015-09-19 10:54:17 +02:00
Torkel Ödegaard
c21cffa6d4 fix(timepicker): UTC now works in all scenarios I can think of, manual edit, date picker edit, #2761 2015-09-18 21:01:13 +02:00
Torkel Ödegaard
96b0e70ddd feat(timepickerv2): fixed lots of minor issues and updated kairosdb and opentsdb data sources to work with the new date formats 2015-09-18 15:06:08 +02:00
Torkel Ödegaard
febe56b062 feat(timepicker): fixed zoomout 2015-09-18 14:04:53 +02:00
Torkel Ödegaard
f5e6722826 feat(timepickerv2): more work on new timepicker, now absolute time mixed with relative time works, yesterday, this day last week, etc now work 2015-09-18 13:54:31 +02:00
Torkel Ödegaard
cea13b1823 feat(timepicker2): moved to controllerAs and bindToController for timepicker component 2015-09-18 12:41:32 +02:00
Torkel Ödegaard
3d85e85f29 fix(events): fixed handling of onAppEvents when used from rootScope, must supply localscope, can now be used in isolate scope scenarios 2015-09-18 12:15:06 +02:00
ubhatnagar
923df8244b Search Dashboard Panel will hide if 'Manage Dashboards' is clicked. 2015-09-18 02:30:02 -07:00
Torkel Ödegaard
69db9e0d45 feat(timepickerV2): absolute time / calendar picker works, #2761 2015-09-18 11:01:37 +02:00
Denny Schäfer
d1534d4dcf Fix changelog (double issue entry and missing version headline) 2015-09-18 10:46:04 +02:00
Torkel Ödegaard
a8a94ef87b Merge branch 'master' into timepicker2 2015-09-18 10:36:50 +02:00
Torkel Ödegaard
f93215f4ec feat(timepicker2): more progress 2015-09-18 10:36:47 +02:00
ubhatnagar
9af460600d Fixed Indentation and Grunt run. 2015-09-18 00:50:55 -07:00
ubhatnagar
e1576b7131 Added Manage Dashboard Tooltip, hides when clicked. 2015-09-18 00:45:29 -07:00
Torkel Ödegaard
5d05de8bda Merge branch 'master' of github.com:grafana/grafana 2015-09-18 08:39:06 +02:00
Torkel Ödegaard
5e949b0564 fix(quota): fixed failing quota unit tests 2015-09-18 08:36:58 +02:00
Torkel Ödegaard
2a52d9bdf6 feat(timepicker2): more work on new timepicker 2015-09-18 08:17:19 +02:00
Torkel Ödegaard
ebf49d0668 Merge pull request #2771 from decbis/maxSeries-func-for-groupByNode
Added maxSeries option for groupByNode Graphite function
2015-09-18 08:16:46 +02:00
Torkel Ödegaard
f42955ab99 Merge pull request #2755 from Dieken/patch-1
fix duplicate tag value suggestions and relax limit on /api/search/lookup
2015-09-18 08:08:18 +02:00
Mike Kobyakov
5d516592d9 Merge remote-tracking branch 'upstream/master' 2015-09-17 23:07:52 -07:00
Eugen Dinca
7dc2b36413 Added maxSeries option for groupByNode function 2015-09-17 16:50:09 -04:00
Torkel Ödegaard
5eefa36111 feat(timepickerv2): big progress on new design of new timepicker, #2761 2015-09-17 22:44:59 +02:00
Cagdas Cirit
c26209d579 Update debian.md 2015-09-17 18:25:36 +02:00
Torkel Ödegaard
a30f73fe36 feat(timepicker): more work on getting new time formats to work in all data sources 2015-09-17 12:40:04 +02:00
Torkel Ödegaard
1a9c52e17f feat(timepicker): lots of big changes, moving to datemath from kbn.parseDateMath, moving to moment dates instead of native javascript dates 2015-09-17 11:21:38 +02:00
Torkel Ödegaard
5ad38ee9f8 feat(timepicker2): fixed timesrv specs 2015-09-17 09:57:59 +02:00
Torkel Ödegaard
4c79591403 fix(graphite): removed debug comment 2015-09-17 09:45:53 +02:00
Torkel Ödegaard
a9812167d7 feat(timepicker2): worked on more rich time range support 2015-09-17 09:44:51 +02:00
raj dutt
a7cc36f741 Update CHANGELOG.md 2015-09-16 23:50:02 -04:00
raj dutt
4c0262cbd0 Update CHANGELOG.md 2015-09-16 23:46:48 -04:00
Torkel Ödegaard
a0a98cb035 feat(timepicker2): working on richer timepicker options 2015-09-16 19:49:05 +02:00
Liu Yubao
4fccfbf543 increase limit to lookup unique metric tag values
Default limit is 25 which is too small. Considering currently the
/api/search/lookup query isn't narrowed down by selected tag
keys and values (see https://github.com/grafana/grafana/pull/1433), 
the limit is set to 3000, this should be fine because people rarely
create new graph panel.
2015-09-17 01:36:36 +08:00
Liu Yubao
62ae80eeae deduplicate tag value suggestions for OpenTSDB 2015-09-17 01:25:28 +08:00
Torkel Ödegaard
d705108be5 feat(timepicker2): added date math tests 2015-09-16 18:48:41 +02:00
Torkel Ödegaard
3912eb7b26 Merge branch 'master' into timepicker2 2015-09-16 17:03:08 +02:00
Torkel Ödegaard
1f959272c5 feat(migration): added back support to import old dashboard from from Elasticsearch 2015-09-16 16:28:41 +02:00
Torkel Ödegaard
f9cd942363 Merge branch 'master' of github.com:grafana/grafana 2015-09-16 15:17:57 +02:00
Torkel Ödegaard
1282da52eb Merge pull request #2750 from elliot/patch-1
Fixed 404 error for robots.txt
2015-09-16 12:09:56 +02:00
Elliot Anderson
10c099a52d Fixed 404 error for robots.txt 2015-09-16 11:02:50 +10:00
Torkel Ödegaard
fa0542ca8b Merge branch 'quotas' of https://github.com/raintank/grafana into raintank-quotas 2015-09-15 14:33:21 +02:00
woodsaj
3926226417 fix getting default quota as map[string]int64 2015-09-15 20:31:58 +08:00
Torkel Ödegaard
6a30511fc4 Merge branch 'quotas' of https://github.com/raintank/grafana into raintank-quotas 2015-09-15 14:23:13 +02:00
Torkel Ödegaard
4ffa26cf2c feat() started work on more feature rich time picker 2015-09-15 13:23:36 +02:00
woodsaj
1ad10914ce add quota middleware unittests 2015-09-15 18:19:47 +08:00
woodsaj
86ed85aa6e move toMap function to be a method on the quota structs 2015-09-15 17:18:26 +08:00
woodsaj
b7de847236 add unittests for quota sqltore methods. 2015-09-15 17:10:46 +08:00
woodsaj
3cf2cd4684 be sure to pass result obj by reference to xorm. 2015-09-15 17:10:16 +08:00
Torkel Ödegaard
2b95cd5081 refactor: moving routes into core, improved bundle loader 2015-09-15 08:53:06 +02:00
Torkel Ödegaard
8f45324bce fix(): fixed requirejs build 2015-09-15 08:20:26 +02:00
Torkel Ödegaard
5545cdbf4d refactor: improving structure, moving things into a core module 2015-09-15 08:17:40 +02:00
Torkel Ödegaard
9dec50832d refactor: refactoring app boot up and core structure 2015-09-14 22:54:00 +02:00
Torkel Ödegaard
64973f1d57 fix(settings): another attempt at fixing, #2736 2015-09-14 15:54:35 +02:00
Torkel Ödegaard
d7bfb727b0 fix(settings): reverted prev settings fix for detecting public_gen folder in dev, caused issue for prod build 2015-09-14 13:42:23 +02:00
Torkel Ödegaard
37ad58c69e fix(gofmt): somehow api.go did not pass gofmt test 2015-09-14 12:30:30 +02:00
Torkel Ödegaard
de753bf330 fix(build): fixed issue with ngAnnotate not including files in core/*, fixes #2733 2015-09-14 09:33:26 +02:00
Torkel Ödegaard
d17f8538b2 fix(backend): made public_gen detection more bullet proof, #2731 2015-09-13 15:23:23 +02:00
Torkel Ödegaard
1900c81d9f tech(nodejs upgrade): upgraded to nodejs 4.0 for grunt build 2015-09-13 12:13:47 +02:00
Torkel Ödegaard
9db6f82628 refactor: finished timepicker to typescript and directive refactor 2015-09-12 12:52:50 +02:00
Torkel Ödegaard
d96a6a59ee refactor: moved timepicker from a simple panel to component, removed simple panel directive 2015-09-12 11:49:27 +02:00
Torkel Ödegaard
7535677ed4 fix(build): fixed failing tslint test 2015-09-11 21:04:02 +02:00
woodsaj
6488324cf1 enhance quota support.
now includes:
- perOrg (users, dashboards, datasources, api_keys)
- perUser (orgs)
- global (users, orgs, dashboards, datasources, api_keys, sessions)
2015-09-11 23:17:10 +08:00
Torkel Ödegaard
812e4c7cd4 refactor: moved array join directive to typecrtipt 2015-09-11 10:54:56 +02:00
Torkel Ödegaard
85baae1ebd feat(influxdb): added back fill option to editor, forgot to add it in the new updated query editor 2015-09-11 10:42:50 +02:00
Torkel Ödegaard
8174b9f041 fix(tests): fixed failling backend test 2015-09-11 08:58:45 +02:00
Torkel Ödegaard
fb9e91e486 Merge branch 'master' of github.com:grafana/grafana 2015-09-11 08:13:49 +02:00
Torkel Ödegaard
1429737a60 tech(typescript): added not about typescript to changelog 2015-09-11 08:11:17 +02:00
Torkel Ödegaard
286b4c0e46 Merge branch 'typescript' 2015-09-11 08:01:11 +02:00
Torkel Ödegaard
166a3c4d64 tech(typescript): added tslint to default task 2015-09-11 08:00:13 +02:00
Torkel Ödegaard
d4a701aad0 tech(typescript): more work on typescript 2015-09-11 07:47:00 +02:00
woodsaj
47bf1bd21a return 404 when quotas not enabled. 2015-09-11 01:51:12 +08:00
woodsaj
852f9bd277 refactor quota settings 2015-09-11 01:47:33 +08:00
woodsaj
555cbeffa5 allow all users to retrieve org and quota data. 2015-09-11 01:18:36 +08:00
woodsaj
3d4d822528 implement updateQuota function 2015-09-11 01:04:29 +08:00
woodsaj
c238130842 quote table names passed by arguments 2015-09-11 01:04:22 +08:00
woodsaj
76e9ebde36 always return after errors. 2015-09-11 01:03:58 +08:00
woodsaj
0688050552 add quota middleware to enforce quotas. issue #321
Conflicts:
	pkg/api/api.go
2015-09-11 01:03:47 +08:00
woodsaj
9023171940 inital backend suport for quotas. issue #321
Conflicts:
	conf/defaults.ini
	main.go
	pkg/services/sqlstore/migrations/migrations.go
2015-09-11 01:01:36 +08:00
Torkel Ödegaard
84371f03b5 tech(typescript): more testing and migration 2015-09-10 16:47:38 +02:00
Torkel Ödegaard
20407bca89 tech(typescript): converted signup controller to typescript 2015-09-10 16:21:57 +02:00
Torkel Ödegaard
96af2debfc Merge pull request #2717 from sileht/sileht/dataproxy_test-bug
Fix dataproxy_test.go tests
2015-09-10 15:51:02 +02:00
Mehdi Abaakouk
6e532231dc Fix dataproxy_test.go tests
This change fix dataproxy_test.go tests that was failing with:

pkg/api/dataproxy_test.go:17: not enough arguments in call to NewReverseProxy
pkg/api/dataproxy_test.go:39: not enough arguments in call to NewReverseProxy
FAIL	_/home/ubuntu/grafana/pkg/api [build failed]
2015-09-10 13:27:49 +00:00
Torkel Ödegaard
dceec44671 removed tsconfig 2015-09-10 14:36:05 +02:00
Torkel Ödegaard
0b5f40e66c tech(): made config system check for generated css or javascript files and panic if there are none, also if there is a public_gen directory it will use that, even if static root is set to public 2015-09-10 13:34:32 +02:00
Torkel Ödegaard
da832368f0 dev building and optimized builds work 2015-09-10 12:42:24 +02:00
Torkel Ödegaard
abac8bccc6 tech(typescript): its looking good 2015-09-10 11:26:40 +02:00
Torkel Ödegaard
82061c7c3b experiments 2015-09-09 20:37:27 +02:00
Torkel Ödegaard
ec3a684be2 Merge pull request #2711 from jsternberg/master
Update docstring for postgres session provider
2015-09-09 20:17:23 +02:00
Jonathan A. Sternberg
5572588c54 Update docstring for postgres session provider
The postgres provider is named postgres and not postgresql. For somebody
configuring the server from the config file example, it is very easy to
write an invalid value into the file and accidentally use the "memory"
provider instead because of a typo.
2015-09-09 14:06:14 -04:00
Torkel Ödegaard
a8197df1c1 more experiments for mixing javascript and typescript 2015-09-09 19:34:24 +02:00
Torkel Ödegaard
005e1e002b more playing around with typescript 2015-09-09 17:40:52 +02:00
Torkel Ödegaard
9603dce469 feat(dataproxy): added whitelist setting and feature for data proxies, closes #2626 2015-09-09 17:21:25 +02:00
Torkel Ödegaard
13190f6f15 fixed version in changelog 2015-09-09 14:25:59 +02:00
Torkel Ödegaard
eaa061d90c cleanup(): removed old influxdb editor partial 2015-09-09 14:18:56 +02:00
Torkel Ödegaard
1ab374008f feat(influxdb): completed work on new influxdb query editor, now supports #2708, #2647, #2599 2015-09-09 14:17:55 +02:00
Torkel Ödegaard
8c9d551826 feat(influxdb): you can now change group by time iunterval on per query basis, #2647 2015-09-09 13:48:57 +02:00
Torkel Ödegaard
c4c3f9dc1f feat(influxdb): more work on changing the influxdb editor to support better aliasing and interval options, #2647, #2599 2015-09-09 13:39:45 +02:00
Torkel Ödegaard
5b722deb39 feat(influxdb): began work on changing the influxdb editor to support better aliasing and interval options, #2647, #2599 2015-09-09 11:59:02 +02:00
Torkel Ödegaard
b61b7f0c3b fix(influxdb): fixed editor bug introduced in recent commit 2015-09-09 11:05:49 +02:00
Torkel Ödegaard
3c40310e9b tech(typescript): testing for how to migrate to typescript 2015-09-09 09:57:06 +02:00
Torkel Ödegaard
7a167742d0 Merge pull request #2701 from brunoqc/patch-1
Fix typo
2015-09-08 22:31:58 +02:00
Bruno Bigras
d2a798eb3d Fix typo 2015-09-08 16:16:51 -04:00
Torkel Ödegaard
3e9e34afb8 feat(annotations): polished up the annotation editor tabs, similar to recent commits for templating editor 2015-09-08 16:59:39 +02:00
Torkel Ödegaard
26d8a041ef fix(templating): updated templating UI and tab behavior, now edit tab is not visible when not actually editing an existing var, fixes #2679 2015-09-08 15:54:08 +02:00
Torkel Ödegaard
7c25edc7b2 docs(): fixed iframe snapshot links in docs, fixes #2682 2015-09-08 15:24:20 +02:00
Torkel Ödegaard
2725053c82 docs(): fixed iframe snapshot links in docs, fixes #2682 2015-09-08 15:19:59 +02:00
Torkel Ödegaard
e2cb66f8d7 fix(logging): removed temp dev logging code 2015-09-08 14:32:25 +02:00
Torkel Ödegaard
fad1d4cf98 feat(organization): added update org address to http api and to org details settings view, closes #2672 2015-09-08 14:22:44 +02:00
Torkel Ödegaard
daf64421f2 fix(api): Added error handling to create and update org http apis and sql update handlers, now checks for org name taken scenarios and returns correct http error code and message, fixes #2686 2015-09-08 13:06:18 +02:00
Torkel Ödegaard
fa3329271d fix(email notifications): added error handling to email template parsing, fixes #2690 2015-09-08 10:57:47 +02:00
Torkel Ödegaard
fdcb4473af fix(api auth): return 401 for authentication errors and 403 for access denied errors, fixes #2693 2015-09-08 10:46:31 +02:00
Torkel Ödegaard
41154d6d11 fix(elasticsearch): fixed series naming & aliasing when using field for extended_stats and percentiles 2015-09-08 10:08:27 +02:00
Torkel Ödegaard
9904d01958 fix(unit test): trying to fix failing unit test due to timezone different on build server 2015-09-08 09:50:50 +02:00
Torkel Ödegaard
171ed497f9 version bumped to 2.5 2015-09-08 09:20:46 +02:00
Torkel Ödegaard
212a8ad6a6 Merge branch 'master' of github.com:grafana/grafana 2015-09-08 09:18:03 +02:00
Torkel Ödegaard
f2c518ba24 Merge branch 'elastic_ds'
Conflicts:
	public/app/plugins/datasource/influxdb/queryCtrl.js
2015-09-08 09:17:34 +02:00
Torkel Ödegaard
f8b61a4ebe changelog(): added #1034 to changelog 2015-09-08 09:16:41 +02:00
Torkel Ödegaard
35cc3837a0 feat(elasticsearch): more work on alias pattern, #1034 2015-09-08 09:10:26 +02:00
Torkel Ödegaard
572a80d1d1 feat(elasticsearch): metric response handling and processsing now supports alias patterns, {{term field name}} and {{metric}} now works, #1034 2015-09-07 23:15:49 +02:00
Torkel Ödegaard
2aa695fb66 feat(elasticsearch): refactoring elasticsearch response handling to support series alias patterns 2015-09-07 20:00:27 +02:00
Torkel Ödegaard
f361f324da feat(elasticsearch): more polish to editor, made interval configurable per query, #1034 2015-09-07 16:35:40 +02:00
Torkel Ödegaard
3999a3caa2 feat(elasticsearch): extended stats like std deviation now works, and sigma option as well, added unique count (cardinality as well, #1034 2015-09-07 13:13:27 +02:00
Torkel Ödegaard
efc3def7f2 feat(elasticsearch): small refactoring and polish 2015-09-07 09:36:56 +02:00
Torkel Ödegaard
6c304924f7 feat(elastic_ds): moving time field name to dataasource option, it is no longer specified for each query and date_histogram 2015-09-07 08:57:46 +02:00
Torkel Ödegaard
f90714f8fe feat(elasticsearch): changed default sort to asc 2015-09-06 16:11:01 +02:00
Torkel Ödegaard
0960360b35 feat(elasticsearch): added support for index time based patterns, #1034 2015-09-06 16:09:42 +02:00
Torkel Ödegaard
8db47e335f fixed jshint errors 2015-09-06 14:45:12 +02:00
Torkel Ödegaard
c609f67e16 fixed broken editors because of some recent refactorings 2015-09-06 14:29:28 +02:00
Torkel Ödegaard
14cb2b0143 began work on support index time patterns 2015-09-06 12:58:53 +02:00
Torkel Ödegaard
b24c539206 feat(elasticsearch): began work on supporting extended stats metric agg, it gives you standard deviation and more 2015-09-05 20:22:54 +02:00
Torkel Ödegaard
52eeefa6d9 feat(elasticsearch): fields are fetch from mapping instead of docs, you can enter custom value in field options, other fixes, #1034 2015-09-05 19:55:58 +02:00
Torkel Ödegaard
f942ec952e feat(elasticsearch): worked on percentiles metric aggregator in editor and in elasticsearch response processing 2015-09-05 18:31:42 +02:00
Torkel Ödegaard
3e9aca3ed4 feat(elasticsearch): terms aggregation options are working, things are starting to come together, #1034 2015-09-05 15:41:04 +02:00
Torkel Ödegaard
2d832e10b0 feat(elasticsearch): term metric filters are starting to work! like terms aggregation with top 5, order by metric 1 desc, where metric 1 is maybe average of @load 2015-09-05 12:51:05 +02:00
Torkel Ödegaard
f1e995ec79 feat(elasticsearch): added bucket agg id concept 2015-09-05 12:24:14 +02:00
Torkel Ödegaard
756ec8ccd7 feat(elasticsearch): close to getting group by term options ui working 2015-09-05 10:48:11 +02:00
Torkel Ödegaard
c48f24d269 feat(editor): more work on editor components, extracing things and making reusable directives 2015-09-05 10:14:21 +02:00
Torkel Ödegaard
0d2e13549a feat(editor): thing are starting to work again 2015-09-05 09:05:09 +02:00
Torkel Ödegaard
f9ce9bdcec feat(editor): refactoring and making new editor abstractions 2015-09-05 08:07:40 +02:00
Torkel Ödegaard
e339dbf473 feat(elasticsearch): so much work on new editor, its pretty broken right now, but when it is done it is going to be amazing 2015-09-04 22:10:56 +02:00
Torkel Ödegaard
f27f028d44 Merge pull request #2676 from jd/master
doc: fix link to basic concepts
2015-09-04 17:34:01 +02:00
Julien Danjou
697aaf7e70 partials: fix closing markup in datasourceHttpConfig 2015-09-04 17:14:27 +02:00
Torkel Ödegaard
cc1e3d0101 feat(elasticsearch): groundwork for a much more sophisticated elasticsearch query editor 2015-09-04 16:05:47 +02:00
Torkel Ödegaard
9daa3997e9 feat(elasticsearch): time field selector now works, #1034 2015-09-04 11:17:52 +02:00
Torkel Ödegaard
83930ec9d1 feat(elasticsearch): raw queries work, more unit tests and polish, #1034 2015-09-04 09:41:23 +02:00
Torkel Ödegaard
b83a1bf4cc Merge pull request #2673 from rodo/add_doc_app_mode
Add comments on app_mode with possible values
2015-09-04 09:25:44 +02:00
Rodolphe Quiédeville
668b47cc6e Add comments on app_mode with possible values 2015-09-04 09:01:06 +02:00
Torkel Ödegaard
f29471521c Merge pull request #2663 from victorhooi/patch-1
Add note about phantomjs binary and PNG rendering.
2015-09-04 08:40:53 +02:00
Torkel Ödegaard
5beced458c fix(): fixed problems in last commit 2015-09-04 07:41:50 +02:00
Torkel Ödegaard
ead451a979 feat(influxdb): More alias options, can now use syntax to reference part of a measurement name (seperated by dots), closes #2599 2015-09-04 07:40:28 +02:00
Torkel Ödegaard
97d42991a7 fix(graph tooltip): fixed graph tooltip when stacking and one series is not stacked (via override), fixes #2670 2015-09-03 21:18:05 +02:00
Torkel Ödegaard
cd6bdc1a78 fix(influxdb): fixed influxdb template var filter suggestion, fixes #2666 2015-09-03 20:53:20 +02:00
Torkel Ödegaard
977f538420 feat(elasticsearch): lots of work on elasticsearch metrics query editor, #1034 2015-09-03 16:35:11 +02:00
Torkel Ödegaard
590b155c6c feat(elasticsearch): lots of work on elasticsearch metrics query editor, #1034 2015-09-03 15:56:41 +02:00
Torkel Ödegaard
7e9f11ea1c feat(elasticsearch): lots of work on elasticsearch metrics query editor, #1034 2015-09-03 14:55:48 +02:00
Torkel Ödegaard
64cee145e0 Merge pull request #2669 from jd/master
doc: fix link to basic concepts
2015-09-03 14:03:04 +02:00
Torkel Ödegaard
525724cc1f feat(elasticsearch): lots of work on elasticsearch metrics query editor, #1034 2015-09-03 14:02:31 +02:00
Julien Danjou
63f9dc826f doc: fix link to basic concepts 2015-09-03 14:01:32 +02:00
Torkel Ödegaard
b3bda02063 feat(elasticsearch): lots of work on elasticsearch metrics processing, handling grouped responses, etc, #1034 2015-09-03 12:35:21 +02:00
Torkel Ödegaard
df1d56e7b1 feat(elasticsearch): lots of work on elasticsearch metrics processing, handling grouped responses, etc, #1034 2015-09-03 11:14:25 +02:00
Victor Hooi
b80adcc00a Add note about phantomjs libraries. 2015-09-03 16:35:49 +10:00
Victor Hooi
68a7c3fa3b Add note about phantomjs binary and PNG rendering. 2015-09-03 16:29:58 +10:00
Torkel Ödegaard
d099d8950f feat(elasticsearch): lots of work on elasticsearch metrics queries, #1034 2015-09-03 08:18:00 +02:00
Torkel Ödegaard
ae7093e0bb feat(elasticsearch): small progress on new elasticsearch metric query capability 2015-09-02 17:45:41 +02:00
Torkel Ödegaard
d932a877e8 fix(influxdb): removed limit of 20 for influxdb field dropdown, fixes #2655 2015-09-02 16:10:58 +02:00
Torkel Ödegaard
745a7b4461 fix(influxdb): Fixed issue when using the eye to disable queries in the query editor and when applying aliases, #2651 2015-09-02 16:06:28 +02:00
Torkel Ödegaard
9e1a9723c2 Merge branch 'cloudwatch' into elastic_ds 2015-09-02 15:25:45 +02:00
Torkel Ödegaard
e48754c73c feat(elasticsearch): began work on elasticsearch datasource, based on work in pr #2293, will need a lot more work 2015-09-02 15:25:40 +02:00
Torkel Ödegaard
096a554bfb Merge branch 'elasticsearch-datasource' of https://github.com/aheinz-sg/grafana into elastic_ds 2015-09-02 15:12:26 +02:00
Torkel Ödegaard
74da5a610c fix(spelling): capitalize text 2015-09-02 13:20:19 +02:00
Torkel Ödegaard
ea7c6edcd0 feat(cloudwatch): lots of refactoring and polish work on cloudwatch query editor 2015-09-02 12:40:08 +02:00
Torkel Ödegaard
27d5f02329 refactoring(query editors): broke out metric segment 2015-09-02 11:33:32 +02:00
Torkel Ödegaard
d56e7787f2 Merge pull request #2637 from matschaffer/env-var-output-fix
Iterate over the right env override list variable
2015-09-02 11:32:49 +02:00
Torkel Ödegaard
6d7c8431be fix(inspector): lots of improvements and fixes for the error inspector, now shows you request details and responses in many more cases, fixes #2646 2015-09-02 10:35:15 +02:00
Torkel Ödegaard
3ed63d09d9 Merge branch 'master' into cloudwatch 2015-09-01 17:25:36 +02:00
Torkel Ödegaard
4b4299604b fix(import): fixed nav link in header, fixes #2633 2015-09-01 17:14:48 +02:00
Torkel Ödegaard
3842bcb921 fix(influxdb): quote field name, fixes #2629 2015-09-01 14:49:42 +02:00
Torkel Ödegaard
f9b98767e7 docs(reference): removed link to non existant text panel page, fixes #2632 2015-09-01 13:07:42 +02:00
Torkel Ödegaard
6989c6332d fix(influxdb): fixed issue in last commit 2015-09-01 13:04:59 +02:00
Torkel Ödegaard
209e9ebda7 fix(influxdb): fixes and refactorings of influxdb 0.9 editor, no longer shows template vars in keys dropdown and group by dropdownm, fixes #2636 2015-09-01 13:01:21 +02:00
Torkel Ödegaard
e27e9dc2aa Merge pull request #2642 from bfontaine/patch-1
influxdb doc: typo fixed
2015-09-01 12:59:19 +02:00
Baptiste Fontaine
28474d9340 influxdb doc: typo fixed 2015-09-01 12:47:26 +02:00
Torkel Ödegaard
aa89416bca fix(invite): fixes to org invite stuff, #2630 2015-09-01 12:35:06 +02:00
Mat Schaffer
6c04ee1abd Iterate over the right env override list variable 2015-09-01 11:11:54 +09:00
Torkel Ödegaard
e93fba206d fix(kariosdb): fixed how kairosdb makes datasource requests, fixes #2628 2015-08-31 19:13:45 +02:00
Torkel Ödegaard
822a689b82 datasource(cloudwatch): began on polishing cloudwatch datasource, #684, #2445 2015-08-31 19:07:25 +02:00
Torkel Ödegaard
ffbf70af25 Merge branch 'cloudwatch' of https://github.com/mtanda/grafana into cloudwatch 2015-08-31 15:45:49 +02:00
Adam Heinz
d3e307b102 Refactor post-rebase to configure directives. 2015-08-31 09:32:47 -04:00
Adam Heinz
a3e4abfd5e Added group by to Elasticsearch data source. 2015-08-31 09:04:56 -04:00
Adam Heinz
56d1411253 Replace deprecated facets with aggregations. 2015-08-31 08:53:49 -04:00
Adam Heinz
7bccd17bbe Enable 'Test Connection' for Elasticsearch datasource. 2015-08-31 08:53:49 -04:00
Adam Heinz
c193208cd2 Rewrite query builder to allow for multiple time series. 2015-08-31 08:53:49 -04:00
Joseph Jones
923f9345a7 add elasticsearch query fields to the es query editor 2015-08-31 08:53:49 -04:00
Adam Heinz
d618526037 Copy/paste influxdb query editor. 2015-08-31 08:53:49 -04:00
Adam Heinz
a1dcd5f069 Initial prototype returning time series from (partially hardcoded) Elasticsearch data source. 2015-08-31 08:53:29 -04:00
Torkel Ödegaard
3dfa28570f ui(timepicker): slight polish to the time picker options view 2015-08-31 14:12:10 +02:00
Torkel Ödegaard
d78c9fa2d2 feat(signup): updated changelog with details about #2353 2015-08-31 11:47:02 +02:00
Torkel Ödegaard
6fac241404 Merge branch 'signup_remake' 2015-08-31 11:42:30 +02:00
Torkel Ödegaard
99bb9d4fcf feat(signup): added back the welcome on signup completed email 2015-08-31 11:42:12 +02:00
Torkel Ödegaard
d19e101e6b feat(signup): almost done with new sign up flow, #2353 2015-08-31 11:35:07 +02:00
Torkel Ödegaard
13c70ac02c feat(signup): selecting org after invite now works 2015-08-31 09:37:14 +02:00
Mitsuhiro Tanda
3405e44a1d add legend format tip 2015-08-31 16:03:39 +09:00
Mitsuhiro Tanda
8c5a28c0b8 improve dollar escape 2015-08-31 16:03:28 +09:00
Mitsuhiro Tanda
7229c59b8e escape {} in tip 2015-08-31 16:02:59 +09:00
Torkel Ödegaard
14884d5a2b feat(signup): progress on new signup flow, #2353 2015-08-30 18:56:53 +02:00
Torkel Ödegaard
688ed405df fix(graph tooltip): multi series tooltip did no highlight correct point when stacking was enabled and series were of different resolution, fixes #2620 2015-08-30 11:11:43 +02:00
Torkel Ödegaard
d3c79c9b49 fix(datasource query editors): fixed issue with duplicate query and the query letter (refId) 2015-08-30 10:24:15 +02:00
Torkel Ödegaard
de0f04ec3c feat(signup): progress on new sign up and email verification flow, #2353 2015-08-28 15:14:24 +02:00
Torkel Ödegaard
c61b22cefb feat(signup): progress on new sign up and email verification flow, #2353 2015-08-28 13:45:16 +02:00
Torkel Ödegaard
24dfa55465 feat(signup): progress on new sign up and email verification flow, #2353 2015-08-28 09:24:30 +02:00
Torkel Ödegaard
d25624a8ad feat(signup): began work on new / alternate signup flow that includes email verification, #2353 2015-08-27 13:59:58 +02:00
Torkel Ödegaard
41f1e5f7c9 Merge pull request #2605 from matschaffer/patch-1
Use SPDB license id
2015-08-27 08:49:52 +02:00
Mat Schaffer
be3f657073 Use SPDB license id
This avoids an npm warning telling you to use such an id.
2015-08-27 07:35:59 +09:00
Torkel Ödegaard
7e44a8ed1d feat(tagmanager): added Name variable to datalayer 2015-08-26 15:07:39 +02:00
Torkel Ödegaard
874503ca68 fix(ngblur): removed ngblur directive as it conflicted with angular naitive directive, fixes #2429 2015-08-26 13:05:33 +02:00
Torkel Ödegaard
29c833d623 Merge pull request #2598 from robison/master
updating the limit of returned tagvs in a MetricKeyLookup
2015-08-26 09:48:44 +02:00
robbie
46c0215b1f updating the limit of returned tagvs in a MetricKeyLookup since opentsdb supports limit in 2.1.0 2015-08-25 12:46:54 -07:00
Mitsuhiro Tanda
7c6e49ec65 fix too much CloudWatch query 2015-08-26 00:31:59 +09:00
Torkel Ödegaard
9a142cea7a fix(panel links): fixed panel height issue when using panel links, could cause strange panel flow, fixes #2576 2015-08-25 15:49:46 +02:00
Torkel Ödegaard
7b911aea46 fix(shutdown flow): improved shutdown flow and log closing, listing to kill and and SIGTERM as well, closes #2516 2015-08-25 15:22:24 +02:00
Torkel Ödegaard
af95daadf4 fix(jscs): fixed failing js style check 2015-08-25 09:39:42 +02:00
Torkel Ödegaard
6e8d5cd873 fix(opentsdb): blur event triggered twice for metric selector, caused double query to opentsdb after metric name change 2015-08-25 09:34:43 +02:00
Torkel Ödegaard
48686cf9f7 fix(influxdb_09): fix for handling empty series object in response from influxdb, fixes #2413 2015-08-25 09:11:39 +02:00
Mitsuhiro Tanda
b7fc3059b6 add legend format 2015-08-25 15:51:32 +09:00
Mitsuhiro Tanda
64ce5e0fad add tooltip 2015-08-25 13:35:27 +09:00
Mitsuhiro Tanda
d815d06c1c ignore empty custom metrics setting 2015-08-24 22:13:53 +09:00
Mitsuhiro Tanda
c0c8465ec2 add loading custom metrics definitions 2015-08-24 22:06:45 +09:00
Torkel Ödegaard
364d9de751 feat(ui viewer): prevent viewers from creating new dashboard or importing dashboard, closes #2590 2015-08-24 14:24:10 +02:00
Torkel Ödegaard
ca5e8c73d7 logging(ldap): added more logging to bind failures, #2588 2015-08-24 11:47:22 +02:00
Torkel Ödegaard
3e0c66edab docs(): updated download links in docs 2015-08-24 10:05:05 +02:00
Mitsuhiro Tanda
e74be5887c don't require cloudwatch dimension 2015-08-24 11:38:52 +09:00
Mitsuhiro Tanda
253d0c834c change required option by access mode 2015-08-23 14:54:08 +09:00
Mitsuhiro Tanda
feb19adb8f fix checkbox 2015-08-23 14:53:58 +09:00
Torkel Ödegaard
5d69c69b7c Merge pull request #2586 from thuck/link_typo
Fix small typo "dashbord" to dashboard
2015-08-22 14:48:13 +02:00
Denis Doria
06077faa6a Fix small typo "dashbord" to dashboard 2015-08-22 11:48:35 +02:00
Torkel Ödegaard
fcc369e854 Merge branch 'v2.1.x'
Conflicts:
	CHANGELOG.md
2015-08-22 08:44:47 +02:00
Torkel Ödegaard
ea187961da fix(templating): Another atempt at fixing #2534 (Init multi value template var used in repeat panel from url), fixes #2564
Conflicts:
	CHANGELOG.md
2015-08-22 08:43:43 +02:00
Torkel Ödegaard
c9b2cec5ff fix(packaging): deb & rpm package did not mark ldap.toml config file as a configuration file, 2.1.1 & 2.1.2 upgrade overwrote it :(, fixes #2580 2015-08-22 08:34:20 +02:00
Torkel Ödegaard
960a4f71a3 fix(jsc): fixed javascript indenting 2015-08-21 16:28:01 +02:00
Torkel Ödegaard
292db86c9e feat(relative time override): You can now use the new relative time option in panel time override, closes #2575 2015-08-21 16:19:51 +02:00
Torkel Ödegaard
6d3b36d61b fix(annotations): removed accidental test code from annotationsSrv 2015-08-21 15:32:20 +02:00
Torkel Ödegaard
c876aa537a feat(panel resize): Resize handles in panel bottom right corners for easy width and height change, closes #2577
Conflicts:
	public/app/features/panel/panelDirective.js
2015-08-21 14:59:15 +02:00
Mitsuhiro Tanda
f1e5238e16 escape dimension if it is variable name 2015-08-21 20:15:45 +09:00
Mitsuhiro Tanda
d75d4a5c08 filter empty dimension 2015-08-21 18:29:38 +09:00
Mitsuhiro Tanda
266fe876ba pass dimension in metricFindQuery 2015-08-21 18:29:32 +09:00
Torkel Ödegaard
ca53ae4fc5 fix(templating): Another atempt at fixing #2534 (Init multi value template var used in repeat panel from url), fixes #2564 2015-08-21 10:40:14 +02:00
Torkel Ödegaard
8f35683ccb fix(annotations): Fixed issue when html sanitizer failes for title to annotation body, now fallbacks to html escaping title and text, fixes #2563 2015-08-21 10:17:02 +02:00
Torkel Ödegaard
30cd782e92 fix(snapshot): Fix for snapshot with expire 7 days option, 7 days option not correct, was 7 hours, fixes #2574 2015-08-21 09:51:16 +02:00
Torkel Ödegaard
3d37c9c9a3 feat(tagmanager): support to add google tagmanager id, closes #2569 2015-08-21 09:30:39 +02:00
Torkel Ödegaard
7072af7c14 fix(auth proxy): Fix for server side rendering of panel when using auth proxy, fixes #2568 2015-08-21 07:49:49 +02:00
Mitsuhiro Tanda
c72bddf15e add cloudwatch datasource test 2015-08-21 12:55:18 +09:00
Haneysmith, Nathan
74ea266157 add login hint to defaults.ini 2015-08-20 11:20:40 -07:00
Haneysmith, Nathan
235bbc9c7e custom login hints via config file 2015-08-20 11:15:36 -07:00
Torkel Ödegaard
abd7c15ba8 fix(TimePicker): Fix for when you applied custom time range it did not refreh dashboard, fixes #2565 2015-08-20 17:57:15 +02:00
Torkel Ödegaard
a4ff1e4f33 docs(): updated version in install docs 2015-08-20 15:20:26 +02:00
Torkel Ödegaard
5b9ea96dc5 Merge branch 'v2.1.x'
Conflicts:
	CHANGELOG.md
	package.json
2015-08-20 11:16:05 +02:00
Mitsuhiro Tanda
269441fe3d add aws-sdk 2015-08-20 00:51:30 +09:00
Mitsuhiro Tanda
00f76ecaf6 CloudWatch proxy support 2015-08-20 00:51:23 +09:00
Torkel Ödegaard
952a69abca docs(tutorial): updated hubot tutorial 2015-08-19 13:53:15 +02:00
Torkel Ödegaard
aa21bfd8a8 fix(timepicker): fixed for viewing auto refresh submenu when timpicker selection is set to Today, fixes #2552 2015-08-19 13:25:36 +02:00
Torkel Ödegaard
5768762591 Merge pull request #2539 from papylhomme/master
Disable load timeout in requirejs
2015-08-18 20:23:47 +02:00
Torkel Ödegaard
ca9c11486e config(github oauth): removed allowed_domains options, closes #1986 2015-08-18 20:19:37 +02:00
Torkel Ödegaard
01d9849e44 fix(user create): fixed for creating multiple users with empty email when auto assign org is set to false, fixes #2011 2015-08-18 20:15:24 +02:00
Torkel Ödegaard
0339026674 fix(default datasource): minor fix for handling of default datasource 2015-08-18 20:04:24 +02:00
Trent White
2f5115ca45 Update hubot_howto.md 2015-08-18 09:37:51 -04:00
Trent White
66878a9b48 Update hubot_howto.md 2015-08-18 09:34:31 -04:00
Trent White
333952a231 Update hubot_howto.md 2015-08-18 09:34:08 -04:00
Torkel Ödegaard
50281f12b9 fix(default datasource): minor fix for handling of default datasource 2015-08-18 14:54:56 +02:00
Torkel Ödegaard
4f8cea6e2d docs(): added tutorial article on hubot and grafana integration 2015-08-18 14:39:04 +02:00
Mitsuhiro Tanda
1c6b7203cc add template variable to drop down list 2015-08-18 20:35:12 +09:00
Torkel Ödegaard
bf5081ec8c fix(type ahead): fixed highlight, and made the highlight more distinct, also rolled back #2436 due to its issues on linux and windows, fixes #2527 2015-08-18 10:09:12 +02:00
Torkel Ödegaard
4f7587492d docs(changelog): fixed minor wording issue in changelog 2015-08-18 08:24:08 +02:00
Torkel Ödegaard
9a9c9b2b12 Merge branch 'query-editor-breakout'
Conflicts:
	CHANGELOG.md
2015-08-18 08:23:13 +02:00
Torkel Ödegaard
d4432ddd64 feat(mixed datasources): feature ready to merge to master, closes #436 2015-08-18 08:22:00 +02:00
Torkel Ödegaard
5c2d49f7ce feat(mixed datasource): updated Elasticsearch so it uses new way to define annotations editor 2015-08-18 07:58:44 +02:00
Mitsuhiro Tanda
28ccd63255 fix templating 2015-08-18 13:29:17 +09:00
Michaël Lhomme
0dc263d919 Disable load timeout in requirejs 2015-08-17 21:41:04 +02:00
Torkel Ödegaard
3de041a411 feat(mixed datasource): added datasource name to left of query hamburger #436 2015-08-17 21:25:08 +02:00
Torkel Ödegaard
00f5f8b2a0 feat(mixed datasource): polishing feature, making sure everything works, #436 2015-08-17 21:20:09 +02:00
Torkel Ödegaard
95f1343a59 feat(mixed datasource): fixing varios issues with the query editor changes, updated kariosdb data source editor to work with the new model, #436 2015-08-17 20:53:40 +02:00
Torkel Ödegaard
b4115b0362 feat(query editor): updated influxdb 0.8.x data source query editors to new abstraction 2015-08-17 17:28:03 +02:00
Torkel Ödegaard
6ee0f2c6a7 feat(mixed data source queries): lots of minor polish to new mixed data source and all the changes it has required, #436 2015-08-17 17:07:33 +02:00
Torkel Ödegaard
af39e4de3e Merge branch 'v2.1.x'
Conflicts:
	CHANGELOG.md
2015-08-17 15:02:47 +02:00
Torkel Ödegaard
4a6b5274bc feat(invite): fixes for org invite enhancement story, #2353 2015-08-17 10:55:52 +02:00
Torkel Ödegaard
f7ea420a3f Merge pull request #2521 from mattttt/email-tweaks
Email tweaks
2015-08-17 10:33:06 +02:00
Torkel Ödegaard
56d5b0b12a feat(mixed datasource): minor progress 2015-08-17 10:31:54 +02:00
Torkel Ödegaard
bb81248eaa Merge pull request #2528 from thuck/permissions
Fixing permission issues for new installations
2015-08-17 10:13:12 +02:00
Torkel Ödegaard
0e18eafcfb Merge pull request #2535 from raintank/logging
close all existing loggers before re-initializing loggers. fixes #2533
2015-08-17 10:05:42 +02:00
woodsaj
c138f390ac close all existing loggers before re-initilizing loggers. fixes #2533 2015-08-17 15:59:40 +08:00
Torkel Ödegaard
a16c63a43e feat(mixed datasources): continued work on editor design change 2015-08-16 20:52:30 +02:00
Denis Doria
9e21a089d2 Fixing permission issues for new installations
The umask as 0027 will generates permissions like:
0640 - for files
0750 - for directories

This should solve the grafana.db being accesable by any user for new installations.
2015-08-16 18:43:27 +02:00
Torkel Ödegaard
3105215425 feat(mixed datasource): changed how query ref ids (letters) are assigned, now they are persisted 2015-08-16 11:24:32 +02:00
Torkel Ödegaard
e916f93787 feat(mixed datasource): fixed failing unit tests 2015-08-16 10:06:36 +02:00
Torkel Ödegaard
1332ddbc93 feat(mixed datasources): updated OpenTSDB data source query editor to new model, #436 2015-08-16 09:52:45 +02:00
Torkel Ödegaard
b30dfcf28a feat(datasource): added new mixed data source 2015-08-16 01:34:09 +02:00
Torkel Ödegaard
b9cfade18c feat(mutli db query): major changes to query editor and data source handling, looks promising 2015-08-15 23:11:37 +02:00
Torkel Ödegaard
ad1fa110ff change(search): opening search dropdown should not take you out of fullscreen view or edit 2015-08-15 21:57:41 +02:00
Torkel Ödegaard
ed49962120 refactor(): began work on big design change for how data source query editors are loaded 2015-08-15 21:49:30 +02:00
Matt Toback
0651f134e4 Backed our new styles out of ink.css and moved them into style.css. Small margin tweaks, looking good to go. 2015-08-14 15:21:51 -04:00
Torkel Ödegaard
16fa5c4df3 fix(mysql): fix for migration in newly added temp_user table, fixes #2509 2015-08-14 09:41:07 +02:00
Torkel Ödegaard
2f849be9d8 docs(): minor tweaks to new tutorial 2015-08-14 09:41:07 +02:00
Torkel Ödegaard
6c49ab932e Merge pull request #2511 from pivotal-cloudops/patch
fix test connection bug
2015-08-14 09:23:14 +02:00
Pivotal
dc9c2773cb fix test connection bug 2015-08-14 13:50:01 +08:00
Matt Toback
60eec49e95 Added in additional text and incorporated the bulletproof button that was built for raintank. Needs some help from Torkel or Nick to make sure it's cleaner 2015-08-13 17:57:58 -04:00
Torkel Ödegaard
f784551e20 docs(): Began work on stack install and config tutorial 2015-08-13 08:52:50 +02:00
Torkel Ödegaard
a3d9169930 docs(): minor update 2015-08-13 08:00:27 +02:00
Torkel Ödegaard
e87502285b Merge pull request #2502 from mtanda/stack_override_tooltip
don't calculate cumulative value if series overrides stack to false
2015-08-13 07:44:27 +02:00
Mitsuhiro Tanda
caccacf52b don't calculate cumulative value if series overrides stack to false 2015-08-13 13:40:16 +09:00
Torkel Ödegaard
5aee981590 Merge branch 'master' of https://github.com/mattttt/grafana
Conflicts:
	docs/sources/installation/debian.md
	docs/sources/installation/ldap.md
2015-08-12 16:30:48 +02:00
Torkel Ödegaard
e6d09b3266 fix(db): remove stars and tags when removing user or dashboard, fixes #2016 2015-08-12 09:23:46 +02:00
Torkel Ödegaard
8fcaa4997d feat(admin): Deleting org from orgs list now works, will permanently delete dashboards, data sources, etc, closes #2457 2015-08-12 08:59:39 +02:00
Torkel Ödegaard
7370af9a82 Merge pull request #2492 from agilgur5/master
docs(ldap): Clarify LDAP features and sample config
2015-08-12 08:20:00 +02:00
Anton Gilgur
e4baef94bc docs(ldap): Clarify LDAP features and sample config
* Clarify certain features, such as multiple mappings
* Fixup ldap.toml sample config
* Fixup docs README's port number
* Fixup bad link from LDAP docs to Configuration docs
* Fixup some spelling, grammar, and line endings
2015-08-11 19:57:53 -07:00
Trent White
8c05f9cf3e Merge pull request #11 from mattttt/trent-update
add text panel page
2015-08-11 16:52:15 -04:00
Trent White
ebcab0f26e add text panel page 2015-08-11 16:50:33 -04:00
Matt
14996bd08b Update templating.md 2015-08-11 15:57:36 -04:00
Matt
dd9fb9d526 Update templating.md 2015-08-11 15:56:18 -04:00
Matt
f3ffed673b Merge pull request #10 from mattttt/build-patch-1
Reformatted a confusing part of of the running grafana locally section
2015-08-11 15:47:38 -04:00
Matt Toback
5b342dd229 Reformatted a confusing part of of the running grafana locally section 2015-08-11 15:41:12 -04:00
Trent White
e626bbf415 Merge pull request #9 from mattttt/trent-update
formatting tweak, added datasource overview blurb.
2015-08-11 15:31:03 -04:00
Trent White
04795709a3 formatting tweak, added datasource overview blurb. 2015-08-11 15:30:13 -04:00
Torkel Ödegaard
745162c589 fix(graphite): Import dashboard from graphite is working again, fixes #2490 2015-08-11 21:20:20 +02:00
Torkel Ödegaard
089508db8e fix(influxdb 0.9): removed function from function dropdown as this function does not exist in InfluxDB 0.9 2015-08-11 21:10:15 +02:00
Matt
a912323d01 Merge pull request #8 from mattttt/ct-additions
Added patch from ct
2015-08-11 14:59:59 -04:00
Matt Toback
511a592ec8 Added patch from ct 2015-08-11 14:58:30 -04:00
Matt
d132d3abfd Merge pull request #7 from mattttt/mattttt-docs
Mattttt docs
2015-08-11 14:41:21 -04:00
Trent White
fb9b5e4274 Merge pull request #6 from mattttt/trent-docs-update
openTSDB image was broken
2015-08-11 14:32:03 -04:00
Trent White
8dcc5645db openTSDB image was broken 2015-08-11 14:26:32 -04:00
raj dutt
c6798892b8 Update screencasts.md
tweaks
2015-08-11 14:26:04 -04:00
Matt Toback
eea5b026ce Sanity checked and verified for merge 2015-08-11 14:17:56 -04:00
raj dutt
331e858ed3 Update gettingstarted.md 2015-08-11 14:04:14 -04:00
Trent White
3d602a2558 Merge remote-tracking branch 'origin/master' 2015-08-11 14:01:03 -04:00
Trent White
14386a2f62 Merge branch 'trent-docs'
Conflicts:
	docs/sources/reference/templating.md
2015-08-11 13:59:46 -04:00
raj dutt
4e91e05470 Update gettingstarted.md 2015-08-11 13:58:44 -04:00
Trent White
ea0bec8bf2 update content on annotations 2015-08-11 13:51:27 -04:00
raj dutt
c2e8a1d733 Update singlestat.md 2015-08-11 13:49:24 -04:00
raj dutt
c6155723a1 Update playlist.md 2015-08-11 13:43:36 -04:00
Trent White
8c64afc81e update to templating doc 2015-08-11 13:42:40 -04:00
raj dutt
eafd1d8c53 Update templating.md 2015-08-11 13:33:01 -04:00
raj dutt
df0673f907 Update templating.md 2015-08-11 13:31:49 -04:00
Torkel Ödegaard
fe093c6385 feat(timepicker): added new relative time option , will set time range to midnight to now, closes #1186 2015-08-11 19:16:45 +02:00
raj dutt
ed536f18ee Update basic_concepts.md 2015-08-11 13:07:30 -04:00
Matt Toback
96590f591c Updates to dashlist article 2015-08-11 12:34:18 -04:00
Trent White
32bfcbcdbc updates to screencasts page, with descriptions of each 2015-08-11 11:43:45 -04:00
Torkel Ödegaard
82feeff3aa tech(emails): small update to grunt watch for emails 2015-08-11 16:40:23 +02:00
Trent White
3af451caeb Merge pull request #4 from mattttt/trent-docs
added pages, touched up some images and content  in data-sources section
2015-08-11 10:15:59 -04:00
Trent White
ae953f2420 added pages, touched up some images and content in data-sources section 2015-08-11 10:12:58 -04:00
Torkel Ödegaard
43ef9f909a feat(admin): admin page for all grafana organizations (list / edit view), #2457 2015-08-11 15:20:50 +02:00
Mitsuhiro Tanda
4f42dae3cb change behavior of dimension value suggestion 2015-08-11 20:43:34 +09:00
Torkel Ödegaard
e01c68dcea fix(logging): removed db connection string from being printed in logs at app startup, fixes #2488 2015-08-11 11:26:28 +02:00
Torkel Ödegaard
234d1291f9 Merge branch 'invite'
Conflicts:
	public/css/less/gfbox.less
	public/emails/reset_password.html
	public/emails/welcome_on_signup.html
2015-08-11 11:22:43 +02:00
Torkel Ödegaard
90169d6a05 Bumped master version to 2.2.0-pre1 2015-08-11 11:18:39 +02:00
Torkel Ödegaard
809562c874 updated install docs for 2.1.1 release 2015-08-11 11:12:06 +02:00
Torkel Ödegaard
be7a3a0940 pumped version to 2.1.1 2015-08-11 10:48:19 +02:00
Torkel Ödegaard
1ea0b5371a feat(invite): new user invites are now also added to correct org after sign up is completed, #2353 2015-08-11 10:45:03 +02:00
Torkel Ödegaard
74932e6311 feat(invite): added specific email for invites to existing grafana users 2015-08-11 10:35:10 +02:00
Torkel Ödegaard
b0b96aa410 Moved reset password and welcome on sign up email to new email build template system 2015-08-11 10:01:52 +02:00
Mitsuhiro Tanda
deedd166db add metricFindQuery 2015-08-11 14:26:24 +09:00
Mitsuhiro Tanda
6ffab821b2 refactor suggest function 2015-08-11 14:26:18 +09:00
Matt
e53c8100a3 Merge pull request #3 from mattttt/mattttt-docs
Adding additional pages and updates from google doc
2015-08-10 23:20:15 -04:00
Mitsuhiro Tanda
6705902a94 fix style 2015-08-11 10:17:48 +09:00
Mitsuhiro Tanda
fd96e30c9c add region field in query editor 2015-08-11 10:17:39 +09:00
Matt Toback
2b59724ea8 Adding additional pages and updates from google doc 2015-08-10 18:19:56 -04:00
Trent White
aa4d6d6f0f Merge pull request #2 from mattttt/trent-docs
add basic concpets doc
2015-08-10 17:52:38 -04:00
Trent White
ca65671553 add basic concpets doc 2015-08-10 17:51:29 -04:00
Trent White
2d99308219 Merge pull request #1 from mattttt/trent-docs
adding Raj edits/additions as well as initial round of pages I created
2015-08-10 17:46:51 -04:00
Trent White
a4be75f410 adding Raj edits/additions as well as initial round of pages I created 2015-08-10 17:44:08 -04:00
Torkel Ödegaard
4439545428 feat(invite): lots of work completing the new email template system and css inlineing, converted new_user_invite.html to new system, #2353 2015-08-10 21:24:47 +02:00
Torkel Ödegaard
835fd383ad fix(postgres): Dashboard search is now case insensitive when using Postgres, fixes #1896 2015-08-10 20:25:01 +02:00
Torkel Ödegaard
dfd1bff389 feat(invite): began work on email template build system, and css inlining 2015-08-10 17:50:02 +02:00
Torkel Ödegaard
e53c1e39d3 feat(invite): can now add org user with sername again, #2353 2015-08-10 14:03:08 +02:00
Torkel Ödegaard
775e044e69 feat(invite): progress on invite feature, #2353 2015-08-10 13:47:06 +02:00
Mitsuhiro Tanda
6a697eed2f fix deactivating statistics bug 2015-08-06 14:41:06 +09:00
Mitsuhiro Tanda
134819cb45 fix jshint error 2015-08-06 00:05:40 +09:00
Mitsuhiro Tanda
88ce05976e add CloudWatch datasource 2015-08-05 23:10:32 +09:00
Torkel Ödegaard
93b8287d23 Merge pull request #2437 from mattttt/invite
Added some small styling tweaks to the modals, and adjusted some copy.
2015-08-05 10:10:57 +02:00
Matt Toback
b64c550989 Added some small styling tweaks to the modals, and adjusted some copy. 2015-08-04 15:58:07 -04:00
Torkel Ödegaard
9d25d2674b fix(invite): fixed link in email 2015-08-04 20:23:04 +02:00
Torkel Ödegaard
5a160f426e feat(invite): trying to get username to work as well 2015-07-29 09:30:23 +02:00
Torkel Ödegaard
6d6af09296 feat(invite): handling of existing org user case when inviting, #2353 2015-07-21 12:18:11 +02:00
Torkel Ödegaard
ab54971763 feat(invite): more progress on completing invite form and actually creating a real user, #2353 2015-07-20 17:46:48 +02:00
Torkel Ödegaard
d75f96fdd5 feat(invite): more progress on invited / sigup view, #2353 2015-07-20 15:52:49 +02:00
Torkel Ödegaard
024c112944 feat(invite): redesign for pending invite list, added revoke button and link, copy invite also works now, #2353 2015-07-20 14:26:49 +02:00
Torkel Ödegaard
3242354a4b feat(invite): worked on pending invitations list, revoke invite now works, #2353 2015-07-20 10:57:39 +02:00
Torkel Ödegaard
4ac652b127 feat(invite): began work on invited signup view, also added backdrop to login view, #2353 2015-07-19 12:34:03 +02:00
Torkel Ödegaard
6088f83408 feat(invite): inital pass on sending new user invite email, #2353 2015-07-18 17:39:12 +02:00
Torkel Ödegaard
e92f2ecea1 feat(invite): existing grafana users now result in new org user directly, no temp user is created, #2353 2015-07-18 11:43:34 +02:00
Torkel Ödegaard
a82aa8203b Merge branch 'master' into invite 2015-07-18 10:14:45 +02:00
Torkel Ödegaard
2c7e807738 feat(invite): small style change 2015-07-17 17:22:42 +02:00
Torkel Ödegaard
2724cf5db8 feat(invite): small progress 2015-07-17 14:42:49 +02:00
Torkel Ödegaard
0ffcce1b5d feat(invite): more work on invite, basic creation works, added new tab directive from angular-ui and made new tab style, #2353 2015-07-17 09:51:34 +02:00
Torkel Ödegaard
444807c35b feat(invite): worked on db & domain model for temp users, #2353 2015-07-16 17:59:11 +02:00
Torkel Ödegaard
c3a5822a40 feat(user invite): progress on user invite feature, #2353 2015-07-16 12:38:55 +02:00
Torkel Ödegaard
57c78bc603 feat(invite): began work on invite users dialog, #2353 2015-07-16 10:44:55 +02:00
Mike Kobyakov
f76374cd8f fix testDatasource, which was calling performSuggestQuery instead of _performSuggestQuery 2015-07-15 12:03:22 -07:00
Mike Kobyakov
eb88a53223 fix for a change in datasource object 2015-07-10 16:09:08 -07:00
Mike Kobyakov
76c18e50a4 Merge remote-tracking branch 'upstream/master'
Conflicts:
	public/app/plugins/datasource/opentsdb/datasource.js
2015-07-10 15:55:45 -07:00
Torkel Ödegaard
2dbb370955 Working on resize handle, drag to resize panels & rows 2015-06-26 18:45:23 +02:00
Mike Kobyakov
0b05f88543 Merge remote-tracking branch 'mychanges/master' 2015-04-22 12:06:32 -07:00
Mike Kobyakov
e395211654 Instead of hard-coding the OpenTsdb aggregators list, pull the supported
aggregators from the datasource directly.
2015-04-22 12:02:45 -07:00
Mike Kobyakov
b01b121a4b Instead of hard-coding the OpenTsdb aggregators list, pull the supported
aggregators from the datasource directly.
2015-03-30 10:17:45 -07:00
2440 changed files with 270219 additions and 49399 deletions

View File

@@ -1,6 +1,6 @@
[run]
init_cmds = [
["go", "build", "-o", "./bin/grafana-server"],
["go", "build", "-o", "./bin/grafana-server", "./pkg/cmd/grafana-server"],
["./bin/grafana-server"]
]
watch_all = true
@@ -9,9 +9,9 @@ watch_dirs = [
"$WORKDIR/public/views",
"$WORKDIR/conf",
]
watch_exts = [".go", "conf/*"]
watch_exts = [".go", ".ini", ".toml", ".html"]
build_delay = 1500
cmds = [
["go", "build", "-o", "./bin/grafana-server"],
["go", "build", "-o", "./bin/grafana-server", "./pkg/cmd/grafana-server"],
["./bin/grafana-server"]
]

19
.editorconfig Normal file
View File

@@ -0,0 +1,19 @@
# http://editorconfig.org
root = true
[*.go]
indent_style = tabs
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

22
.github/CONTRIBUTING.md vendored Normal file
View File

@@ -0,0 +1,22 @@
Follow the setup guide in README.md
### Rebuild frontend assets on source change
```
grunt && grunt watch
```
### Rerun tests on source change
```
grunt karma:dev
```
### Run tests for backend assets before commit
```
test -z "$(gofmt -s -l . | grep -v Godeps/_workspace/src/ | tee /dev/stderr)"
```
### Run tests for frontend assets before commit
```
grunt test
godep go test -v ./pkg/...
```

12
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,12 @@
Thank you! For helping us make Grafana even better.
To help us respond to your issues faster, please make sure to add as much information as possible.
If this issue is about a plugin, please open the issue in that repository.
Start your issues title with [Feature Request] / [Bug] / [Question] or no tag if your unsure.
Ex
* What grafana version are you using?
* What datasource are you using?
* What OS are you running grafana on?

2
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,2 @@
* Link the PR to an issue for new features
* Rebase your PR if it gets out of sync with master

12
.gitignore vendored
View File

@@ -1,9 +1,14 @@
node_modules
npm-debug.log
coverage/
.aws-config.json
awsconfig
/dist
/emails/dist
/public_gen
/public/vendor/npm
/tmp
vendor/phantomjs/phantomjs
docs/AWS_S3_BUCKET
docs/GIT_BRANCH
@@ -26,5 +31,10 @@ public/css/*.min.css
conf/custom.ini
fig.yml
docker-compose.yml
profile.cov
/grafana
.notouch
/pkg/cmd/grafana-cli/grafana-cli
/pkg/cmd/grafana-server/grafana-server
/examples/*/dist

View File

@@ -5,3 +5,6 @@ if [ $? -gt 0 ]; then
echo "Some files aren't formatted, please run 'go fmt ./pkg/...' to format your source code before committing"
exit 1
fi
grunt test

View File

@@ -4,7 +4,7 @@
"bitwise":false,
"curly": true,
"eqnull": true,
"globalstrict": true,
"strict": true,
"devel": true,
"eqeqeq": true,
"forin": false,
@@ -12,7 +12,7 @@
"supernew": true,
"expr": true,
"indent": 2,
"latedef": true,
"latedef": false,
"newcap": true,
"noarg": true,
"noempty": true,
@@ -23,13 +23,15 @@
"laxcomma": true,
"sub": true,
"unused": true,
"maxdepth": 5,
"maxdepth": 6,
"maxlen": 140,
"globals": {
"System": true,
"Promise": true,
"define": true,
"require": true,
"Chromath": false,
"setImmediate": true
}
}
}

View File

@@ -1,10 +1,159 @@
# 2.1.2 (unreleased)
# 3.0.0 (unrelased master branch)
### New Features
* **Playlists**: Playlists can now be persisted and started from urls, closes [#3655](https://github.com/grafana/grafana/issues/3655)
* **Metadata**: Settings panel now shows dashboard metadata, closes [#3304](https://github.com/grafana/grafana/issues/3304)
* **InfluxDB**: Support for policy selection in query editor, closes [#2018](https://github.com/grafana/grafana/issues/2018)
* **Snapshots UI**: Dashboard snapshots list can be managed through UI, closes[#1984](https://github.com/grafana/grafana/issues/1984)
* **Prometheus**: Prometheus annotation support, closes[#2883](https://github.com/grafana/grafana/pull/2883)
* **Cli**: New cli tool for downloading and updating plugins
* **Annotations**: Annotations can now contain links that can be clicked (you can navigate on to annotation popovers), closes [#1588](https://github.com/grafana/grafana/issues/1588)
* **Opentsdb**: Opentsdb 2.2 filters support, closes[#3077](https://github.com/grafana/grafana/issues/3077)
### Breaking changes
* **Plugin API**: Both datasource and panel plugin api (and plugin.json schema) have been updated, requiring an update to plugins. See [plugin api](https://github.com/grafana/grafana/blob/master/public/app/plugins/plugin_api.md) for more info.
* **InfluxDB 0.8.x** The data source for the old version of influxdb (0.8.x) is no longer included in default builds, but can easily be installed via improved plugin system, closes [#3523](https://github.com/grafana/grafana/issues/3523)
* **KairosDB** The data source is no longer included in default builds, but can easily be installed via improved plugin system, closes [#3524](https://github.com/grafana/grafana/issues/3524)
* **Templating**: Templating value formats (glob/regex/pipe etc) are now handled automatically and not specified by the user, this makes variable values possible to reuse in many contexts. It can in some edge cases break existing dashboards that have template variables that do not reload on dashboard load. To fix any issue just go into template variable options and update the variable (so it's values are reloaded.).
### Enhancements
* **LDAP**: Support for nested LDAP Groups, closes [#4401](https://github.com/grafana/grafana/issues/4401), [#3808](https://github.com/grafana/grafana/issues/3808)
* **Sessions**: Support for memcached as session storage, closes [#3458](https://github.com/grafana/grafana/issues/3458)
* **mysql**: Grafana now supports ssl for mysql, closes [#3584](https://github.com/grafana/grafana/issues/3584)
* **snapshot**: Annotations are now included in snapshots, closes [#3635](https://github.com/grafana/grafana/issues/3635)
* **Admin**: Admin can now have global overview of Grafana setup, closes [#3812](https://github.com/grafana/grafana/issues/3812)
* **graph**: Right side legend height is now fixed at row height, closes [#1277](https://github.com/grafana/grafana/issues/1277)
* **Table**: All content in table panel is now html escaped, closes [#3673](https://github.com/grafana/grafana/issues/3673)
* **graph**: Template variables can now be used in TimeShift and TimeFrom, closes[#1960](https://github.com/grafana/grafana/issues/1960)
* **Tooltip**: Optionally add milliseconds to timestamp in tool tip, closes[#2248](https://github.com/grafana/grafana/issues/2248)
* **Opentsdb**: Support milliseconds when using openTSDB datasource, closes [#2865](https://github.com/grafana/grafana/issues/2865)
* **Opentsdb**: Add support for annotations, closes[#664](https://github.com/grafana/grafana/issues/664)
### Bug fixes
* **Playlist**: Fix for memory leak when running a playlist, closes [#3794](https://github.com/grafana/grafana/pull/3794)
* **InfluxDB**: Fix for InfluxDB and table panel when using Format As Table and having group by time, fixes [#3928](https://github.com/grafana/grafana/issues/3928)
* **Panel Time shift**: Fix for panel time range and using dashboard times liek `Today` and `This Week`, fixes [#3941](https://github.com/grafana/grafana/issues/3941)
* **Row repeat**: Repeated rows will now appear next to each other and not by the bottom of the dashboard, fixes [#3942](https://github.com/grafana/grafana/issues/3942)
* **Png renderer**: Fix for phantomjs path on windows, fixes [#3657](https://github.com/grafana/grafana/issues/3657)
# 2.6.1 (unrelased, 2.6.x branch)
### New Features
* **Elasticsearch**: Support for derivative unit option, closes [#3512](https://github.com/grafana/grafana/issues/3512)
### Bug fixes
* **Graph Panel**: Fixed typehead when adding series style override, closes [#3554](https://github.com/grafana/grafana/issues/3554)
# 2.6.0 (2015-12-14)
### New Features
* **Elasticsearch**: Support for pipeline aggregations Moving average and derivative, closes [#2715](https://github.com/grafana/grafana/issues/2715)
* **Elasticsearch**: Support for inline script and missing options for metrics, closes [#3500](https://github.com/grafana/grafana/issues/3500)
* **Syslog**: Support for syslog logging, closes [#3161](https://github.com/grafana/grafana/pull/3161)
* **Timepicker**: Always show refresh button even with refresh rate, closes [#3498](https://github.com/grafana/grafana/pull/3498)
* **Login**: Make it possible to change the login hint on the login page, closes [#2571](https://github.com/grafana/grafana/pull/2571)
### Bug Fixes
* **metric editors**: Fix for clicking typeahead auto dropdown option, fixes [#3428](https://github.com/grafana/grafana/issues/3428)
* **influxdb**: Fixed issue showing Group By label only on first query, fixes [#3453](https://github.com/grafana/grafana/issues/3453)
* **logging**: Add more verbose info logging for http reqeusts, closes [#3405](https://github.com/grafana/grafana/pull/3405)
# 2.6.0-Beta1 (2015-12-04)
### New Table Panel
* **table**: New powerful and flexible table panel, closes [#215](https://github.com/grafana/grafana/issues/215)
### Enhancements
* **CloudWatch**: Support for multiple AWS Credentials, closes [#3053](https://github.com/grafana/grafana/issues/3053), [#3080](https://github.com/grafana/grafana/issues/3080)
* **Elasticsearch**: Support for dynamic daily indices for annotations, closes [#3061](https://github.com/grafana/grafana/issues/3061)
* **Elasticsearch**: Support for setting min_doc_count for date histogram, closes [#3416](https://github.com/grafana/grafana/issues/3416)
* **Graph Panel**: Option to hide series with all zeroes from legend and tooltip, closes [#1381](https://github.com/grafana/grafana/issues/1381), [#3336](https://github.com/grafana/grafana/issues/3336)
### Bug Fixes
* **cloudwatch**: fix for handling of period for long time ranges, fixes [#3086](https://github.com/grafana/grafana/issues/3086)
* **dashboard**: fix for collapse row by clicking on row title, fixes [#3065](https://github.com/grafana/grafana/issues/3065)
* **influxdb**: fix for relative time ranges `last x months` and `last x years`, fixes [#3067](https://github.com/grafana/grafana/issues/3067)
* **graph**: layout fix for color picker when right side legend was enabled, fixes [#3093](https://github.com/grafana/grafana/issues/3093)
* **elasticsearch**: disabling elastic query (via eye) caused error, fixes [#3300](https://github.com/grafana/grafana/issues/3300)
### Breaking changes
* **elasticsearch**: Manual json edited queries are not supported any more (They very barely worked in 2.5)
# 2.5 (2015-10-28)
**New Feature: Mix data sources**
- A built in data source is now available named `-- Mixed --`, When picked in the metrics tab,
it allows you to add queries of differnet data source types & instances to the same graph/panel!
[Issue #436](https://github.com/grafana/grafana/issues/436)
**New Feature: Elasticsearch Metrics Query Editor and Viz Support**
- Feature rich query editor and processing features enables you to issues all kind of metric queries to Elasticsearch
- See [Issue #1034](https://github.com/grafana/grafana/issues/1034) for more info.
**New Feature: New and much improved time picker**
- Support for quick ranges like `Today`, `This day last week`, `This week`, `The day so far`, etc.
- Improved UI and improved support for UTC, [Issue #2761](https://github.com/grafana/grafana/issues/2761) for more info.
**User Onboarding**
- Org admin can now send email invites (or invite links) to people who are not yet Grafana users
- Sign up flow now supports email verification (if enabled)
- See [Issue #2353](https://github.com/grafana/grafana/issues/2353) for more info.
**Other new Features && Enhancements**
- [Pull #2720](https://github.com/grafana/grafana/pull/2720). Admin: Initial basic quota support (per Org)
- [Issue #2577](https://github.com/grafana/grafana/issues/2577). Panel: Resize handles in panel bottom right corners for easy width and height change
- [Issue #2457](https://github.com/grafana/grafana/issues/2457). Admin: admin page for all grafana organizations (list / edit view)
- [Issue #1186](https://github.com/grafana/grafana/issues/1186). Time Picker: New option `today`, will set time range from midnight to now
- [Issue #2647](https://github.com/grafana/grafana/issues/2647). InfluxDB: You can now set group by time interval on each query
- [Issue #2599](https://github.com/grafana/grafana/issues/2599). InfluxDB: Improved alias support, you can now use the `AS` clause for each select statement
- [Issue #2708](https://github.com/grafana/grafana/issues/2708). InfluxDB: You can now set math expression for select clauses.
- [Issue #1575](https://github.com/grafana/grafana/issues/1575). Drilldown link: now you can click on the external link icon in the panel header to access drilldown links!
- [Issue #1646](https://github.com/grafana/grafana/issues/1646). OpenTSDB: Fetch list of aggregators from OpenTSDB
- [Issue #2955](https://github.com/grafana/grafana/issues/2955). Graph: More axis units (Length, Volume, Temperature, Pressure, etc), thanks @greglook
- [Issue #2928](https://github.com/grafana/grafana/issues/2928). LDAP: Support for searching for groups memberships, i.e. POSIX (no memberOf) schemas, also multiple ldap servers, and root ca cert, thanks @abligh
**Fixes**
- [Issue #2413](https://github.com/grafana/grafana/issues/2413). InfluxDB 0.9: Fix for handling empty series object in response from influxdb
- [Issue #2574](https://github.com/grafana/grafana/issues/2574). Snapshot: Fix for snapshot with expire 7 days option, 7 days option not correct, was 7 hours
- [Issue #2568](https://github.com/grafana/grafana/issues/2568). AuthProxy: Fix for server side rendering of panel when using auth proxy
- [Issue #2490](https://github.com/grafana/grafana/issues/2490). Graphite: Dashboard import was broken in 2.1 and 2.1.1, working now
- [Issue #2565](https://github.com/grafana/grafana/issues/2565). TimePicker: Fix for when you applied custom time range it did not refreh dashboard
- [Issue #2563](https://github.com/grafana/grafana/issues/2563). Annotations: Fixed issue when html sanitizer failes for title to annotation body, now fallbacks to html escaping title and text
- [Issue #2564](https://github.com/grafana/grafana/issues/2564). Templating: Another atempt at fixing #2534 (Init multi value template var used in repeat panel from url)
- [Issue #2620](https://github.com/grafana/grafana/issues/2620). Graph: multi series tooltip did no highlight correct point when stacking was enabled and series were of different resolution
- [Issue #2636](https://github.com/grafana/grafana/issues/2636). InfluxDB: Do no show template vars in dropdown for tag keys and group by keys
- [Issue #2604](https://github.com/grafana/grafana/issues/2604). InfluxDB: More alias options, can now use `$[0-9]` syntax to reference part of a measurement name (seperated by dots)
**Breaking Changes**
- Notice to makers/users of custom data sources, there is a minor breaking change in 2.2 that
require an update to custom data sources for them to work in 2.2. [Read this doc](https://github.com/grafana/grafana/tree/master/docs/sources/datasources/plugin_api.md) for more on the
data source api change.
- Data source api changes, [PLUGIN_CHANGES.md](https://github.com/grafana/grafana/blob/master/public/app/plugins/PLUGIN_CHANGES.md)
- The duplicate query function used in data source editors is changed, and moveMetricQuery function was renamed
**Tech (Note for devs)**
Started using Typescript (transpiled to ES5), uncompiled typescript files and less files are in public folder (in source tree)
This folder is never modified by build steps. Compiled css and javascript files are put in public_gen, all other files
that do not undergo transformation are just copied from public to public_gen, it is public_gen that is used by grafana-server
if it is found.
Grunt & Watch tasks:
- `grunt` : default task, will remove public_gen, copy over all files from public, do less & typescript compilation
- `grunt watch`: will watch for changes to less, and typescript files and compile them to public_gen, and for other files it will just copy them to public_gen
# 2.1.3 (2015-08-24)
**Fixes**
- [Issue #2580](https://github.com/grafana/grafana/issues/2580). Packaging: ldap.toml was not marked as config file and could be overwritten in upgrade
- [Issue #2564](https://github.com/grafana/grafana/issues/2564). Templating: Another atempt at fixing #2534 (Init multi value template var used in repeat panel from url)
# 2.1.2 (2015-08-20)
**Fixes**
- [Issue #2558](https://github.com/grafana/grafana/issues/2558). DragDrop: Fix for broken drag drop behavior
- [Issue #2534](https://github.com/grafana/grafana/issues/2534). Templating: fix for setting template variable value via url and having repeated panels or rows
# 2.1.1 (2015-08-11)
**Fixes**
@@ -14,6 +163,7 @@
- [Issue #2460](https://github.com/grafana/grafana/issues/2460). SinglestatPanel: Fix to handle series with no data points
- [Issue #2461](https://github.com/grafana/grafana/issues/2461). LDAP: Fix for ldap users with empty email address
- [Issue #2484](https://github.com/grafana/grafana/issues/2484). Graphite: Fix bug when using series ref (#A-Z) and referenced series is hidden in query editor.
- [Issue #1896](https://github.com/grafana/grafana/issues/1896). Postgres: Dashboard search is now case insensitive when using Postgres
**Enhancements**
- [Issue #2477](https://github.com/grafana/grafana/issues/2477). InfluxDB(0.9): Added more condition operators (`<`, `>`, `<>`, `!~`), thx @thuck
@@ -124,6 +274,10 @@
# 2.0.0-Beta1 (2015-03-30)
**Important Note**
Grafana 2.x is fundamentally different from 1.x; it now ships with an integrated backend server. Please read the [Documentation](http://docs.grafana.org) for more detailed about this SIGNIFCANT change to Grafana
**New features**
- [Issue #1623](https://github.com/grafana/grafana/issues/1623). Share Dashboard: Dashboard snapshot sharing (dash and data snapshot), save to local or save to public snapshot dashboard snapshots.raintank.io site
- [Issue #1622](https://github.com/grafana/grafana/issues/1622). Share Panel: The share modal now has an embed option, gives you an iframe that you can use to embedd a single graph on another web site

View File

@@ -1,14 +0,0 @@
If you have any idea for an improvement or found a bug do not hesitate to open an issue.
And if you have time clone this repo and submit a pull request and help me make Grafana the
kickass metrics & devops dashboard we all dream about!
Prerequisites:
- Nodejs (for jshint & grunt & development server)
Clone repository:
npm install
grunt server (starts development web server in src folder)
grunt (runs jshint and less -> css compilation)
Please remember to run grunt before doing pull request to verify that your code passes all the jshint validations.

268
Godeps/Godeps.json generated
View File

@@ -1,6 +1,7 @@
{
"ImportPath": "github.com/grafana/grafana",
"GoVersion": "go1.4.2",
"GoVersion": "go1.5.1",
"GodepVersion": "v60",
"Packages": [
"./pkg/..."
],
@@ -15,52 +16,263 @@
"Rev": "d9bcf409c8a368d06c9b347705c381e7c12d54df"
},
{
"ImportPath": "github.com/Unknwon/macaron",
"Rev": "93de4f3fad97bf246b838f828e2348f46f21f20a"
"ImportPath": "github.com/aws/aws-sdk-go/aws",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/aws/awserr",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/aws/awsutil",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/aws/client",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/aws/client/metadata",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/aws/corehandlers",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/aws/credentials",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/aws/defaults",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/aws/ec2metadata",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/aws/request",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/aws/session",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/private/endpoints",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/ec2query",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/query",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/query/queryutil",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/rest",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/private/signer/v4",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/private/waiter",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/service/cloudwatch",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/aws/aws-sdk-go/service/ec2",
"Comment": "v1.0.0",
"Rev": "abb928e07c4108683d6b4d0b6ca08fe6bc0eee5f"
},
{
"ImportPath": "github.com/bmizerany/assert",
"Comment": "release.r60-6-ge17e998",
"Rev": "e17e99893cb6509f428e1728281c2ad60a6b31e3"
},
{
"ImportPath": "github.com/bradfitz/gomemcache/memcache",
"Comment": "release.r60-40-g72a6864",
"Rev": "72a68649ba712ee7c4b5b4a943a626bcd7d90eb8"
},
{
"ImportPath": "github.com/codegangsta/cli",
"Comment": "1.2.0-187-gc31a797",
"Rev": "c31a7975863e7810c92e2e288a9ab074f9a88f29"
},
{
"ImportPath": "github.com/davecgh/go-spew/spew",
"Rev": "2df174808ee097f90d259e432cc04442cf60be21"
},
{
"ImportPath": "github.com/fatih/color",
"Comment": "v0.1-16-g4f7bcef",
"Rev": "4f7bcef27eec7925456d0c30c5e7b0408b3339be"
},
{
"ImportPath": "github.com/franela/goreq",
"Rev": "3ddeded65be21dacb5a2e2d0b95af9ff6862a2b5"
},
{
"ImportPath": "github.com/go-ini/ini",
"Comment": "v0-48-g060d7da",
"Rev": "060d7da055ba6ec5ea7a31f116332fe5efa04ce0"
},
{
"ImportPath": "github.com/go-ldap/ldap",
"Comment": "v1-19-g83e6542",
"Rev": "83e65426fd1c06626e88aa8a085e5bfed0208e29"
"Comment": "v2.2.1",
"Rev": "07a7330929b9ee80495c88a4439657d89c7dbd87"
},
{
"ImportPath": "github.com/go-macaron/binding",
"Rev": "2502aaf4bce3a4e6451b4610847bfb8dffdb6266"
},
{
"ImportPath": "github.com/go-macaron/gzip",
"Rev": "4938e9be6b279d8426cb1c89a6bcf7af70b0c21d"
},
{
"ImportPath": "github.com/go-macaron/inject",
"Rev": "c5ab7bf3a307593cd44cb272d1a5beea473dd072"
},
{
"ImportPath": "github.com/go-macaron/session",
"Rev": "66031fcb37a0fff002a1f028eb0b3a815c78306b"
},
{
"ImportPath": "github.com/go-macaron/session/memcache",
"Rev": "66031fcb37a0fff002a1f028eb0b3a815c78306b"
},
{
"ImportPath": "github.com/go-macaron/session/mysql",
"Rev": "66031fcb37a0fff002a1f028eb0b3a815c78306b"
},
{
"ImportPath": "github.com/go-macaron/session/postgres",
"Rev": "66031fcb37a0fff002a1f028eb0b3a815c78306b"
},
{
"ImportPath": "github.com/go-macaron/session/redis",
"Rev": "66031fcb37a0fff002a1f028eb0b3a815c78306b"
},
{
"ImportPath": "github.com/go-sql-driver/mysql",
"Comment": "v1.2-26-g9543750",
"Rev": "9543750295406ef070f7de8ae9c43ccddd44e15e"
"Comment": "v1.2-171-g267b128",
"Rev": "267b128680c46286b9ca13475c3cca5de8f79bd7"
},
{
"ImportPath": "github.com/go-xorm/core",
"Rev": "be6e7ac47dc57bd0ada25322fa526944f66ccaa6"
"Comment": "v0.4.4-7-g9e608f7",
"Rev": "9e608f7330b9d16fe2818cfe731128b3f156cb9a"
},
{
"ImportPath": "github.com/go-xorm/xorm",
"Comment": "v0.4.2-58-ge2889e5",
"Rev": "e2889e5517600b82905f1d2ba8b70deb71823ffe"
"Comment": "v0.4.4-44-gf561133",
"Rev": "f56113384f2c63dfe4cd8e768e349f1c35122b58"
},
{
"ImportPath": "github.com/gorilla/websocket",
"Rev": "c45a635370221f34fea2d5163fd156fcb4e38e8a"
},
{
"ImportPath": "github.com/gosimple/slug",
"Rev": "8d258463b4459f161f51d6a357edacd3eef9d663"
},
{
"ImportPath": "github.com/hashicorp/go-version",
"Rev": "7e3c02b30806fa5779d3bdfc152ce4c6f40e7b38"
},
{
"ImportPath": "github.com/jmespath/go-jmespath",
"Comment": "0.2.2",
"Rev": "3433f3ea46d9f8019119e7dd41274e112a2359a9"
},
{
"ImportPath": "github.com/jtolds/gls",
"Rev": "f1ac7f4f24f50328e6bc838ca4437d1612a0243c"
},
{
"ImportPath": "github.com/klauspost/compress/flate",
"Rev": "7b02889a2005228347aef0e76beeaee564d82f8c"
},
{
"ImportPath": "github.com/klauspost/compress/gzip",
"Rev": "7b02889a2005228347aef0e76beeaee564d82f8c"
},
{
"ImportPath": "github.com/klauspost/cpuid",
"Rev": "349c675778172472f5e8f3a3e0fe187e302e5a10"
},
{
"ImportPath": "github.com/klauspost/crc32",
"Rev": "6834731faf32e62a2dd809d99fb24d1e4ae5a92d"
},
{
"ImportPath": "github.com/kr/pretty",
"Comment": "go.weekly.2011-12-22-27-ge6ac2fc",
"Rev": "e6ac2fc51e89a3249e82157fa0bb7a18ef9dd5bb"
},
{
"ImportPath": "github.com/kr/text",
"Rev": "bb797dc4fb8320488f47bf11de07a733d7233e1f"
},
{
"ImportPath": "github.com/lib/pq",
"Comment": "go1.0-cutoff-13-g19eeca3",
"Rev": "19eeca3e30d2577b1761db471ec130810e67f532"
},
{
"ImportPath": "github.com/macaron-contrib/binding",
"Rev": "0fbe4b9707e6eb556ef843e5471592f55ce0a5e7"
"ImportPath": "github.com/lib/pq/oid",
"Comment": "go1.0-cutoff-13-g19eeca3",
"Rev": "19eeca3e30d2577b1761db471ec130810e67f532"
},
{
"ImportPath": "github.com/macaron-contrib/session",
"Rev": "31e841d95c7302b9ac456c830ea2d6dfcef4f84a"
"ImportPath": "github.com/mattn/go-colorable",
"Rev": "9cbef7c35391cca05f15f8181dc0b18bc9736dbb"
},
{
"ImportPath": "github.com/mattn/go-isatty",
"Rev": "56b76bdf51f7708750eac80fa38b952bb9f32639"
},
{
"ImportPath": "github.com/mattn/go-sqlite3",
@@ -75,6 +287,26 @@
"Comment": "1.5.0-356-gfbc0a1c",
"Rev": "fbc0a1c888f9f96263f9a559d1769905245f1123"
},
{
"ImportPath": "github.com/smartystreets/goconvey/convey/assertions",
"Comment": "1.5.0-356-gfbc0a1c",
"Rev": "fbc0a1c888f9f96263f9a559d1769905245f1123"
},
{
"ImportPath": "github.com/smartystreets/goconvey/convey/assertions/oglematchers",
"Comment": "1.5.0-356-gfbc0a1c",
"Rev": "fbc0a1c888f9f96263f9a559d1769905245f1123"
},
{
"ImportPath": "github.com/smartystreets/goconvey/convey/gotest",
"Comment": "1.5.0-356-gfbc0a1c",
"Rev": "fbc0a1c888f9f96263f9a559d1769905245f1123"
},
{
"ImportPath": "github.com/smartystreets/goconvey/convey/reporting",
"Comment": "1.5.0-356-gfbc0a1c",
"Rev": "fbc0a1c888f9f96263f9a559d1769905245f1123"
},
{
"ImportPath": "github.com/streadway/amqp",
"Rev": "150b7f24d6ad507e6026c13d85ce1f1391ac7400"
@@ -87,6 +319,10 @@
"ImportPath": "golang.org/x/oauth2",
"Rev": "c58fcf0ffc1c772aa2e1ee4894bc19f2649263b2"
},
{
"ImportPath": "golang.org/x/sys/unix",
"Rev": "7a56174f0086b32866ebd746a794417edbc678a1"
},
{
"ImportPath": "gopkg.in/asn1-ber.v1",
"Comment": "v1",
@@ -102,6 +338,10 @@
"Comment": "v0-16-g1772191",
"Rev": "177219109c97e7920c933e21c9b25f874357b237"
},
{
"ImportPath": "gopkg.in/macaron.v1",
"Rev": "1c6dd87797ae9319b4658cbd48d1d0420b279fd5"
},
{
"ImportPath": "gopkg.in/redis.v2",
"Comment": "v2.3.2",

View File

@@ -1,94 +0,0 @@
Macaron [![Build Status](https://drone.io/github.com/Unknwon/macaron/status.png)](https://drone.io/github.com/Unknwon/macaron/latest) [![](http://gocover.io/_badge/github.com/Unknwon/macaron)](http://gocover.io/github.com/Unknwon/macaron)
=======================
![Macaron Logo](https://raw.githubusercontent.com/Unknwon/macaron/master/macaronlogo.png)
Package macaron is a high productive and modular design web framework in Go.
##### Current version: 0.5.4
## Getting Started
To install Macaron:
go get github.com/Unknwon/macaron
The very basic usage of Macaron:
```go
package main
import "github.com/Unknwon/macaron"
func main() {
m := macaron.Classic()
m.Get("/", func() string {
return "Hello world!"
})
m.Run()
}
```
## Features
- Powerful routing with suburl.
- Flexible routes combinations.
- Unlimited nested group routers.
- Directly integrate with existing services.
- Dynamically change template files at runtime.
- Allow to use in-memory template and static files.
- Easy to plugin/unplugin features with modular design.
- Handy dependency injection powered by [inject](https://github.com/codegangsta/inject).
- Better router layer and less reflection make faster speed.
## Middlewares
Middlewares allow you easily plugin/unplugin features for your Macaron applications.
There are already many [middlewares](https://github.com/macaron-contrib) to simplify your work:
- gzip - Gzip compression to all requests
- render - Go template engine
- static - Serves static files
- [binding](https://github.com/macaron-contrib/binding) - Request data binding and validation
- [i18n](https://github.com/macaron-contrib/i18n) - Internationalization and Localization
- [cache](https://github.com/macaron-contrib/cache) - Cache manager
- [session](https://github.com/macaron-contrib/session) - Session manager
- [csrf](https://github.com/macaron-contrib/csrf) - Generates and validates csrf tokens
- [captcha](https://github.com/macaron-contrib/captcha) - Captcha service
- [pongo2](https://github.com/macaron-contrib/pongo2) - Pongo2 template engine support
- [sockets](https://github.com/macaron-contrib/sockets) - WebSockets channels binding
- [bindata](https://github.com/macaron-contrib/bindata) - Embed binary data as static and template files
- [toolbox](https://github.com/macaron-contrib/toolbox) - Health check, pprof, profile and statistic services
- [oauth2](https://github.com/macaron-contrib/oauth2) - OAuth 2.0 backend
- [switcher](https://github.com/macaron-contrib/switcher) - Multiple-site support
- [method](https://github.com/macaron-contrib/method) - HTTP method override
- [permissions2](https://github.com/xyproto/permissions2) - Cookies, users and permissions
- [renders](https://github.com/macaron-contrib/renders) - Beego-like render engine(Macaron has built-in template engine, this is another option)
## Use Cases
- [Gogs](https://github.com/gogits/gogs): Go Git Service
- [Gogs Web](https://github.com/gogits/gogsweb): Gogs official website
- [Go Walker](https://gowalker.org): Go online API documentation
- [Switch](https://github.com/gpmgo/switch): Gopm registry
- [YouGam](http://yougam.com): Online Forum
- [Car Girl](http://qcnl.gzsy.com/): Online campaign
- [Critical Stack Intel](https://intel.criticalstack.com/): A 100% free intel marketplace from Critical Stack, Inc.
## Getting Help
- [API Reference](https://gowalker.org/github.com/Unknwon/macaron)
- [Documentation](http://macaron.gogs.io)
- [FAQs](http://macaron.gogs.io/docs/faqs)
- [![Join the chat at https://gitter.im/Unknwon/macaron](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/Unknwon/macaron?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
## Credits
- Basic design of [Martini](https://github.com/go-martini/martini).
- Router layer of [beego](https://github.com/astaxie/beego).
- Logo is modified by [@insionng](https://github.com/insionng) based on [Tribal Dragon](http://xtremeyamazaki.deviantart.com/art/Tribal-Dragon-27005087).
## License
This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text.

View File

@@ -1,370 +0,0 @@
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package macaron
import (
"bytes"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
"time"
"github.com/Unknwon/com"
. "github.com/smartystreets/goconvey/convey"
)
func Test_Context(t *testing.T) {
Convey("Do advanced encapsulation operations", t, func() {
m := Classic()
m.Use(Renderers(RenderOptions{
Directory: "fixtures/basic",
}, "fixtures/basic2"))
Convey("Get request body", func() {
m.Get("/body1", func(ctx *Context) {
data, err := ioutil.ReadAll(ctx.Req.Body().ReadCloser())
So(err, ShouldBeNil)
So(string(data), ShouldEqual, "This is my request body")
})
m.Get("/body2", func(ctx *Context) {
data, err := ctx.Req.Body().Bytes()
So(err, ShouldBeNil)
So(string(data), ShouldEqual, "This is my request body")
})
m.Get("/body3", func(ctx *Context) {
data, err := ctx.Req.Body().String()
So(err, ShouldBeNil)
So(data, ShouldEqual, "This is my request body")
})
for i := 1; i <= 3; i++ {
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/body"+com.ToStr(i), nil)
req.Body = ioutil.NopCloser(bytes.NewBufferString("This is my request body"))
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
}
})
Convey("Get remote IP address", func() {
m.Get("/remoteaddr", func(ctx *Context) string {
return ctx.RemoteAddr()
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/remoteaddr", nil)
req.RemoteAddr = "127.0.0.1:3333"
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "127.0.0.1")
})
Convey("Render HTML", func() {
Convey("Normal HTML", func() {
m.Get("/html", func(ctx *Context) {
ctx.HTML(304, "hello", "Unknwon") // 304 for logger test.
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/html", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "<h1>Hello Unknwon</h1>")
})
Convey("HTML template set", func() {
m.Get("/html2", func(ctx *Context) {
ctx.Data["Name"] = "Unknwon"
ctx.HTMLSet(200, "basic2", "hello2")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/html2", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "<h1>Hello Unknwon</h1>")
})
Convey("With layout", func() {
m.Get("/layout", func(ctx *Context) {
ctx.HTML(200, "hello", "Unknwon", HTMLOptions{"layout"})
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/layout", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "head<h1>Hello Unknwon</h1>foot")
})
})
Convey("Parse from and query", func() {
m.Get("/query", func(ctx *Context) string {
var buf bytes.Buffer
buf.WriteString(ctx.QueryTrim("name") + " ")
buf.WriteString(ctx.QueryEscape("name") + " ")
buf.WriteString(com.ToStr(ctx.QueryInt("int")) + " ")
buf.WriteString(com.ToStr(ctx.QueryInt64("int64")) + " ")
buf.WriteString(com.ToStr(ctx.QueryFloat64("float64")) + " ")
return buf.String()
})
m.Get("/query2", func(ctx *Context) string {
var buf bytes.Buffer
buf.WriteString(strings.Join(ctx.QueryStrings("list"), ",") + " ")
buf.WriteString(strings.Join(ctx.QueryStrings("404"), ",") + " ")
return buf.String()
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/query?name=Unknwon&int=12&int64=123&float64=1.25", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "Unknwon Unknwon 12 123 1.25 ")
resp = httptest.NewRecorder()
req, err = http.NewRequest("GET", "/query2?list=item1&list=item2", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "item1,item2 ")
})
Convey("URL parameter", func() {
m.Get("/:name/:int/:int64/:float64", func(ctx *Context) string {
var buf bytes.Buffer
ctx.SetParams("name", ctx.Params("name"))
buf.WriteString(ctx.Params(""))
buf.WriteString(ctx.Params(":name") + " ")
buf.WriteString(ctx.ParamsEscape(":name") + " ")
buf.WriteString(com.ToStr(ctx.ParamsInt(":int")) + " ")
buf.WriteString(com.ToStr(ctx.ParamsInt64(":int64")) + " ")
buf.WriteString(com.ToStr(ctx.ParamsFloat64(":float64")) + " ")
return buf.String()
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/user/1/13/1.24", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "user user 1 13 1.24 ")
})
Convey("Get file", func() {
m.Get("/getfile", func(ctx *Context) {
ctx.GetFile("hi")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/getfile", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
})
Convey("Set and get cookie", func() {
m.Get("/set", func(ctx *Context) {
ctx.SetCookie("user", "Unknwon", 1, "/", "localhost", true, true)
ctx.SetCookie("user", "Unknwon", int32(1), "/", "localhost", 1)
ctx.SetCookie("user", "Unknwon", int64(1))
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/set", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Header().Get("Set-Cookie"), ShouldEqual, "user=Unknwon; Path=/; Domain=localhost; Max-Age=1; HttpOnly; Secure")
m.Get("/get", func(ctx *Context) string {
ctx.GetCookie("404")
So(ctx.GetCookieInt("uid"), ShouldEqual, 1)
So(ctx.GetCookieInt64("uid"), ShouldEqual, 1)
So(ctx.GetCookieFloat64("balance"), ShouldEqual, 1.25)
return ctx.GetCookie("user")
})
resp = httptest.NewRecorder()
req, err = http.NewRequest("GET", "/get", nil)
So(err, ShouldBeNil)
req.Header.Set("Cookie", "user=Unknwon; uid=1; balance=1.25")
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "Unknwon")
})
Convey("Set and get secure cookie", func() {
m.SetDefaultCookieSecret("macaron")
m.Get("/set", func(ctx *Context) {
ctx.SetSecureCookie("user", "Unknwon", 1)
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/set", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
cookie := resp.Header().Get("Set-Cookie")
m.Get("/get", func(ctx *Context) string {
name, ok := ctx.GetSecureCookie("user")
So(ok, ShouldBeTrue)
return name
})
resp = httptest.NewRecorder()
req, err = http.NewRequest("GET", "/get", nil)
So(err, ShouldBeNil)
req.Header.Set("Cookie", cookie)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "Unknwon")
})
Convey("Serve files", func() {
m.Get("/file", func(ctx *Context) {
ctx.ServeFile("fixtures/custom_funcs/index.tmpl")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/file", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "{{ myCustomFunc }}")
m.Get("/file2", func(ctx *Context) {
ctx.ServeFile("fixtures/custom_funcs/index.tmpl", "ok.tmpl")
})
resp = httptest.NewRecorder()
req, err = http.NewRequest("GET", "/file2", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "{{ myCustomFunc }}")
})
Convey("Serve file content", func() {
m.Get("/file", func(ctx *Context) {
ctx.ServeFileContent("fixtures/custom_funcs/index.tmpl")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/file", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "{{ myCustomFunc }}")
m.Get("/file2", func(ctx *Context) {
ctx.ServeFileContent("fixtures/custom_funcs/index.tmpl", "ok.tmpl")
})
resp = httptest.NewRecorder()
req, err = http.NewRequest("GET", "/file2", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "{{ myCustomFunc }}")
m.Get("/file3", func(ctx *Context) {
ctx.ServeFileContent("404.tmpl")
})
resp = httptest.NewRecorder()
req, err = http.NewRequest("GET", "/file3", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "open 404.tmpl: no such file or directory\n")
So(resp.Code, ShouldEqual, 500)
})
Convey("Serve content", func() {
m.Get("/content", func(ctx *Context) {
ctx.ServeContent("content1", bytes.NewReader([]byte("Hello world!")))
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/content", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "Hello world!")
m.Get("/content2", func(ctx *Context) {
ctx.ServeContent("content1", bytes.NewReader([]byte("Hello world!")), time.Now())
})
resp = httptest.NewRecorder()
req, err = http.NewRequest("GET", "/content2", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "Hello world!")
})
})
}
func Test_Context_Render(t *testing.T) {
Convey("Invalid render", t, func() {
defer func() {
So(recover(), ShouldNotBeNil)
}()
m := New()
m.Get("/", func(ctx *Context) {
ctx.HTML(200, "hey")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
})
}
func Test_Context_Redirect(t *testing.T) {
Convey("Context with default redirect", t, func() {
url, err := url.Parse("http://localhost/path/one")
So(err, ShouldBeNil)
resp := httptest.NewRecorder()
req := http.Request{
Method: "GET",
URL: url,
}
ctx := &Context{
Req: Request{&req},
Resp: NewResponseWriter(resp),
Data: make(map[string]interface{}),
}
ctx.Redirect("two")
So(resp.Code, ShouldEqual, http.StatusFound)
So(resp.HeaderMap["Location"][0], ShouldEqual, "/path/two")
})
Convey("Context with custom redirect", t, func() {
url, err := url.Parse("http://localhost/path/one")
So(err, ShouldBeNil)
resp := httptest.NewRecorder()
req := http.Request{
Method: "GET",
URL: url,
}
ctx := &Context{
Req: Request{&req},
Resp: NewResponseWriter(resp),
Data: make(map[string]interface{}),
}
ctx.Redirect("two", 307)
So(resp.Code, ShouldEqual, http.StatusTemporaryRedirect)
So(resp.HeaderMap["Location"][0], ShouldEqual, "/path/two")
})
}

View File

@@ -1,81 +0,0 @@
// Copyright 2013 Martini Authors
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package macaron
import (
"bufio"
"compress/gzip"
"fmt"
"net"
"net/http"
"strings"
)
const (
HeaderAcceptEncoding = "Accept-Encoding"
HeaderContentEncoding = "Content-Encoding"
HeaderContentLength = "Content-Length"
HeaderContentType = "Content-Type"
HeaderVary = "Vary"
)
// Gziper returns a Handler that adds gzip compression to all requests.
// Make sure to include the Gzip middleware above other middleware
// that alter the response body (like the render middleware).
func Gziper() Handler {
return func(ctx *Context) {
if !strings.Contains(ctx.Req.Header.Get(HeaderAcceptEncoding), "gzip") {
return
}
headers := ctx.Resp.Header()
headers.Set(HeaderContentEncoding, "gzip")
headers.Set(HeaderVary, HeaderAcceptEncoding)
gz := gzip.NewWriter(ctx.Resp)
defer gz.Close()
gzw := gzipResponseWriter{gz, ctx.Resp}
ctx.Resp = gzw
ctx.MapTo(gzw, (*http.ResponseWriter)(nil))
ctx.Next()
// delete content length after we know we have been written to
gzw.Header().Del("Content-Length")
}
}
type gzipResponseWriter struct {
w *gzip.Writer
ResponseWriter
}
func (grw gzipResponseWriter) Write(p []byte) (int, error) {
if len(grw.Header().Get(HeaderContentType)) == 0 {
grw.Header().Set(HeaderContentType, http.DetectContentType(p))
}
return grw.w.Write(p)
}
func (grw gzipResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
hijacker, ok := grw.ResponseWriter.(http.Hijacker)
if !ok {
return nil, nil, fmt.Errorf("the ResponseWriter doesn't support the Hijacker interface")
}
return hijacker.Hijack()
}

View File

@@ -1,65 +0,0 @@
// Copyright 2013 Martini Authors
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package macaron
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_Gzip(t *testing.T) {
Convey("Gzip response content", t, func() {
before := false
m := New()
m.Use(Gziper())
m.Use(func(r http.ResponseWriter) {
r.(ResponseWriter).Before(func(rw ResponseWriter) {
before = true
})
})
m.Get("/", func() string { return "hello wolrd!" })
// Not yet gzip.
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
_, ok := resp.HeaderMap[HeaderContentEncoding]
So(ok, ShouldBeFalse)
ce := resp.Header().Get(HeaderContentEncoding)
So(strings.EqualFold(ce, "gzip"), ShouldBeFalse)
// Gzip now.
resp = httptest.NewRecorder()
req.Header.Set(HeaderAcceptEncoding, "gzip")
m.ServeHTTP(resp, req)
_, ok = resp.HeaderMap[HeaderContentEncoding]
So(ok, ShouldBeTrue)
ce = resp.Header().Get(HeaderContentEncoding)
So(strings.EqualFold(ce, "gzip"), ShouldBeTrue)
So(before, ShouldBeTrue)
})
}

View File

@@ -1,4 +0,0 @@
inject
======
Dependency injection for go

View File

@@ -1 +0,0 @@
ignore

View File

@@ -1,174 +0,0 @@
// Copyright 2013 Martini Authors
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package inject_test
import (
"fmt"
"reflect"
"testing"
"github.com/Unknwon/macaron/inject"
)
type SpecialString interface {
}
type TestStruct struct {
Dep1 string `inject:"t" json:"-"`
Dep2 SpecialString `inject`
Dep3 string
}
type Greeter struct {
Name string
}
func (g *Greeter) String() string {
return "Hello, My name is" + g.Name
}
/* Test Helpers */
func expect(t *testing.T, a interface{}, b interface{}) {
if a != b {
t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}
func refute(t *testing.T, a interface{}, b interface{}) {
if a == b {
t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a))
}
}
func Test_InjectorInvoke(t *testing.T) {
injector := inject.New()
expect(t, injector == nil, false)
dep := "some dependency"
injector.Map(dep)
dep2 := "another dep"
injector.MapTo(dep2, (*SpecialString)(nil))
dep3 := make(chan *SpecialString)
dep4 := make(chan *SpecialString)
typRecv := reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(dep3).Elem())
typSend := reflect.ChanOf(reflect.SendDir, reflect.TypeOf(dep4).Elem())
injector.Set(typRecv, reflect.ValueOf(dep3))
injector.Set(typSend, reflect.ValueOf(dep4))
_, err := injector.Invoke(func(d1 string, d2 SpecialString, d3 <-chan *SpecialString, d4 chan<- *SpecialString) {
expect(t, d1, dep)
expect(t, d2, dep2)
expect(t, reflect.TypeOf(d3).Elem(), reflect.TypeOf(dep3).Elem())
expect(t, reflect.TypeOf(d4).Elem(), reflect.TypeOf(dep4).Elem())
expect(t, reflect.TypeOf(d3).ChanDir(), reflect.RecvDir)
expect(t, reflect.TypeOf(d4).ChanDir(), reflect.SendDir)
})
expect(t, err, nil)
}
func Test_InjectorInvokeReturnValues(t *testing.T) {
injector := inject.New()
expect(t, injector == nil, false)
dep := "some dependency"
injector.Map(dep)
dep2 := "another dep"
injector.MapTo(dep2, (*SpecialString)(nil))
result, err := injector.Invoke(func(d1 string, d2 SpecialString) string {
expect(t, d1, dep)
expect(t, d2, dep2)
return "Hello world"
})
expect(t, result[0].String(), "Hello world")
expect(t, err, nil)
}
func Test_InjectorApply(t *testing.T) {
injector := inject.New()
injector.Map("a dep").MapTo("another dep", (*SpecialString)(nil))
s := TestStruct{}
err := injector.Apply(&s)
expect(t, err, nil)
expect(t, s.Dep1, "a dep")
expect(t, s.Dep2, "another dep")
}
func Test_InterfaceOf(t *testing.T) {
iType := inject.InterfaceOf((*SpecialString)(nil))
expect(t, iType.Kind(), reflect.Interface)
iType = inject.InterfaceOf((**SpecialString)(nil))
expect(t, iType.Kind(), reflect.Interface)
// Expecting nil
defer func() {
rec := recover()
refute(t, rec, nil)
}()
iType = inject.InterfaceOf((*testing.T)(nil))
}
func Test_InjectorSet(t *testing.T) {
injector := inject.New()
typ := reflect.TypeOf("string")
typSend := reflect.ChanOf(reflect.SendDir, typ)
typRecv := reflect.ChanOf(reflect.RecvDir, typ)
// instantiating unidirectional channels is not possible using reflect
// http://golang.org/src/pkg/reflect/value.go?s=60463:60504#L2064
chanRecv := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0)
chanSend := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0)
injector.Set(typSend, chanSend)
injector.Set(typRecv, chanRecv)
expect(t, injector.GetVal(typSend).IsValid(), true)
expect(t, injector.GetVal(typRecv).IsValid(), true)
expect(t, injector.GetVal(chanSend.Type()).IsValid(), false)
}
func Test_InjectorGet(t *testing.T) {
injector := inject.New()
injector.Map("some dependency")
expect(t, injector.GetVal(reflect.TypeOf("string")).IsValid(), true)
expect(t, injector.GetVal(reflect.TypeOf(11)).IsValid(), false)
}
func Test_InjectorSetParent(t *testing.T) {
injector := inject.New()
injector.MapTo("another dep", (*SpecialString)(nil))
injector2 := inject.New()
injector2.SetParent(injector)
expect(t, injector2.GetVal(inject.InterfaceOf((*SpecialString)(nil))).IsValid(), true)
}
func TestInjectImplementors(t *testing.T) {
injector := inject.New()
g := &Greeter{"Jeremy"}
injector.Map(g)
expect(t, injector.GetVal(inject.InterfaceOf((*fmt.Stringer)(nil))).IsValid(), true)
}

View File

@@ -1,67 +0,0 @@
// Copyright 2013 Martini Authors
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package macaron
import (
"bytes"
"log"
"net/http"
"net/http/httptest"
"testing"
"github.com/Unknwon/com"
. "github.com/smartystreets/goconvey/convey"
)
func Test_Logger(t *testing.T) {
Convey("Global logger", t, func() {
buf := bytes.NewBufferString("")
m := New()
m.Map(log.New(buf, "[Macaron] ", 0))
m.Use(Logger())
m.Use(func(res http.ResponseWriter) {
res.WriteHeader(http.StatusNotFound)
})
m.Get("/", func() {})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://localhost:4000/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusNotFound)
So(len(buf.String()), ShouldBeGreaterThan, 0)
})
if ColorLog {
Convey("Color console output", t, func() {
m := Classic()
m.Get("/:code:int", func(ctx *Context) (int, string) {
return ctx.ParamsInt(":code"), ""
})
// Just for testing if logger would capture.
codes := []int{200, 201, 202, 301, 302, 304, 401, 403, 404, 500}
for _, code := range codes {
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://localhost:4000/"+com.ToStr(code), nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, code)
}
})
}
}

View File

@@ -1,218 +0,0 @@
// Copyright 2013 Martini Authors
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package macaron
import (
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func Test_Version(t *testing.T) {
Convey("Get version", t, func() {
So(Version(), ShouldEqual, _VERSION)
})
}
func Test_New(t *testing.T) {
Convey("Initialize a new instance", t, func() {
So(New(), ShouldNotBeNil)
})
Convey("Just test that Run doesn't bomb", t, func() {
go New().Run()
time.Sleep(1 * time.Second)
os.Setenv("PORT", "4001")
go New().Run("0.0.0.0")
go New().Run(4002)
go New().Run("0.0.0.0", 4003)
})
}
func Test_Macaron_Before(t *testing.T) {
Convey("Register before handlers", t, func() {
m := New()
m.Before(func(rw http.ResponseWriter, req *http.Request) bool {
return false
})
m.Before(func(rw http.ResponseWriter, req *http.Request) bool {
return true
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
})
}
func Test_Macaron_ServeHTTP(t *testing.T) {
Convey("Serve HTTP requests", t, func() {
result := ""
m := New()
m.Use(func(c *Context) {
result += "foo"
c.Next()
result += "ban"
})
m.Use(func(c *Context) {
result += "bar"
c.Next()
result += "baz"
})
m.Get("/", func() {})
m.Action(func(res http.ResponseWriter, req *http.Request) {
result += "bat"
res.WriteHeader(http.StatusBadRequest)
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(result, ShouldEqual, "foobarbatbazban")
So(resp.Code, ShouldEqual, http.StatusBadRequest)
})
}
func Test_Macaron_Handlers(t *testing.T) {
Convey("Add custom handlers", t, func() {
result := ""
batman := func(c *Context) {
result += "batman!"
}
m := New()
m.Use(func(c *Context) {
result += "foo"
c.Next()
result += "ban"
})
m.Handlers(
batman,
batman,
batman,
)
Convey("Add not callable function", func() {
defer func() {
So(recover(), ShouldNotBeNil)
}()
m.Use("shit")
})
m.Get("/", func() {})
m.Action(func(res http.ResponseWriter, req *http.Request) {
result += "bat"
res.WriteHeader(http.StatusBadRequest)
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(result, ShouldEqual, "batman!batman!batman!bat")
So(resp.Code, ShouldEqual, http.StatusBadRequest)
})
}
func Test_Macaron_EarlyWrite(t *testing.T) {
Convey("Write early content to response", t, func() {
result := ""
m := New()
m.Use(func(res http.ResponseWriter) {
result += "foobar"
res.Write([]byte("Hello world"))
})
m.Use(func() {
result += "bat"
})
m.Get("/", func() {})
m.Action(func(res http.ResponseWriter) {
result += "baz"
res.WriteHeader(http.StatusBadRequest)
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(result, ShouldEqual, "foobar")
So(resp.Code, ShouldEqual, http.StatusOK)
})
}
func Test_Macaron_Written(t *testing.T) {
Convey("Written sign", t, func() {
resp := httptest.NewRecorder()
m := New()
m.Handlers(func(res http.ResponseWriter) {
res.WriteHeader(http.StatusOK)
})
ctx := m.createContext(resp, &http.Request{Method: "GET"})
So(ctx.Written(), ShouldBeFalse)
ctx.run()
So(ctx.Written(), ShouldBeTrue)
})
}
func Test_Macaron_Basic_NoRace(t *testing.T) {
Convey("Make sure no race between requests", t, func() {
m := New()
handlers := []Handler{func() {}, func() {}}
// Ensure append will not realloc to trigger the race condition
m.handlers = handlers[:1]
m.Get("/", func() {})
req, _ := http.NewRequest("GET", "/", nil)
for i := 0; i < 2; i++ {
go func() {
resp := httptest.NewRecorder()
m.ServeHTTP(resp, req)
}()
}
})
}
func Test_SetENV(t *testing.T) {
Convey("Get and save environment variable", t, func() {
tests := []struct {
in string
out string
}{
{"", "development"},
{"not_development", "not_development"},
}
for _, test := range tests {
setENV(test.in)
So(Env, ShouldEqual, test.out)
}
})
}
func Test_Config(t *testing.T) {
Convey("Set and get configuration object", t, func() {
So(Config(), ShouldNotBeNil)
cfg, err := SetConfig([]byte(""))
So(err, ShouldBeNil)
So(cfg, ShouldNotBeNil)
})
}

View File

@@ -1,74 +0,0 @@
// Copyright 2013 Martini Authors
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package macaron
import (
"bytes"
"log"
"net/http"
"net/http/httptest"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_Recovery(t *testing.T) {
Convey("Recovery from panic", t, func() {
buf := bytes.NewBufferString("")
setENV(DEV)
m := New()
m.Map(log.New(buf, "[Macaron] ", 0))
m.Use(func(res http.ResponseWriter, req *http.Request) {
res.Header().Set("Content-Type", "unpredictable")
})
m.Use(Recovery())
m.Use(func(res http.ResponseWriter, req *http.Request) {
panic("here is a panic!")
})
m.Get("/", func() {})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusInternalServerError)
So(resp.HeaderMap.Get("Content-Type"), ShouldEqual, "text/html")
So(buf.String(), ShouldNotBeEmpty)
})
Convey("Revocery panic to another response writer", t, func() {
resp := httptest.NewRecorder()
resp2 := httptest.NewRecorder()
setENV(DEV)
m := New()
m.Use(Recovery())
m.Use(func(c *Context) {
c.MapTo(resp2, (*http.ResponseWriter)(nil))
panic("here is a panic!")
})
m.Get("/", func() {})
req, err := http.NewRequest("GET", "/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp2.Code, ShouldEqual, http.StatusInternalServerError)
So(resp2.HeaderMap.Get("Content-Type"), ShouldEqual, "text/html")
So(resp2.Body.Len(), ShouldBeGreaterThan, 0)
})
}

View File

@@ -1,581 +0,0 @@
// Copyright 2013 Martini Authors
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package macaron
import (
"encoding/xml"
"html/template"
"net/http"
"net/http/httptest"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
type Greeting struct {
One string `json:"one"`
Two string `json:"two"`
}
type GreetingXML struct {
XMLName xml.Name `xml:"greeting"`
One string `xml:"one,attr"`
Two string `xml:"two,attr"`
}
func Test_Render_JSON(t *testing.T) {
Convey("Render JSON", t, func() {
m := Classic()
m.Use(Renderer())
m.Get("/foobar", func(r Render) {
r.JSON(300, Greeting{"hello", "world"})
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusMultipleChoices)
So(resp.Header().Get(ContentType), ShouldEqual, ContentJSON+"; charset=UTF-8")
So(resp.Body.String(), ShouldEqual, `{"one":"hello","two":"world"}`)
})
Convey("Render JSON with prefix", t, func() {
m := Classic()
prefix := ")]}',\n"
m.Use(Renderer(RenderOptions{
PrefixJSON: []byte(prefix),
}))
m.Get("/foobar", func(r Render) {
r.JSON(300, Greeting{"hello", "world"})
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusMultipleChoices)
So(resp.Header().Get(ContentType), ShouldEqual, ContentJSON+"; charset=UTF-8")
So(resp.Body.String(), ShouldEqual, prefix+`{"one":"hello","two":"world"}`)
})
Convey("Render Indented JSON", t, func() {
m := Classic()
m.Use(Renderer(RenderOptions{
IndentJSON: true,
}))
m.Get("/foobar", func(r Render) {
r.JSON(300, Greeting{"hello", "world"})
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusMultipleChoices)
So(resp.Header().Get(ContentType), ShouldEqual, ContentJSON+"; charset=UTF-8")
So(resp.Body.String(), ShouldEqual, `{
"one": "hello",
"two": "world"
}`)
})
Convey("Render JSON and return string", t, func() {
m := Classic()
m.Use(Renderer())
m.Get("/foobar", func(r Render) {
result, err := r.JSONString(Greeting{"hello", "world"})
So(err, ShouldBeNil)
So(result, ShouldEqual, `{"one":"hello","two":"world"}`)
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
})
Convey("Render with charset JSON", t, func() {
m := Classic()
m.Use(Renderer(RenderOptions{
Charset: "foobar",
}))
m.Get("/foobar", func(r Render) {
r.JSON(300, Greeting{"hello", "world"})
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusMultipleChoices)
So(resp.Header().Get(ContentType), ShouldEqual, ContentJSON+"; charset=foobar")
So(resp.Body.String(), ShouldEqual, `{"one":"hello","two":"world"}`)
})
}
func Test_Render_XML(t *testing.T) {
Convey("Render XML", t, func() {
m := Classic()
m.Use(Renderer())
m.Get("/foobar", func(r Render) {
r.XML(300, GreetingXML{One: "hello", Two: "world"})
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusMultipleChoices)
So(resp.Header().Get(ContentType), ShouldEqual, ContentXML+"; charset=UTF-8")
So(resp.Body.String(), ShouldEqual, `<greeting one="hello" two="world"></greeting>`)
})
Convey("Render XML with prefix", t, func() {
m := Classic()
prefix := ")]}',\n"
m.Use(Renderer(RenderOptions{
PrefixXML: []byte(prefix),
}))
m.Get("/foobar", func(r Render) {
r.XML(300, GreetingXML{One: "hello", Two: "world"})
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusMultipleChoices)
So(resp.Header().Get(ContentType), ShouldEqual, ContentXML+"; charset=UTF-8")
So(resp.Body.String(), ShouldEqual, prefix+`<greeting one="hello" two="world"></greeting>`)
})
Convey("Render Indented XML", t, func() {
m := Classic()
m.Use(Renderer(RenderOptions{
IndentXML: true,
}))
m.Get("/foobar", func(r Render) {
r.XML(300, GreetingXML{One: "hello", Two: "world"})
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusMultipleChoices)
So(resp.Header().Get(ContentType), ShouldEqual, ContentXML+"; charset=UTF-8")
So(resp.Body.String(), ShouldEqual, `<greeting one="hello" two="world"></greeting>`)
})
}
func Test_Render_HTML(t *testing.T) {
Convey("Render HTML", t, func() {
m := Classic()
m.Use(Renderers(RenderOptions{
Directory: "fixtures/basic",
}, "fixtures/basic2"))
m.Get("/foobar", func(r Render) {
r.HTML(200, "hello", "jeremy")
r.SetTemplatePath("", "fixtures/basic2")
})
m.Get("/foobar2", func(r Render) {
if r.HasTemplateSet("basic2") {
r.HTMLSet(200, "basic2", "hello", "jeremy")
}
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Header().Get(ContentType), ShouldEqual, ContentHTML+"; charset=UTF-8")
So(resp.Body.String(), ShouldEqual, "<h1>Hello jeremy</h1>")
resp = httptest.NewRecorder()
req, err = http.NewRequest("GET", "/foobar2", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Header().Get(ContentType), ShouldEqual, ContentHTML+"; charset=UTF-8")
So(resp.Body.String(), ShouldEqual, "<h1>What's up, jeremy</h1>")
Convey("Change render templates path", func() {
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Header().Get(ContentType), ShouldEqual, ContentHTML+"; charset=UTF-8")
So(resp.Body.String(), ShouldEqual, "<h1>What's up, jeremy</h1>")
})
})
Convey("Render HTML and return string", t, func() {
m := Classic()
m.Use(Renderers(RenderOptions{
Directory: "fixtures/basic",
}, "basic2:fixtures/basic2"))
m.Get("/foobar", func(r Render) {
result, err := r.HTMLString("hello", "jeremy")
So(err, ShouldBeNil)
So(result, ShouldEqual, "<h1>Hello jeremy</h1>")
})
m.Get("/foobar2", func(r Render) {
result, err := r.HTMLSetString("basic2", "hello", "jeremy")
So(err, ShouldBeNil)
So(result, ShouldEqual, "<h1>What's up, jeremy</h1>")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
resp = httptest.NewRecorder()
req, err = http.NewRequest("GET", "/foobar2", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
})
Convey("Render with nested HTML", t, func() {
m := Classic()
m.Use(Renderer(RenderOptions{
Directory: "fixtures/basic",
}))
m.Get("/foobar", func(r Render) {
r.HTML(200, "admin/index", "jeremy")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Header().Get(ContentType), ShouldEqual, ContentHTML+"; charset=UTF-8")
So(resp.Body.String(), ShouldEqual, "<h1>Admin jeremy</h1>")
})
Convey("Render bad HTML", t, func() {
m := Classic()
m.Use(Renderer(RenderOptions{
Directory: "fixtures/basic",
}))
m.Get("/foobar", func(r Render) {
r.HTML(200, "nope", nil)
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusInternalServerError)
So(resp.Body.String(), ShouldEqual, "html/template: \"nope\" is undefined\n")
})
Convey("Invalid template set", t, func() {
Convey("Empty template set argument", func() {
defer func() {
So(recover(), ShouldNotBeNil)
}()
m := Classic()
m.Use(Renderers(RenderOptions{
Directory: "fixtures/basic",
}, ""))
})
Convey("Bad template set path", func() {
defer func() {
So(recover(), ShouldNotBeNil)
}()
m := Classic()
m.Use(Renderers(RenderOptions{
Directory: "fixtures/basic",
}, "404"))
})
})
}
func Test_Render_XHTML(t *testing.T) {
Convey("Render XHTML", t, func() {
m := Classic()
m.Use(Renderer(RenderOptions{
Directory: "fixtures/basic",
HTMLContentType: ContentXHTML,
}))
m.Get("/foobar", func(r Render) {
r.HTML(200, "hello", "jeremy")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Header().Get(ContentType), ShouldEqual, ContentXHTML+"; charset=UTF-8")
So(resp.Body.String(), ShouldEqual, "<h1>Hello jeremy</h1>")
})
}
func Test_Render_Extensions(t *testing.T) {
Convey("Render with extensions", t, func() {
m := Classic()
m.Use(Renderer(RenderOptions{
Directory: "fixtures/basic",
Extensions: []string{".tmpl", ".html"},
}))
m.Get("/foobar", func(r Render) {
r.HTML(200, "hypertext", nil)
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Header().Get(ContentType), ShouldEqual, ContentHTML+"; charset=UTF-8")
So(resp.Body.String(), ShouldEqual, "Hypertext!")
})
}
func Test_Render_Funcs(t *testing.T) {
Convey("Render with functions", t, func() {
m := Classic()
m.Use(Renderer(RenderOptions{
Directory: "fixtures/custom_funcs",
Funcs: []template.FuncMap{
{
"myCustomFunc": func() string {
return "My custom function"
},
},
},
}))
m.Get("/foobar", func(r Render) {
r.HTML(200, "index", "jeremy")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "My custom function")
})
}
func Test_Render_Layout(t *testing.T) {
Convey("Render with layout", t, func() {
m := Classic()
m.Use(Renderer(RenderOptions{
Directory: "fixtures/basic",
Layout: "layout",
}))
m.Get("/foobar", func(r Render) {
r.HTML(200, "content", "jeremy")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "head<h1>jeremy</h1>foot")
})
Convey("Render with current layout", t, func() {
m := Classic()
m.Use(Renderer(RenderOptions{
Directory: "fixtures/basic",
Layout: "current_layout",
}))
m.Get("/foobar", func(r Render) {
r.HTML(200, "content", "jeremy")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "content head<h1>jeremy</h1>content foot")
})
Convey("Render with override layout", t, func() {
m := Classic()
m.Use(Renderer(RenderOptions{
Directory: "fixtures/basic",
Layout: "layout",
}))
m.Get("/foobar", func(r Render) {
r.HTML(200, "content", "jeremy", HTMLOptions{
Layout: "another_layout",
})
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Header().Get(ContentType), ShouldEqual, ContentHTML+"; charset=UTF-8")
So(resp.Body.String(), ShouldEqual, "another head<h1>jeremy</h1>another foot")
})
}
func Test_Render_Delimiters(t *testing.T) {
Convey("Render with delimiters", t, func() {
m := Classic()
m.Use(Renderer(RenderOptions{
Delims: Delims{"{[{", "}]}"},
Directory: "fixtures/basic",
}))
m.Get("/foobar", func(r Render) {
r.HTML(200, "delims", "jeremy")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Header().Get(ContentType), ShouldEqual, ContentHTML+"; charset=UTF-8")
So(resp.Body.String(), ShouldEqual, "<h1>Hello jeremy</h1>")
})
}
func Test_Render_BinaryData(t *testing.T) {
Convey("Render binary data", t, func() {
m := Classic()
m.Use(Renderer())
m.Get("/foobar", func(r Render) {
r.RawData(200, []byte("hello there"))
})
m.Get("/foobar2", func(r Render) {
r.RenderData(200, []byte("hello there"))
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Header().Get(ContentType), ShouldEqual, ContentBinary)
So(resp.Body.String(), ShouldEqual, "hello there")
resp = httptest.NewRecorder()
req, err = http.NewRequest("GET", "/foobar2", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Header().Get(ContentType), ShouldEqual, CONTENT_PLAIN)
So(resp.Body.String(), ShouldEqual, "hello there")
})
Convey("Render binary data with mime type", t, func() {
m := Classic()
m.Use(Renderer())
m.Get("/foobar", func(r Render) {
r.RW().Header().Set(ContentType, "image/jpeg")
r.RawData(200, []byte("..jpeg data.."))
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/foobar", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Header().Get(ContentType), ShouldEqual, "image/jpeg")
So(resp.Body.String(), ShouldEqual, "..jpeg data..")
})
}
func Test_Render_Status(t *testing.T) {
Convey("Render with status 204", t, func() {
resp := httptest.NewRecorder()
r := TplRender{resp, newTemplateSet(), &RenderOptions{}, "", time.Now()}
r.Status(204)
So(resp.Code, ShouldEqual, http.StatusNoContent)
})
Convey("Render with status 404", t, func() {
resp := httptest.NewRecorder()
r := TplRender{resp, newTemplateSet(), &RenderOptions{}, "", time.Now()}
r.Error(404)
So(resp.Code, ShouldEqual, http.StatusNotFound)
})
Convey("Render with status 500", t, func() {
resp := httptest.NewRecorder()
r := TplRender{resp, newTemplateSet(), &RenderOptions{}, "", time.Now()}
r.Error(500)
So(resp.Code, ShouldEqual, http.StatusInternalServerError)
})
}
func Test_Render_NoRace(t *testing.T) {
Convey("Make sure render has no race", t, func() {
m := Classic()
m.Use(Renderer(RenderOptions{
Directory: "fixtures/basic",
}))
m.Get("/foobar", func(r Render) {
r.HTML(200, "hello", "world")
})
done := make(chan bool)
doreq := func() {
resp := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/foobar", nil)
m.ServeHTTP(resp, req)
done <- true
}
// Run two requests to check there is no race condition
go doreq()
go doreq()
<-done
<-done
})
}
func Test_GetExt(t *testing.T) {
Convey("Get extension", t, func() {
So(GetExt("test"), ShouldBeBlank)
So(GetExt("test.tmpl"), ShouldEqual, ".tmpl")
So(GetExt("test.go.tmpl"), ShouldEqual, ".go.tmpl")
})
}

View File

@@ -1,188 +0,0 @@
// Copyright 2013 Martini Authors
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package macaron
import (
"bufio"
"io"
"net"
"net/http"
"net/http/httptest"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
type closeNotifyingRecorder struct {
*httptest.ResponseRecorder
closed chan bool
}
func newCloseNotifyingRecorder() *closeNotifyingRecorder {
return &closeNotifyingRecorder{
httptest.NewRecorder(),
make(chan bool, 1),
}
}
func (c *closeNotifyingRecorder) close() {
c.closed <- true
}
func (c *closeNotifyingRecorder) CloseNotify() <-chan bool {
return c.closed
}
type hijackableResponse struct {
Hijacked bool
}
func newHijackableResponse() *hijackableResponse {
return &hijackableResponse{}
}
func (h *hijackableResponse) Header() http.Header { return nil }
func (h *hijackableResponse) Write(buf []byte) (int, error) { return 0, nil }
func (h *hijackableResponse) WriteHeader(code int) {}
func (h *hijackableResponse) Flush() {}
func (h *hijackableResponse) Hijack() (net.Conn, *bufio.ReadWriter, error) {
h.Hijacked = true
return nil, nil, nil
}
func Test_ResponseWriter(t *testing.T) {
Convey("Write string to response writer", t, func() {
resp := httptest.NewRecorder()
rw := NewResponseWriter(resp)
rw.Write([]byte("Hello world"))
So(resp.Code, ShouldEqual, rw.Status())
So(resp.Body.String(), ShouldEqual, "Hello world")
So(rw.Status(), ShouldEqual, http.StatusOK)
So(rw.Size(), ShouldEqual, 11)
So(rw.Written(), ShouldBeTrue)
})
Convey("Write strings to response writer", t, func() {
resp := httptest.NewRecorder()
rw := NewResponseWriter(resp)
rw.Write([]byte("Hello world"))
rw.Write([]byte("foo bar bat baz"))
So(resp.Code, ShouldEqual, rw.Status())
So(resp.Body.String(), ShouldEqual, "Hello worldfoo bar bat baz")
So(rw.Status(), ShouldEqual, http.StatusOK)
So(rw.Size(), ShouldEqual, 26)
So(rw.Written(), ShouldBeTrue)
})
Convey("Write header to response writer", t, func() {
resp := httptest.NewRecorder()
rw := NewResponseWriter(resp)
rw.WriteHeader(http.StatusNotFound)
So(resp.Code, ShouldEqual, rw.Status())
So(resp.Body.String(), ShouldBeBlank)
So(rw.Status(), ShouldEqual, http.StatusNotFound)
So(rw.Size(), ShouldEqual, 0)
})
Convey("Write before response write", t, func() {
result := ""
resp := httptest.NewRecorder()
rw := NewResponseWriter(resp)
rw.Before(func(ResponseWriter) {
result += "foo"
})
rw.Before(func(ResponseWriter) {
result += "bar"
})
rw.WriteHeader(http.StatusNotFound)
So(resp.Code, ShouldEqual, rw.Status())
So(resp.Body.String(), ShouldBeBlank)
So(rw.Status(), ShouldEqual, http.StatusNotFound)
So(rw.Size(), ShouldEqual, 0)
So(result, ShouldEqual, "barfoo")
})
Convey("Response writer with Hijack", t, func() {
hijackable := newHijackableResponse()
rw := NewResponseWriter(hijackable)
hijacker, ok := rw.(http.Hijacker)
So(ok, ShouldBeTrue)
_, _, err := hijacker.Hijack()
So(err, ShouldBeNil)
So(hijackable.Hijacked, ShouldBeTrue)
})
Convey("Response writer with bad Hijack", t, func() {
hijackable := new(http.ResponseWriter)
rw := NewResponseWriter(*hijackable)
hijacker, ok := rw.(http.Hijacker)
So(ok, ShouldBeTrue)
_, _, err := hijacker.Hijack()
So(err, ShouldNotBeNil)
})
Convey("Response writer with close notify", t, func() {
resp := newCloseNotifyingRecorder()
rw := NewResponseWriter(resp)
closed := false
notifier := rw.(http.CloseNotifier).CloseNotify()
resp.close()
select {
case <-notifier:
closed = true
case <-time.After(time.Second):
}
So(closed, ShouldBeTrue)
})
Convey("Response writer with flusher", t, func() {
resp := httptest.NewRecorder()
rw := NewResponseWriter(resp)
_, ok := rw.(http.Flusher)
So(ok, ShouldBeTrue)
})
Convey("Response writer with flusher handler", t, func() {
m := Classic()
m.Get("/events", func(w http.ResponseWriter, r *http.Request) {
f, ok := w.(http.Flusher)
So(ok, ShouldBeTrue)
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
for i := 0; i < 2; i++ {
time.Sleep(10 * time.Millisecond)
io.WriteString(w, "data: Hello\n\n")
f.Flush()
}
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/events", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Body.String(), ShouldEqual, "data: Hello\n\ndata: Hello\n\n")
})
}

View File

@@ -1,69 +0,0 @@
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package macaron
import (
"net/http"
"net/http/httptest"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_Return_Handler(t *testing.T) {
Convey("Return with status and body", t, func() {
m := Classic()
m.Get("/", func() (int, string) {
return 418, "i'm a teapot"
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusTeapot)
So(resp.Body.String(), ShouldEqual, "i'm a teapot")
})
Convey("Return with pointer", t, func() {
m := Classic()
m.Get("/", func() *string {
str := "hello world"
return &str
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "hello world")
})
Convey("Return with byte slice", t, func() {
m := Classic()
m.Get("/", func() []byte {
return []byte("hello world")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "hello world")
})
}

View File

@@ -1,199 +0,0 @@
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package macaron
import (
"net/http"
"net/http/httptest"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_Router_Handle(t *testing.T) {
Convey("Register all HTTP methods routes", t, func() {
m := Classic()
m.Get("/get", func() string {
return "GET"
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/get", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "GET")
m.Patch("/patch", func() string {
return "PATCH"
})
resp = httptest.NewRecorder()
req, err = http.NewRequest("PATCH", "/patch", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "PATCH")
m.Post("/post", func() string {
return "POST"
})
resp = httptest.NewRecorder()
req, err = http.NewRequest("POST", "/post", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "POST")
m.Put("/put", func() string {
return "PUT"
})
resp = httptest.NewRecorder()
req, err = http.NewRequest("PUT", "/put", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "PUT")
m.Delete("/delete", func() string {
return "DELETE"
})
resp = httptest.NewRecorder()
req, err = http.NewRequest("DELETE", "/delete", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "DELETE")
m.Options("/options", func() string {
return "OPTIONS"
})
resp = httptest.NewRecorder()
req, err = http.NewRequest("OPTIONS", "/options", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "OPTIONS")
m.Head("/head", func() string {
return "HEAD"
})
resp = httptest.NewRecorder()
req, err = http.NewRequest("HEAD", "/head", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "HEAD")
m.Any("/any", func() string {
return "ANY"
})
resp = httptest.NewRecorder()
req, err = http.NewRequest("GET", "/any", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "ANY")
m.Route("/route", "GET,POST", func() string {
return "ROUTE"
})
resp = httptest.NewRecorder()
req, err = http.NewRequest("POST", "/route", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "ROUTE")
})
Convey("Register all HTTP methods routes with combo", t, func() {
m := Classic()
m.SetURLPrefix("/prefix")
m.Use(Renderer())
m.Combo("/", func(ctx *Context) {
ctx.Data["prefix"] = "Prefix_"
}).
Get(func(ctx *Context) string { return ctx.Data["prefix"].(string) + "GET" }).
Patch(func(ctx *Context) string { return ctx.Data["prefix"].(string) + "PATCH" }).
Post(func(ctx *Context) string { return ctx.Data["prefix"].(string) + "POST" }).
Put(func(ctx *Context) string { return ctx.Data["prefix"].(string) + "PUT" }).
Delete(func(ctx *Context) string { return ctx.Data["prefix"].(string) + "DELETE" }).
Options(func(ctx *Context) string { return ctx.Data["prefix"].(string) + "OPTIONS" }).
Head(func(ctx *Context) string { return ctx.Data["prefix"].(string) + "HEAD" })
for name := range _HTTP_METHODS {
resp := httptest.NewRecorder()
req, err := http.NewRequest(name, "/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "Prefix_"+name)
}
defer func() {
So(recover(), ShouldNotBeNil)
}()
m.Combo("/").Get(func() {}).Get(nil)
})
Convey("Register duplicated routes", t, func() {
r := NewRouter()
r.Get("/")
r.Get("/")
})
Convey("Register invalid HTTP method", t, func() {
defer func() {
So(recover(), ShouldNotBeNil)
}()
r := NewRouter()
r.Handle("404", "/", nil)
})
}
func Test_Router_Group(t *testing.T) {
Convey("Register route group", t, func() {
m := Classic()
m.Group("/api", func() {
m.Group("/v1", func() {
m.Get("/list", func() string {
return "Well done!"
})
})
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/api/v1/list", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "Well done!")
})
}
func Test_Router_NotFound(t *testing.T) {
Convey("Custom not found handler", t, func() {
m := Classic()
m.Get("/", func() {})
m.NotFound(func() string {
return "Custom not found"
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/404", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "Custom not found")
})
}
func Test_Router_splat(t *testing.T) {
Convey("Register router with glob", t, func() {
m := Classic()
m.Get("/*", func(ctx *Context) string {
return ctx.Params("*")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/hahaha", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Body.String(), ShouldEqual, "hahaha")
})
}

View File

@@ -1,246 +0,0 @@
// Copyright 2013 Martini Authors
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package macaron
import (
"bytes"
"io/ioutil"
"net/http"
"net/http/httptest"
"os"
"path"
"strings"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
var currentRoot, _ = os.Getwd()
func Test_Static(t *testing.T) {
Convey("Serve static files", t, func() {
m := New()
m.Use(Static("./"))
resp := httptest.NewRecorder()
resp.Body = new(bytes.Buffer)
req, err := http.NewRequest("GET", "http://localhost:4000/macaron.go", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Header().Get("Expires"), ShouldBeBlank)
So(resp.Body.Len(), ShouldBeGreaterThan, 0)
Convey("Change static path", func() {
m.Get("/", func(ctx *Context) {
ctx.ChangeStaticPath("./", "inject")
})
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
resp = httptest.NewRecorder()
resp.Body = new(bytes.Buffer)
req, err = http.NewRequest("GET", "http://localhost:4000/inject.go", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Header().Get("Expires"), ShouldBeBlank)
So(resp.Body.Len(), ShouldBeGreaterThan, 0)
})
})
Convey("Serve static files with local path", t, func() {
Root = os.TempDir()
f, err := ioutil.TempFile(Root, "static_content")
So(err, ShouldBeNil)
f.WriteString("Expected Content")
f.Close()
m := New()
m.Use(Static("."))
resp := httptest.NewRecorder()
resp.Body = new(bytes.Buffer)
req, err := http.NewRequest("GET", "http://localhost:4000/"+path.Base(strings.Replace(f.Name(), "\\", "/", -1)), nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Header().Get("Expires"), ShouldBeBlank)
So(resp.Body.String(), ShouldEqual, "Expected Content")
})
Convey("Serve static files with head", t, func() {
m := New()
m.Use(Static(currentRoot))
resp := httptest.NewRecorder()
resp.Body = new(bytes.Buffer)
req, err := http.NewRequest("HEAD", "http://localhost:4000/macaron.go", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(resp.Body.Len(), ShouldEqual, 0)
})
Convey("Serve static files as post", t, func() {
m := New()
m.Use(Static(currentRoot))
resp := httptest.NewRecorder()
req, err := http.NewRequest("POST", "http://localhost:4000/macaron.go", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusNotFound)
})
Convey("Serve static files with bad directory", t, func() {
m := Classic()
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://localhost:4000/macaron.go", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldNotEqual, http.StatusOK)
})
}
func Test_Static_Options(t *testing.T) {
Convey("Serve static files with options logging", t, func() {
var buf bytes.Buffer
m := NewWithLogger(&buf)
opt := StaticOptions{}
m.Use(Static(currentRoot, opt))
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://localhost:4000/macaron.go", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(buf.String(), ShouldEqual, "[Macaron] [Static] Serving /macaron.go\n")
// Not disable logging.
m.Handlers()
buf.Reset()
opt.SkipLogging = true
m.Use(Static(currentRoot, opt))
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(buf.Len(), ShouldEqual, 0)
})
Convey("Serve static files with options serve index", t, func() {
var buf bytes.Buffer
m := NewWithLogger(&buf)
opt := StaticOptions{IndexFile: "macaron.go"}
m.Use(Static(currentRoot, opt))
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://localhost:4000/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(buf.String(), ShouldEqual, "[Macaron] [Static] Serving /macaron.go\n")
})
Convey("Serve static files with options prefix", t, func() {
var buf bytes.Buffer
m := NewWithLogger(&buf)
opt := StaticOptions{Prefix: "public"}
m.Use(Static(currentRoot, opt))
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://localhost:4000/public/macaron.go", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(buf.String(), ShouldEqual, "[Macaron] [Static] Serving /macaron.go\n")
})
Convey("Serve static files with options expires", t, func() {
var buf bytes.Buffer
m := NewWithLogger(&buf)
opt := StaticOptions{Expires: func() string { return "46" }}
m.Use(Static(currentRoot, opt))
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://localhost:4000/macaron.go", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Header().Get("Expires"), ShouldEqual, "46")
})
}
func Test_Static_Redirect(t *testing.T) {
Convey("Serve static files with redirect", t, func() {
m := New()
m.Use(Static(currentRoot, StaticOptions{Prefix: "/public"}))
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://localhost:4000/public", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusFound)
So(resp.Header().Get("Location"), ShouldEqual, "/public/")
})
}
func Test_Statics(t *testing.T) {
Convey("Serve multiple static routers", t, func() {
Convey("Register empty directory", func() {
defer func() {
So(recover(), ShouldNotBeNil)
}()
m := New()
m.Use(Statics(StaticOptions{}))
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://localhost:4000/", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
})
Convey("Serve normally", func() {
var buf bytes.Buffer
m := NewWithLogger(&buf)
m.Use(Statics(StaticOptions{}, currentRoot, currentRoot+"/inject"))
resp := httptest.NewRecorder()
req, err := http.NewRequest("GET", "http://localhost:4000/macaron.go", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(buf.String(), ShouldEqual, "[Macaron] [Static] Serving /macaron.go\n")
resp = httptest.NewRecorder()
req, err = http.NewRequest("GET", "http://localhost:4000/inject/inject.go", nil)
So(err, ShouldBeNil)
m.ServeHTTP(resp, req)
So(resp.Code, ShouldEqual, http.StatusOK)
So(buf.String(), ShouldEndWith, "[Macaron] [Static] Serving /inject/inject.go\n")
})
})
}

View File

@@ -1,421 +0,0 @@
// Copyright 2013 Beego Authors
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package macaron
// NOTE: last sync 0c93364 on Dec 19, 2014.
import (
"path"
"regexp"
"strings"
"github.com/Unknwon/com"
)
type leafInfo struct {
// Names of wildcards that lead to this leaf.
// eg, ["id" "name"] for the wildcard ":id" and ":name".
wildcards []string
// Not nil if the leaf is regexp.
regexps *regexp.Regexp
handle Handle
}
func (leaf *leafInfo) match(wildcardValues []string) (ok bool, params Params) {
if leaf.regexps == nil {
if len(wildcardValues) == 0 && len(leaf.wildcards) > 0 {
if com.IsSliceContainsStr(leaf.wildcards, ":") {
params = make(map[string]string)
j := 0
for _, v := range leaf.wildcards {
if v == ":" {
continue
}
params[v] = ""
j += 1
}
return true, params
}
return false, nil
} else if len(wildcardValues) == 0 {
return true, nil // Static path.
}
// Match *
if len(leaf.wildcards) == 1 && leaf.wildcards[0] == ":splat" {
params = make(map[string]string)
params[":splat"] = path.Join(wildcardValues...)
return true, params
}
// Match *.*
if len(leaf.wildcards) == 3 && leaf.wildcards[0] == "." {
params = make(map[string]string)
lastone := wildcardValues[len(wildcardValues)-1]
strs := strings.SplitN(lastone, ".", 2)
if len(strs) == 2 {
params[":ext"] = strs[1]
} else {
params[":ext"] = ""
}
params[":path"] = path.Join(wildcardValues[:len(wildcardValues)-1]...) + "/" + strs[0]
return true, params
}
// Match :id
params = make(map[string]string)
j := 0
for _, v := range leaf.wildcards {
if v == ":" {
continue
}
if v == "." {
lastone := wildcardValues[len(wildcardValues)-1]
strs := strings.SplitN(lastone, ".", 2)
if len(strs) == 2 {
params[":ext"] = strs[1]
} else {
params[":ext"] = ""
}
if len(wildcardValues[j:]) == 1 {
params[":path"] = strs[0]
} else {
params[":path"] = path.Join(wildcardValues[j:]...) + "/" + strs[0]
}
return true, params
}
if len(wildcardValues) <= j {
return false, nil
}
params[v] = wildcardValues[j]
j++
}
if len(params) != len(wildcardValues) {
return false, nil
}
return true, params
}
if !leaf.regexps.MatchString(path.Join(wildcardValues...)) {
return false, nil
}
params = make(map[string]string)
matches := leaf.regexps.FindStringSubmatch(path.Join(wildcardValues...))
for i, match := range matches[1:] {
params[leaf.wildcards[i]] = match
}
return true, params
}
// Tree represents a router tree for Macaron instance.
type Tree struct {
fixroutes map[string]*Tree
wildcard *Tree
leaves []*leafInfo
}
// NewTree initializes and returns a router tree.
func NewTree() *Tree {
return &Tree{
fixroutes: make(map[string]*Tree),
}
}
// splitPath splites patthen into parts.
//
// Examples:
// "/" -> []
// "/admin" -> ["admin"]
// "/admin/" -> ["admin"]
// "/admin/users" -> ["admin", "users"]
func splitPath(pattern string) []string {
if len(pattern) == 0 {
return []string{}
}
elements := strings.Split(pattern, "/")
if elements[0] == "" {
elements = elements[1:]
}
if elements[len(elements)-1] == "" {
elements = elements[:len(elements)-1]
}
return elements
}
// AddRouter adds a new route to router tree.
func (t *Tree) AddRouter(pattern string, handle Handle) {
t.addSegments(splitPath(pattern), handle, nil, "")
}
// splitSegment splits segment into parts.
//
// Examples:
// "admin" -> false, nil, ""
// ":id" -> true, [:id], ""
// "?:id" -> true, [: :id], "" : meaning can empty
// ":id:int" -> true, [:id], ([0-9]+)
// ":name:string" -> true, [:name], ([\w]+)
// ":id([0-9]+)" -> true, [:id], ([0-9]+)
// ":id([0-9]+)_:name" -> true, [:id :name], ([0-9]+)_(.+)
// "cms_:id_:page.html" -> true, [:id :page], cms_(.+)_(.+).html
// "*" -> true, [:splat], ""
// "*.*" -> true,[. :path :ext], "" . meaning separator
func splitSegment(key string) (bool, []string, string) {
if strings.HasPrefix(key, "*") {
if key == "*.*" {
return true, []string{".", ":path", ":ext"}, ""
} else {
return true, []string{":splat"}, ""
}
}
if strings.ContainsAny(key, ":") {
var paramsNum int
var out []rune
var start bool
var startexp bool
var param []rune
var expt []rune
var skipnum int
params := []string{}
reg := regexp.MustCompile(`[a-zA-Z0-9]+`)
for i, v := range key {
if skipnum > 0 {
skipnum -= 1
continue
}
if start {
//:id:int and :name:string
if v == ':' {
if len(key) >= i+4 {
if key[i+1:i+4] == "int" {
out = append(out, []rune("([0-9]+)")...)
params = append(params, ":"+string(param))
start = false
startexp = false
skipnum = 3
param = make([]rune, 0)
paramsNum += 1
continue
}
}
if len(key) >= i+7 {
if key[i+1:i+7] == "string" {
out = append(out, []rune(`([\w]+)`)...)
params = append(params, ":"+string(param))
paramsNum += 1
start = false
startexp = false
skipnum = 6
param = make([]rune, 0)
continue
}
}
}
// params only support a-zA-Z0-9
if reg.MatchString(string(v)) {
param = append(param, v)
continue
}
if v != '(' {
out = append(out, []rune(`(.+)`)...)
params = append(params, ":"+string(param))
param = make([]rune, 0)
paramsNum += 1
start = false
startexp = false
}
}
if startexp {
if v != ')' {
expt = append(expt, v)
continue
}
}
if v == ':' {
param = make([]rune, 0)
start = true
} else if v == '(' {
startexp = true
start = false
params = append(params, ":"+string(param))
paramsNum += 1
expt = make([]rune, 0)
expt = append(expt, '(')
} else if v == ')' {
startexp = false
expt = append(expt, ')')
out = append(out, expt...)
param = make([]rune, 0)
} else if v == '?' {
params = append(params, ":")
} else {
out = append(out, v)
}
}
if len(param) > 0 {
if paramsNum > 0 {
out = append(out, []rune(`(.+)`)...)
}
params = append(params, ":"+string(param))
}
return true, params, string(out)
} else {
return false, nil, ""
}
}
// addSegments add segments to the router tree.
func (t *Tree) addSegments(segments []string, handle Handle, wildcards []string, reg string) {
// Fixed root route.
if len(segments) == 0 {
if reg != "" {
filterCards := make([]string, 0, len(wildcards))
for _, v := range wildcards {
if v == ":" || v == "." {
continue
}
filterCards = append(filterCards, v)
}
t.leaves = append(t.leaves, &leafInfo{
handle: handle,
wildcards: filterCards,
regexps: regexp.MustCompile("^" + reg + "$"),
})
} else {
t.leaves = append(t.leaves, &leafInfo{
handle: handle,
wildcards: wildcards,
})
}
return
}
seg := segments[0]
iswild, params, regexpStr := splitSegment(seg)
//for the router /login/*/access match /login/2009/11/access
if !iswild && com.IsSliceContainsStr(wildcards, ":splat") {
iswild = true
regexpStr = seg
}
if seg == "*" && len(wildcards) > 0 && reg == "" {
iswild = true
regexpStr = "(.+)"
}
if iswild {
if t.wildcard == nil {
t.wildcard = NewTree()
}
if regexpStr != "" {
if reg == "" {
rr := ""
for _, w := range wildcards {
if w == "." || w == ":" {
continue
}
if w == ":splat" {
rr = rr + "(.+)/"
} else {
rr = rr + "([^/]+)/"
}
}
regexpStr = rr + regexpStr
} else {
regexpStr = "/" + regexpStr
}
} else if reg != "" {
if seg == "*.*" {
regexpStr = "/([^.]+).(.+)"
} else {
for _, w := range params {
if w == "." || w == ":" {
continue
}
regexpStr = "/([^/]+)" + regexpStr
}
}
}
t.wildcard.addSegments(segments[1:], handle, append(wildcards, params...), reg+regexpStr)
} else {
subTree, ok := t.fixroutes[seg]
if !ok {
subTree = NewTree()
t.fixroutes[seg] = subTree
}
subTree.addSegments(segments[1:], handle, wildcards, reg)
}
}
func (t *Tree) match(segments []string, wildcardValues []string) (handle Handle, params Params) {
// Handle leaf nodes.
if len(segments) == 0 {
for _, l := range t.leaves {
if ok, pa := l.match(wildcardValues); ok {
return l.handle, pa
}
}
if t.wildcard != nil {
for _, l := range t.wildcard.leaves {
if ok, pa := l.match(wildcardValues); ok {
return l.handle, pa
}
}
}
return nil, nil
}
seg, segs := segments[0], segments[1:]
subTree, ok := t.fixroutes[seg]
if ok {
handle, params = subTree.match(segs, wildcardValues)
} else if len(segs) == 0 { //.json .xml
if subindex := strings.LastIndex(seg, "."); subindex != -1 {
subTree, ok = t.fixroutes[seg[:subindex]]
if ok {
handle, params = subTree.match(segs, wildcardValues)
if handle != nil {
if params == nil {
params = make(map[string]string)
}
params[":ext"] = seg[subindex+1:]
return handle, params
}
}
}
}
if handle == nil && t.wildcard != nil {
handle, params = t.wildcard.match(segs, append(wildcardValues, seg))
}
if handle == nil {
for _, l := range t.leaves {
if ok, pa := l.match(append(wildcardValues, segments...)); ok {
return l.handle, pa
}
}
}
return handle, params
}
// Match returns Handle and params if any route is matched.
func (t *Tree) Match(pattern string) (Handle, Params) {
if len(pattern) == 0 || pattern[0] != '/' {
return nil, nil
}
return t.match(splitPath(pattern), nil)
}

View File

@@ -1,112 +0,0 @@
// Copyright 2014 Unknwon
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package macaron
import (
// "net/http"
"strings"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func Test_splitSegment(t *testing.T) {
type result struct {
Ok bool
Parts []string
Regex string
}
cases := map[string]result{
"admin": result{false, nil, ""},
":id": result{true, []string{":id"}, ""},
"?:id": result{true, []string{":", ":id"}, ""},
":id:int": result{true, []string{":id"}, "([0-9]+)"},
":name:string": result{true, []string{":name"}, `([\w]+)`},
":id([0-9]+)": result{true, []string{":id"}, "([0-9]+)"},
":id([0-9]+)_:name": result{true, []string{":id", ":name"}, "([0-9]+)_(.+)"},
"cms_:id_:page.html": result{true, []string{":id", ":page"}, "cms_(.+)_(.+).html"},
"*": result{true, []string{":splat"}, ""},
"*.*": result{true, []string{".", ":path", ":ext"}, ""},
}
Convey("Splits segment into parts", t, func() {
for key, result := range cases {
ok, parts, regex := splitSegment(key)
So(ok, ShouldEqual, result.Ok)
if result.Parts == nil {
So(parts, ShouldBeNil)
} else {
So(parts, ShouldNotBeNil)
So(strings.Join(parts, " "), ShouldEqual, strings.Join(result.Parts, " "))
}
So(regex, ShouldEqual, result.Regex)
}
})
}
func Test_Tree_Match(t *testing.T) {
type result struct {
pattern string
reqUrl string
params map[string]string
}
cases := []result{
{"/:id", "/123", map[string]string{":id": "123"}},
{"/hello/?:id", "/hello", map[string]string{":id": ""}},
{"/", "/", nil},
{"", "", nil},
{"/customer/login", "/customer/login", nil},
{"/customer/login", "/customer/login.json", map[string]string{":ext": "json"}},
{"/*", "/customer/123", map[string]string{":splat": "customer/123"}},
{"/*", "/customer/2009/12/11", map[string]string{":splat": "customer/2009/12/11"}},
{"/aa/*/bb", "/aa/2009/bb", map[string]string{":splat": "2009"}},
{"/cc/*/dd", "/cc/2009/11/dd", map[string]string{":splat": "2009/11"}},
{"/ee/:year/*/ff", "/ee/2009/11/ff", map[string]string{":year": "2009", ":splat": "11"}},
{"/thumbnail/:size/uploads/*", "/thumbnail/100x100/uploads/items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg",
map[string]string{":size": "100x100", ":splat": "items/2014/04/20/dPRCdChkUd651t1Hvs18.jpg"}},
{"/*.*", "/nice/api.json", map[string]string{":path": "nice/api", ":ext": "json"}},
{"/:name/*.*", "/nice/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}},
{"/:name/test/*.*", "/nice/test/api.json", map[string]string{":name": "nice", ":path": "api", ":ext": "json"}},
{"/dl/:width:int/:height:int/*.*", "/dl/48/48/05ac66d9bda00a3acf948c43e306fc9a.jpg",
map[string]string{":width": "48", ":height": "48", ":ext": "jpg", ":path": "05ac66d9bda00a3acf948c43e306fc9a"}},
{"/v1/shop/:id:int", "/v1/shop/123", map[string]string{":id": "123"}},
{"/:year:int/:month:int/:id/:endid", "/1111/111/aaa/aaa", map[string]string{":year": "1111", ":month": "111", ":id": "aaa", ":endid": "aaa"}},
{"/v1/shop/:id/:name", "/v1/shop/123/nike", map[string]string{":id": "123", ":name": "nike"}},
{"/v1/shop/:id/account", "/v1/shop/123/account", map[string]string{":id": "123"}},
{"/v1/shop/:name:string", "/v1/shop/nike", map[string]string{":name": "nike"}},
{"/v1/shop/:id([0-9]+)", "/v1/shop//123", map[string]string{":id": "123"}},
{"/v1/shop/:id([0-9]+)_:name", "/v1/shop/123_nike", map[string]string{":id": "123", ":name": "nike"}},
{"/v1/shop/:id(.+)_cms.html", "/v1/shop/123_cms.html", map[string]string{":id": "123"}},
{"/v1/shop/cms_:id(.+)_:page(.+).html", "/v1/shop/cms_123_1.html", map[string]string{":id": "123", ":page": "1"}},
{"/v1/:v/cms/aaa_:id(.+)_:page(.+).html", "/v1/2/cms/aaa_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}},
{"/v1/:v/cms_:id(.+)_:page(.+).html", "/v1/2/cms_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}},
{"/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", "/v1/2_cms/ttt_123_1.html", map[string]string{":v": "2", ":id": "123", ":page": "1"}},
}
Convey("Match routers in tree", t, func() {
for _, c := range cases {
t := NewTree()
t.AddRouter(c.pattern, nil)
_, params := t.Match(c.reqUrl)
if params != nil {
for k, v := range c.params {
vv, ok := params[k]
So(ok, ShouldBeTrue)
So(vv, ShouldEqual, v)
}
}
}
})
}

View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,3 @@
AWS SDK for Go
Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Copyright 2014-2015 Stripe, Inc.

View File

@@ -0,0 +1,105 @@
// Package awserr represents API error interface accessors for the SDK.
package awserr
// An Error wraps lower level errors with code, message and an original error.
// The underlying concrete error type may also satisfy other interfaces which
// can be to used to obtain more specific information about the error.
//
// Calling Error() or String() will always include the full information about
// an error based on its underlying type.
//
// Example:
//
// output, err := s3manage.Upload(svc, input, opts)
// if err != nil {
// if awsErr, ok := err.(awserr.Error); ok {
// // Get error details
// log.Println("Error:", err.Code(), err.Message())
//
// // Prints out full error message, including original error if there was one.
// log.Println("Error:", err.Error())
//
// // Get original error
// if origErr := err.Err(); origErr != nil {
// // operate on original error.
// }
// } else {
// fmt.Println(err.Error())
// }
// }
//
type Error interface {
// Satisfy the generic error interface.
error
// Returns the short phrase depicting the classification of the error.
Code() string
// Returns the error details message.
Message() string
// Returns the original error if one was set. Nil is returned if not set.
OrigErr() error
}
// New returns an Error object described by the code, message, and origErr.
//
// If origErr satisfies the Error interface it will not be wrapped within a new
// Error object and will instead be returned.
func New(code, message string, origErr error) Error {
if e, ok := origErr.(Error); ok && e != nil {
return e
}
return newBaseError(code, message, origErr)
}
// A RequestFailure is an interface to extract request failure information from
// an Error such as the request ID of the failed request returned by a service.
// RequestFailures may not always have a requestID value if the request failed
// prior to reaching the service such as a connection error.
//
// Example:
//
// output, err := s3manage.Upload(svc, input, opts)
// if err != nil {
// if reqerr, ok := err.(RequestFailure); ok {
// log.Printf("Request failed", reqerr.Code(), reqerr.Message(), reqerr.RequestID())
// } else {
// log.Printf("Error:", err.Error()
// }
// }
//
// Combined with awserr.Error:
//
// output, err := s3manage.Upload(svc, input, opts)
// if err != nil {
// if awsErr, ok := err.(awserr.Error); ok {
// // Generic AWS Error with Code, Message, and original error (if any)
// fmt.Println(awsErr.Code(), awsErr.Message(), awsErr.OrigErr())
//
// if reqErr, ok := err.(awserr.RequestFailure); ok {
// // A service error occurred
// fmt.Println(reqErr.StatusCode(), reqErr.RequestID())
// }
// } else {
// fmt.Println(err.Error())
// }
// }
//
type RequestFailure interface {
Error
// The status code of the HTTP response.
StatusCode() int
// The request ID returned by the service for a request failure. This will
// be empty if no request ID is available such as the request failed due
// to a connection error.
RequestID() string
}
// NewRequestFailure returns a new request error wrapper for the given Error
// provided.
func NewRequestFailure(err Error, statusCode int, reqID string) RequestFailure {
return newRequestError(err, statusCode, reqID)
}

View File

@@ -0,0 +1,135 @@
package awserr
import "fmt"
// SprintError returns a string of the formatted error code.
//
// Both extra and origErr are optional. If they are included their lines
// will be added, but if they are not included their lines will be ignored.
func SprintError(code, message, extra string, origErr error) string {
msg := fmt.Sprintf("%s: %s", code, message)
if extra != "" {
msg = fmt.Sprintf("%s\n\t%s", msg, extra)
}
if origErr != nil {
msg = fmt.Sprintf("%s\ncaused by: %s", msg, origErr.Error())
}
return msg
}
// A baseError wraps the code and message which defines an error. It also
// can be used to wrap an original error object.
//
// Should be used as the root for errors satisfying the awserr.Error. Also
// for any error which does not fit into a specific error wrapper type.
type baseError struct {
// Classification of error
code string
// Detailed information about error
message string
// Optional original error this error is based off of. Allows building
// chained errors.
origErr error
}
// newBaseError returns an error object for the code, message, and err.
//
// code is a short no whitespace phrase depicting the classification of
// the error that is being created.
//
// message is the free flow string containing detailed information about the error.
//
// origErr is the error object which will be nested under the new error to be returned.
func newBaseError(code, message string, origErr error) *baseError {
return &baseError{
code: code,
message: message,
origErr: origErr,
}
}
// Error returns the string representation of the error.
//
// See ErrorWithExtra for formatting.
//
// Satisfies the error interface.
func (b baseError) Error() string {
return SprintError(b.code, b.message, "", b.origErr)
}
// String returns the string representation of the error.
// Alias for Error to satisfy the stringer interface.
func (b baseError) String() string {
return b.Error()
}
// Code returns the short phrase depicting the classification of the error.
func (b baseError) Code() string {
return b.code
}
// Message returns the error details message.
func (b baseError) Message() string {
return b.message
}
// OrigErr returns the original error if one was set. Nil is returned if no error
// was set.
func (b baseError) OrigErr() error {
return b.origErr
}
// So that the Error interface type can be included as an anonymous field
// in the requestError struct and not conflict with the error.Error() method.
type awsError Error
// A requestError wraps a request or service error.
//
// Composed of baseError for code, message, and original error.
type requestError struct {
awsError
statusCode int
requestID string
}
// newRequestError returns a wrapped error with additional information for request
// status code, and service requestID.
//
// Should be used to wrap all request which involve service requests. Even if
// the request failed without a service response, but had an HTTP status code
// that may be meaningful.
//
// Also wraps original errors via the baseError.
func newRequestError(err Error, statusCode int, requestID string) *requestError {
return &requestError{
awsError: err,
statusCode: statusCode,
requestID: requestID,
}
}
// Error returns the string representation of the error.
// Satisfies the error interface.
func (r requestError) Error() string {
extra := fmt.Sprintf("status code: %d, request id: %s",
r.statusCode, r.requestID)
return SprintError(r.Code(), r.Message(), extra, r.OrigErr())
}
// String returns the string representation of the error.
// Alias for Error to satisfy the stringer interface.
func (r requestError) String() string {
return r.Error()
}
// StatusCode returns the wrapped status code for the error
func (r requestError) StatusCode() int {
return r.statusCode
}
// RequestID returns the wrapped requestID
func (r requestError) RequestID() string {
return r.requestID
}

View File

@@ -0,0 +1,100 @@
package awsutil
import (
"io"
"reflect"
)
// Copy deeply copies a src structure to dst. Useful for copying request and
// response structures.
//
// Can copy between structs of different type, but will only copy fields which
// are assignable, and exist in both structs. Fields which are not assignable,
// or do not exist in both structs are ignored.
func Copy(dst, src interface{}) {
dstval := reflect.ValueOf(dst)
if !dstval.IsValid() {
panic("Copy dst cannot be nil")
}
rcopy(dstval, reflect.ValueOf(src), true)
}
// CopyOf returns a copy of src while also allocating the memory for dst.
// src must be a pointer type or this operation will fail.
func CopyOf(src interface{}) (dst interface{}) {
dsti := reflect.New(reflect.TypeOf(src).Elem())
dst = dsti.Interface()
rcopy(dsti, reflect.ValueOf(src), true)
return
}
// rcopy performs a recursive copy of values from the source to destination.
//
// root is used to skip certain aspects of the copy which are not valid
// for the root node of a object.
func rcopy(dst, src reflect.Value, root bool) {
if !src.IsValid() {
return
}
switch src.Kind() {
case reflect.Ptr:
if _, ok := src.Interface().(io.Reader); ok {
if dst.Kind() == reflect.Ptr && dst.Elem().CanSet() {
dst.Elem().Set(src)
} else if dst.CanSet() {
dst.Set(src)
}
} else {
e := src.Type().Elem()
if dst.CanSet() && !src.IsNil() {
dst.Set(reflect.New(e))
}
if src.Elem().IsValid() {
// Keep the current root state since the depth hasn't changed
rcopy(dst.Elem(), src.Elem(), root)
}
}
case reflect.Struct:
t := dst.Type()
for i := 0; i < t.NumField(); i++ {
name := t.Field(i).Name
srcVal := src.FieldByName(name)
dstVal := dst.FieldByName(name)
if srcVal.IsValid() && dstVal.CanSet() {
rcopy(dstVal, srcVal, false)
}
}
case reflect.Slice:
if src.IsNil() {
break
}
s := reflect.MakeSlice(src.Type(), src.Len(), src.Cap())
dst.Set(s)
for i := 0; i < src.Len(); i++ {
rcopy(dst.Index(i), src.Index(i), false)
}
case reflect.Map:
if src.IsNil() {
break
}
s := reflect.MakeMap(src.Type())
dst.Set(s)
for _, k := range src.MapKeys() {
v := src.MapIndex(k)
v2 := reflect.New(v.Type()).Elem()
rcopy(v2, v, false)
dst.SetMapIndex(k, v2)
}
default:
// Assign the value if possible. If its not assignable, the value would
// need to be converted and the impact of that may be unexpected, or is
// not compatible with the dst type.
if src.Type().AssignableTo(dst.Type()) {
dst.Set(src)
}
}
}

View File

@@ -0,0 +1,233 @@
package awsutil_test
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"testing"
"github.com/aws/aws-sdk-go/aws/awsutil"
"github.com/stretchr/testify/assert"
)
func ExampleCopy() {
type Foo struct {
A int
B []*string
}
// Create the initial value
str1 := "hello"
str2 := "bye bye"
f1 := &Foo{A: 1, B: []*string{&str1, &str2}}
// Do the copy
var f2 Foo
awsutil.Copy(&f2, f1)
// Print the result
fmt.Println(awsutil.Prettify(f2))
// Output:
// {
// A: 1,
// B: ["hello","bye bye"]
// }
}
func TestCopy(t *testing.T) {
type Foo struct {
A int
B []*string
C map[string]*int
}
// Create the initial value
str1 := "hello"
str2 := "bye bye"
int1 := 1
int2 := 2
f1 := &Foo{
A: 1,
B: []*string{&str1, &str2},
C: map[string]*int{
"A": &int1,
"B": &int2,
},
}
// Do the copy
var f2 Foo
awsutil.Copy(&f2, f1)
// Values are equal
assert.Equal(t, f2.A, f1.A)
assert.Equal(t, f2.B, f1.B)
assert.Equal(t, f2.C, f1.C)
// But pointers are not!
str3 := "nothello"
int3 := 57
f2.A = 100
f2.B[0] = &str3
f2.C["B"] = &int3
assert.NotEqual(t, f2.A, f1.A)
assert.NotEqual(t, f2.B, f1.B)
assert.NotEqual(t, f2.C, f1.C)
}
func TestCopyNestedWithUnexported(t *testing.T) {
type Bar struct {
a int
B int
}
type Foo struct {
A string
B Bar
}
f1 := &Foo{A: "string", B: Bar{a: 1, B: 2}}
var f2 Foo
awsutil.Copy(&f2, f1)
// Values match
assert.Equal(t, f2.A, f1.A)
assert.NotEqual(t, f2.B, f1.B)
assert.NotEqual(t, f2.B.a, f1.B.a)
assert.Equal(t, f2.B.B, f2.B.B)
}
func TestCopyIgnoreNilMembers(t *testing.T) {
type Foo struct {
A *string
B []string
C map[string]string
}
f := &Foo{}
assert.Nil(t, f.A)
assert.Nil(t, f.B)
assert.Nil(t, f.C)
var f2 Foo
awsutil.Copy(&f2, f)
assert.Nil(t, f2.A)
assert.Nil(t, f2.B)
assert.Nil(t, f2.C)
fcopy := awsutil.CopyOf(f)
f3 := fcopy.(*Foo)
assert.Nil(t, f3.A)
assert.Nil(t, f3.B)
assert.Nil(t, f3.C)
}
func TestCopyPrimitive(t *testing.T) {
str := "hello"
var s string
awsutil.Copy(&s, &str)
assert.Equal(t, "hello", s)
}
func TestCopyNil(t *testing.T) {
var s string
awsutil.Copy(&s, nil)
assert.Equal(t, "", s)
}
func TestCopyReader(t *testing.T) {
var buf io.Reader = bytes.NewReader([]byte("hello world"))
var r io.Reader
awsutil.Copy(&r, buf)
b, err := ioutil.ReadAll(r)
assert.NoError(t, err)
assert.Equal(t, []byte("hello world"), b)
// empty bytes because this is not a deep copy
b, err = ioutil.ReadAll(buf)
assert.NoError(t, err)
assert.Equal(t, []byte(""), b)
}
func TestCopyDifferentStructs(t *testing.T) {
type SrcFoo struct {
A int
B []*string
C map[string]*int
SrcUnique string
SameNameDiffType int
unexportedPtr *int
ExportedPtr *int
}
type DstFoo struct {
A int
B []*string
C map[string]*int
DstUnique int
SameNameDiffType string
unexportedPtr *int
ExportedPtr *int
}
// Create the initial value
str1 := "hello"
str2 := "bye bye"
int1 := 1
int2 := 2
f1 := &SrcFoo{
A: 1,
B: []*string{&str1, &str2},
C: map[string]*int{
"A": &int1,
"B": &int2,
},
SrcUnique: "unique",
SameNameDiffType: 1,
unexportedPtr: &int1,
ExportedPtr: &int2,
}
// Do the copy
var f2 DstFoo
awsutil.Copy(&f2, f1)
// Values are equal
assert.Equal(t, f2.A, f1.A)
assert.Equal(t, f2.B, f1.B)
assert.Equal(t, f2.C, f1.C)
assert.Equal(t, "unique", f1.SrcUnique)
assert.Equal(t, 1, f1.SameNameDiffType)
assert.Equal(t, 0, f2.DstUnique)
assert.Equal(t, "", f2.SameNameDiffType)
assert.Equal(t, int1, *f1.unexportedPtr)
assert.Nil(t, f2.unexportedPtr)
assert.Equal(t, int2, *f1.ExportedPtr)
assert.Equal(t, int2, *f2.ExportedPtr)
}
func ExampleCopyOf() {
type Foo struct {
A int
B []*string
}
// Create the initial value
str1 := "hello"
str2 := "bye bye"
f1 := &Foo{A: 1, B: []*string{&str1, &str2}}
// Do the copy
v := awsutil.CopyOf(f1)
var f2 *Foo = v.(*Foo)
// Print the result
fmt.Println(awsutil.Prettify(f2))
// Output:
// {
// A: 1,
// B: ["hello","bye bye"]
// }
}

View File

@@ -0,0 +1,27 @@
package awsutil
import (
"reflect"
)
// DeepEqual returns if the two values are deeply equal like reflect.DeepEqual.
// In addition to this, this method will also dereference the input values if
// possible so the DeepEqual performed will not fail if one parameter is a
// pointer and the other is not.
//
// DeepEqual will not perform indirection of nested values of the input parameters.
func DeepEqual(a, b interface{}) bool {
ra := reflect.Indirect(reflect.ValueOf(a))
rb := reflect.Indirect(reflect.ValueOf(b))
if raValid, rbValid := ra.IsValid(), rb.IsValid(); !raValid && !rbValid {
// If the elements are both nil, and of the same type the are equal
// If they are of different types they are not equal
return reflect.TypeOf(a) == reflect.TypeOf(b)
} else if raValid != rbValid {
// Both values must be valid to be equal
return false
}
return reflect.DeepEqual(ra.Interface(), rb.Interface())
}

View File

@@ -0,0 +1,29 @@
package awsutil_test
import (
"testing"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awsutil"
"github.com/stretchr/testify/assert"
)
func TestDeepEqual(t *testing.T) {
cases := []struct {
a, b interface{}
equal bool
}{
{"a", "a", true},
{"a", "b", false},
{"a", aws.String(""), false},
{"a", nil, false},
{"a", aws.String("a"), true},
{(*bool)(nil), (*bool)(nil), true},
{(*bool)(nil), (*string)(nil), false},
{nil, nil, true},
}
for i, c := range cases {
assert.Equal(t, c.equal, awsutil.DeepEqual(c.a, c.b), "%d, a:%v b:%v, %t", i, c.a, c.b, c.equal)
}
}

View File

@@ -0,0 +1,222 @@
package awsutil
import (
"reflect"
"regexp"
"strconv"
"strings"
"github.com/jmespath/go-jmespath"
)
var indexRe = regexp.MustCompile(`(.+)\[(-?\d+)?\]$`)
// rValuesAtPath returns a slice of values found in value v. The values
// in v are explored recursively so all nested values are collected.
func rValuesAtPath(v interface{}, path string, createPath, caseSensitive, nilTerm bool) []reflect.Value {
pathparts := strings.Split(path, "||")
if len(pathparts) > 1 {
for _, pathpart := range pathparts {
vals := rValuesAtPath(v, pathpart, createPath, caseSensitive, nilTerm)
if len(vals) > 0 {
return vals
}
}
return nil
}
values := []reflect.Value{reflect.Indirect(reflect.ValueOf(v))}
components := strings.Split(path, ".")
for len(values) > 0 && len(components) > 0 {
var index *int64
var indexStar bool
c := strings.TrimSpace(components[0])
if c == "" { // no actual component, illegal syntax
return nil
} else if caseSensitive && c != "*" && strings.ToLower(c[0:1]) == c[0:1] {
// TODO normalize case for user
return nil // don't support unexported fields
}
// parse this component
if m := indexRe.FindStringSubmatch(c); m != nil {
c = m[1]
if m[2] == "" {
index = nil
indexStar = true
} else {
i, _ := strconv.ParseInt(m[2], 10, 32)
index = &i
indexStar = false
}
}
nextvals := []reflect.Value{}
for _, value := range values {
// pull component name out of struct member
if value.Kind() != reflect.Struct {
continue
}
if c == "*" { // pull all members
for i := 0; i < value.NumField(); i++ {
if f := reflect.Indirect(value.Field(i)); f.IsValid() {
nextvals = append(nextvals, f)
}
}
continue
}
value = value.FieldByNameFunc(func(name string) bool {
if c == name {
return true
} else if !caseSensitive && strings.ToLower(name) == strings.ToLower(c) {
return true
}
return false
})
if nilTerm && value.Kind() == reflect.Ptr && len(components[1:]) == 0 {
if !value.IsNil() {
value.Set(reflect.Zero(value.Type()))
}
return []reflect.Value{value}
}
if createPath && value.Kind() == reflect.Ptr && value.IsNil() {
// TODO if the value is the terminus it should not be created
// if the value to be set to its position is nil.
value.Set(reflect.New(value.Type().Elem()))
value = value.Elem()
} else {
value = reflect.Indirect(value)
}
if value.Kind() == reflect.Slice || value.Kind() == reflect.Map {
if !createPath && value.IsNil() {
value = reflect.ValueOf(nil)
}
}
if value.IsValid() {
nextvals = append(nextvals, value)
}
}
values = nextvals
if indexStar || index != nil {
nextvals = []reflect.Value{}
for _, value := range values {
value := reflect.Indirect(value)
if value.Kind() != reflect.Slice {
continue
}
if indexStar { // grab all indices
for i := 0; i < value.Len(); i++ {
idx := reflect.Indirect(value.Index(i))
if idx.IsValid() {
nextvals = append(nextvals, idx)
}
}
continue
}
// pull out index
i := int(*index)
if i >= value.Len() { // check out of bounds
if createPath {
// TODO resize slice
} else {
continue
}
} else if i < 0 { // support negative indexing
i = value.Len() + i
}
value = reflect.Indirect(value.Index(i))
if value.Kind() == reflect.Slice || value.Kind() == reflect.Map {
if !createPath && value.IsNil() {
value = reflect.ValueOf(nil)
}
}
if value.IsValid() {
nextvals = append(nextvals, value)
}
}
values = nextvals
}
components = components[1:]
}
return values
}
// ValuesAtPath returns a list of values at the case insensitive lexical
// path inside of a structure.
func ValuesAtPath(i interface{}, path string) ([]interface{}, error) {
result, err := jmespath.Search(path, i)
if err != nil {
return nil, err
}
v := reflect.ValueOf(result)
if !v.IsValid() || (v.Kind() == reflect.Ptr && v.IsNil()) {
return nil, nil
}
if s, ok := result.([]interface{}); ok {
return s, err
}
if v.Kind() == reflect.Map && v.Len() == 0 {
return nil, nil
}
if v.Kind() == reflect.Slice {
out := make([]interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
out[i] = v.Index(i).Interface()
}
return out, nil
}
return []interface{}{result}, nil
}
// SetValueAtPath sets a value at the case insensitive lexical path inside
// of a structure.
func SetValueAtPath(i interface{}, path string, v interface{}) {
if rvals := rValuesAtPath(i, path, true, false, v == nil); rvals != nil {
for _, rval := range rvals {
if rval.Kind() == reflect.Ptr && rval.IsNil() {
continue
}
setValue(rval, v)
}
}
}
func setValue(dstVal reflect.Value, src interface{}) {
if dstVal.Kind() == reflect.Ptr {
dstVal = reflect.Indirect(dstVal)
}
srcVal := reflect.ValueOf(src)
if !srcVal.IsValid() { // src is literal nil
if dstVal.CanAddr() {
// Convert to pointer so that pointer's value can be nil'ed
// dstVal = dstVal.Addr()
}
dstVal.Set(reflect.Zero(dstVal.Type()))
} else if srcVal.Kind() == reflect.Ptr {
if srcVal.IsNil() {
srcVal = reflect.Zero(dstVal.Type())
} else {
srcVal = reflect.ValueOf(src).Elem()
}
dstVal.Set(srcVal)
} else {
dstVal.Set(srcVal)
}
}

View File

@@ -0,0 +1,142 @@
package awsutil_test
import (
"testing"
"github.com/aws/aws-sdk-go/aws/awsutil"
"github.com/stretchr/testify/assert"
)
type Struct struct {
A []Struct
z []Struct
B *Struct
D *Struct
C string
E map[string]string
}
var data = Struct{
A: []Struct{{C: "value1"}, {C: "value2"}, {C: "value3"}},
z: []Struct{{C: "value1"}, {C: "value2"}, {C: "value3"}},
B: &Struct{B: &Struct{C: "terminal"}, D: &Struct{C: "terminal2"}},
C: "initial",
}
var data2 = Struct{A: []Struct{
{A: []Struct{{C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}}},
{A: []Struct{{C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}}},
}}
func TestValueAtPathSuccess(t *testing.T) {
var testCases = []struct {
expect []interface{}
data interface{}
path string
}{
{[]interface{}{"initial"}, data, "C"},
{[]interface{}{"value1"}, data, "A[0].C"},
{[]interface{}{"value2"}, data, "A[1].C"},
{[]interface{}{"value3"}, data, "A[2].C"},
{[]interface{}{"value3"}, data, "a[2].c"},
{[]interface{}{"value3"}, data, "A[-1].C"},
{[]interface{}{"value1", "value2", "value3"}, data, "A[].C"},
{[]interface{}{"terminal"}, data, "B . B . C"},
{[]interface{}{"initial"}, data, "A.D.X || C"},
{[]interface{}{"initial"}, data, "A[0].B || C"},
{[]interface{}{
Struct{A: []Struct{{C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}, {C: "1"}}},
Struct{A: []Struct{{C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}, {C: "2"}}},
}, data2, "A"},
}
for i, c := range testCases {
v, err := awsutil.ValuesAtPath(c.data, c.path)
assert.NoError(t, err, "case %d, expected no error, %s", i, c.path)
assert.Equal(t, c.expect, v, "case %d, %s", i, c.path)
}
}
func TestValueAtPathFailure(t *testing.T) {
var testCases = []struct {
expect []interface{}
errContains string
data interface{}
path string
}{
{nil, "", data, "C.x"},
{nil, "SyntaxError: Invalid token: tDot", data, ".x"},
{nil, "", data, "X.Y.Z"},
{nil, "", data, "A[100].C"},
{nil, "", data, "A[3].C"},
{nil, "", data, "B.B.C.Z"},
{nil, "", data, "z[-1].C"},
{nil, "", nil, "A.B.C"},
{[]interface{}{}, "", Struct{}, "A"},
{nil, "", data, "A[0].B.C"},
{nil, "", data, "D"},
}
for i, c := range testCases {
v, err := awsutil.ValuesAtPath(c.data, c.path)
if c.errContains != "" {
assert.Contains(t, err.Error(), c.errContains, "case %d, expected error, %s", i, c.path)
continue
} else {
assert.NoError(t, err, "case %d, expected no error, %s", i, c.path)
}
assert.Equal(t, c.expect, v, "case %d, %s", i, c.path)
}
}
func TestSetValueAtPathSuccess(t *testing.T) {
var s Struct
awsutil.SetValueAtPath(&s, "C", "test1")
awsutil.SetValueAtPath(&s, "B.B.C", "test2")
awsutil.SetValueAtPath(&s, "B.D.C", "test3")
assert.Equal(t, "test1", s.C)
assert.Equal(t, "test2", s.B.B.C)
assert.Equal(t, "test3", s.B.D.C)
awsutil.SetValueAtPath(&s, "B.*.C", "test0")
assert.Equal(t, "test0", s.B.B.C)
assert.Equal(t, "test0", s.B.D.C)
var s2 Struct
awsutil.SetValueAtPath(&s2, "b.b.c", "test0")
assert.Equal(t, "test0", s2.B.B.C)
awsutil.SetValueAtPath(&s2, "A", []Struct{{}})
assert.Equal(t, []Struct{{}}, s2.A)
str := "foo"
s3 := Struct{}
awsutil.SetValueAtPath(&s3, "b.b.c", str)
assert.Equal(t, "foo", s3.B.B.C)
s3 = Struct{B: &Struct{B: &Struct{C: str}}}
awsutil.SetValueAtPath(&s3, "b.b.c", nil)
assert.Equal(t, "", s3.B.B.C)
s3 = Struct{}
awsutil.SetValueAtPath(&s3, "b.b.c", nil)
assert.Equal(t, "", s3.B.B.C)
s3 = Struct{}
awsutil.SetValueAtPath(&s3, "b.b.c", &str)
assert.Equal(t, "foo", s3.B.B.C)
var s4 struct{ Name *string }
awsutil.SetValueAtPath(&s4, "Name", str)
assert.Equal(t, str, *s4.Name)
s4 = struct{ Name *string }{}
awsutil.SetValueAtPath(&s4, "Name", nil)
assert.Equal(t, (*string)(nil), s4.Name)
s4 = struct{ Name *string }{Name: &str}
awsutil.SetValueAtPath(&s4, "Name", nil)
assert.Equal(t, (*string)(nil), s4.Name)
s4 = struct{ Name *string }{}
awsutil.SetValueAtPath(&s4, "Name", &str)
assert.Equal(t, str, *s4.Name)
}

View File

@@ -0,0 +1,103 @@
package awsutil
import (
"bytes"
"fmt"
"io"
"reflect"
"strings"
)
// Prettify returns the string representation of a value.
func Prettify(i interface{}) string {
var buf bytes.Buffer
prettify(reflect.ValueOf(i), 0, &buf)
return buf.String()
}
// prettify will recursively walk value v to build a textual
// representation of the value.
func prettify(v reflect.Value, indent int, buf *bytes.Buffer) {
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
switch v.Kind() {
case reflect.Struct:
strtype := v.Type().String()
if strtype == "time.Time" {
fmt.Fprintf(buf, "%s", v.Interface())
break
} else if strings.HasPrefix(strtype, "io.") {
buf.WriteString("<buffer>")
break
}
buf.WriteString("{\n")
names := []string{}
for i := 0; i < v.Type().NumField(); i++ {
name := v.Type().Field(i).Name
f := v.Field(i)
if name[0:1] == strings.ToLower(name[0:1]) {
continue // ignore unexported fields
}
if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice || f.Kind() == reflect.Map) && f.IsNil() {
continue // ignore unset fields
}
names = append(names, name)
}
for i, n := range names {
val := v.FieldByName(n)
buf.WriteString(strings.Repeat(" ", indent+2))
buf.WriteString(n + ": ")
prettify(val, indent+2, buf)
if i < len(names)-1 {
buf.WriteString(",\n")
}
}
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
case reflect.Slice:
nl, id, id2 := "", "", ""
if v.Len() > 3 {
nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2)
}
buf.WriteString("[" + nl)
for i := 0; i < v.Len(); i++ {
buf.WriteString(id2)
prettify(v.Index(i), indent+2, buf)
if i < v.Len()-1 {
buf.WriteString("," + nl)
}
}
buf.WriteString(nl + id + "]")
case reflect.Map:
buf.WriteString("{\n")
for i, k := range v.MapKeys() {
buf.WriteString(strings.Repeat(" ", indent+2))
buf.WriteString(k.String() + ": ")
prettify(v.MapIndex(k), indent+2, buf)
if i < v.Len()-1 {
buf.WriteString(",\n")
}
}
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
default:
format := "%v"
switch v.Interface().(type) {
case string:
format = "%q"
case io.ReadSeeker, io.Reader:
format = "buffer(%p)"
}
fmt.Fprintf(buf, format, v.Interface())
}
}

View File

@@ -0,0 +1,89 @@
package awsutil
import (
"bytes"
"fmt"
"reflect"
"strings"
)
// StringValue returns the string representation of a value.
func StringValue(i interface{}) string {
var buf bytes.Buffer
stringValue(reflect.ValueOf(i), 0, &buf)
return buf.String()
}
func stringValue(v reflect.Value, indent int, buf *bytes.Buffer) {
for v.Kind() == reflect.Ptr {
v = v.Elem()
}
switch v.Kind() {
case reflect.Struct:
buf.WriteString("{\n")
names := []string{}
for i := 0; i < v.Type().NumField(); i++ {
name := v.Type().Field(i).Name
f := v.Field(i)
if name[0:1] == strings.ToLower(name[0:1]) {
continue // ignore unexported fields
}
if (f.Kind() == reflect.Ptr || f.Kind() == reflect.Slice) && f.IsNil() {
continue // ignore unset fields
}
names = append(names, name)
}
for i, n := range names {
val := v.FieldByName(n)
buf.WriteString(strings.Repeat(" ", indent+2))
buf.WriteString(n + ": ")
stringValue(val, indent+2, buf)
if i < len(names)-1 {
buf.WriteString(",\n")
}
}
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
case reflect.Slice:
nl, id, id2 := "", "", ""
if v.Len() > 3 {
nl, id, id2 = "\n", strings.Repeat(" ", indent), strings.Repeat(" ", indent+2)
}
buf.WriteString("[" + nl)
for i := 0; i < v.Len(); i++ {
buf.WriteString(id2)
stringValue(v.Index(i), indent+2, buf)
if i < v.Len()-1 {
buf.WriteString("," + nl)
}
}
buf.WriteString(nl + id + "]")
case reflect.Map:
buf.WriteString("{\n")
for i, k := range v.MapKeys() {
buf.WriteString(strings.Repeat(" ", indent+2))
buf.WriteString(k.String() + ": ")
stringValue(v.MapIndex(k), indent+2, buf)
if i < v.Len()-1 {
buf.WriteString(",\n")
}
}
buf.WriteString("\n" + strings.Repeat(" ", indent) + "}")
default:
format := "%v"
switch v.Interface().(type) {
case string:
format = "%q"
}
fmt.Fprintf(buf, format, v.Interface())
}
}

View File

@@ -0,0 +1,120 @@
package client
import (
"fmt"
"io/ioutil"
"net/http/httputil"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/client/metadata"
"github.com/aws/aws-sdk-go/aws/request"
)
// A Config provides configuration to a service client instance.
type Config struct {
Config *aws.Config
Handlers request.Handlers
Endpoint, SigningRegion string
}
// ConfigProvider provides a generic way for a service client to receive
// the ClientConfig without circular dependencies.
type ConfigProvider interface {
ClientConfig(serviceName string, cfgs ...*aws.Config) Config
}
// A Client implements the base client request and response handling
// used by all service clients.
type Client struct {
request.Retryer
metadata.ClientInfo
Config aws.Config
Handlers request.Handlers
}
// New will return a pointer to a new initialized service client.
func New(cfg aws.Config, info metadata.ClientInfo, handlers request.Handlers, options ...func(*Client)) *Client {
svc := &Client{
Config: cfg,
ClientInfo: info,
Handlers: handlers,
}
switch retryer, ok := cfg.Retryer.(request.Retryer); {
case ok:
svc.Retryer = retryer
case cfg.Retryer != nil && cfg.Logger != nil:
s := fmt.Sprintf("WARNING: %T does not implement request.Retryer; using DefaultRetryer instead", cfg.Retryer)
cfg.Logger.Log(s)
fallthrough
default:
maxRetries := aws.IntValue(cfg.MaxRetries)
if cfg.MaxRetries == nil || maxRetries == aws.UseServiceDefaultRetries {
maxRetries = 3
}
svc.Retryer = DefaultRetryer{NumMaxRetries: maxRetries}
}
svc.AddDebugHandlers()
for _, option := range options {
option(svc)
}
return svc
}
// NewRequest returns a new Request pointer for the service API
// operation and parameters.
func (c *Client) NewRequest(operation *request.Operation, params interface{}, data interface{}) *request.Request {
return request.New(c.Config, c.ClientInfo, c.Handlers, c.Retryer, operation, params, data)
}
// AddDebugHandlers injects debug logging handlers into the service to log request
// debug information.
func (c *Client) AddDebugHandlers() {
if !c.Config.LogLevel.AtLeast(aws.LogDebug) {
return
}
c.Handlers.Send.PushFront(logRequest)
c.Handlers.Send.PushBack(logResponse)
}
const logReqMsg = `DEBUG: Request %s/%s Details:
---[ REQUEST POST-SIGN ]-----------------------------
%s
-----------------------------------------------------`
func logRequest(r *request.Request) {
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
dumpedBody, _ := httputil.DumpRequestOut(r.HTTPRequest, logBody)
if logBody {
// Reset the request body because dumpRequest will re-wrap the r.HTTPRequest's
// Body as a NoOpCloser and will not be reset after read by the HTTP
// client reader.
r.Body.Seek(r.BodyStart, 0)
r.HTTPRequest.Body = ioutil.NopCloser(r.Body)
}
r.Config.Logger.Log(fmt.Sprintf(logReqMsg, r.ClientInfo.ServiceName, r.Operation.Name, string(dumpedBody)))
}
const logRespMsg = `DEBUG: Response %s/%s Details:
---[ RESPONSE ]--------------------------------------
%s
-----------------------------------------------------`
func logResponse(r *request.Request) {
var msg = "no reponse data"
if r.HTTPResponse != nil {
logBody := r.Config.LogLevel.Matches(aws.LogDebugWithHTTPBody)
dumpedBody, _ := httputil.DumpResponse(r.HTTPResponse, logBody)
msg = string(dumpedBody)
} else if r.Error != nil {
msg = r.Error.Error()
}
r.Config.Logger.Log(fmt.Sprintf(logRespMsg, r.ClientInfo.ServiceName, r.Operation.Name, msg))
}

View File

@@ -0,0 +1,45 @@
package client
import (
"math"
"math/rand"
"time"
"github.com/aws/aws-sdk-go/aws/request"
)
// DefaultRetryer implements basic retry logic using exponential backoff for
// most services. If you want to implement custom retry logic, implement the
// request.Retryer interface or create a structure type that composes this
// struct and override the specific methods. For example, to override only
// the MaxRetries method:
//
// type retryer struct {
// service.DefaultRetryer
// }
//
// // This implementation always has 100 max retries
// func (d retryer) MaxRetries() uint { return 100 }
type DefaultRetryer struct {
NumMaxRetries int
}
// MaxRetries returns the number of maximum returns the service will use to make
// an individual API request.
func (d DefaultRetryer) MaxRetries() int {
return d.NumMaxRetries
}
// RetryRules returns the delay duration before retrying this request again
func (d DefaultRetryer) RetryRules(r *request.Request) time.Duration {
delay := int(math.Pow(2, float64(r.RetryCount))) * (rand.Intn(30) + 30)
return time.Duration(delay) * time.Millisecond
}
// ShouldRetry returns if the request should be retried.
func (d DefaultRetryer) ShouldRetry(r *request.Request) bool {
if r.HTTPResponse.StatusCode >= 500 {
return true
}
return r.IsErrorRetryable()
}

View File

@@ -0,0 +1,12 @@
package metadata
// ClientInfo wraps immutable data from the client.Client structure.
type ClientInfo struct {
ServiceName string
APIVersion string
Endpoint string
SigningName string
SigningRegion string
JSONVersion string
TargetPrefix string
}

View File

@@ -0,0 +1,270 @@
package aws
import (
"net/http"
"time"
"github.com/aws/aws-sdk-go/aws/credentials"
)
// UseServiceDefaultRetries instructs the config to use the service's own default
// number of retries. This will be the default action if Config.MaxRetries
// is nil also.
const UseServiceDefaultRetries = -1
// RequestRetryer is an alias for a type that implements the request.Retryer interface.
type RequestRetryer interface{}
// A Config provides service configuration for service clients. By default,
// all clients will use the {defaults.DefaultConfig} structure.
type Config struct {
// The credentials object to use when signing requests. Defaults to
// a chain of credential providers to search for credentials in environment
// variables, shared credential file, and EC2 Instance Roles.
Credentials *credentials.Credentials
// An optional endpoint URL (hostname only or fully qualified URI)
// that overrides the default generated endpoint for a client. Set this
// to `""` to use the default generated endpoint.
//
// @note You must still provide a `Region` value when specifying an
// endpoint for a client.
Endpoint *string
// The region to send requests to. This parameter is required and must
// be configured globally or on a per-client basis unless otherwise
// noted. A full list of regions is found in the "Regions and Endpoints"
// document.
//
// @see http://docs.aws.amazon.com/general/latest/gr/rande.html
// AWS Regions and Endpoints
Region *string
// Set this to `true` to disable SSL when sending requests. Defaults
// to `false`.
DisableSSL *bool
// The HTTP client to use when sending requests. Defaults to
// `http.DefaultClient`.
HTTPClient *http.Client
// An integer value representing the logging level. The default log level
// is zero (LogOff), which represents no logging. To enable logging set
// to a LogLevel Value.
LogLevel *LogLevelType
// The logger writer interface to write logging messages to. Defaults to
// standard out.
Logger Logger
// The maximum number of times that a request will be retried for failures.
// Defaults to -1, which defers the max retry setting to the service specific
// configuration.
MaxRetries *int
// Retryer guides how HTTP requests should be retried in case of recoverable failures.
//
// When nil or the value does not implement the request.Retryer interface,
// the request.DefaultRetryer will be used.
//
// When both Retryer and MaxRetries are non-nil, the former is used and
// the latter ignored.
//
// To set the Retryer field in a type-safe manner and with chaining, use
// the request.WithRetryer helper function:
//
// cfg := request.WithRetryer(aws.NewConfig(), myRetryer)
//
Retryer RequestRetryer
// Disables semantic parameter validation, which validates input for missing
// required fields and/or other semantic request input errors.
DisableParamValidation *bool
// Disables the computation of request and response checksums, e.g.,
// CRC32 checksums in Amazon DynamoDB.
DisableComputeChecksums *bool
// Set this to `true` to force the request to use path-style addressing,
// i.e., `http://s3.amazonaws.com/BUCKET/KEY`. By default, the S3 client will
// use virtual hosted bucket addressing when possible
// (`http://BUCKET.s3.amazonaws.com/KEY`).
//
// @note This configuration option is specific to the Amazon S3 service.
// @see http://docs.aws.amazon.com/AmazonS3/latest/dev/VirtualHosting.html
// Amazon S3: Virtual Hosting of Buckets
S3ForcePathStyle *bool
SleepDelay func(time.Duration)
}
// NewConfig returns a new Config pointer that can be chained with builder methods to
// set multiple configuration values inline without using pointers.
//
// svc := s3.New(aws.NewConfig().WithRegion("us-west-2").WithMaxRetries(10))
//
func NewConfig() *Config {
return &Config{}
}
// WithCredentials sets a config Credentials value returning a Config pointer
// for chaining.
func (c *Config) WithCredentials(creds *credentials.Credentials) *Config {
c.Credentials = creds
return c
}
// WithEndpoint sets a config Endpoint value returning a Config pointer for
// chaining.
func (c *Config) WithEndpoint(endpoint string) *Config {
c.Endpoint = &endpoint
return c
}
// WithRegion sets a config Region value returning a Config pointer for
// chaining.
func (c *Config) WithRegion(region string) *Config {
c.Region = &region
return c
}
// WithDisableSSL sets a config DisableSSL value returning a Config pointer
// for chaining.
func (c *Config) WithDisableSSL(disable bool) *Config {
c.DisableSSL = &disable
return c
}
// WithHTTPClient sets a config HTTPClient value returning a Config pointer
// for chaining.
func (c *Config) WithHTTPClient(client *http.Client) *Config {
c.HTTPClient = client
return c
}
// WithMaxRetries sets a config MaxRetries value returning a Config pointer
// for chaining.
func (c *Config) WithMaxRetries(max int) *Config {
c.MaxRetries = &max
return c
}
// WithDisableParamValidation sets a config DisableParamValidation value
// returning a Config pointer for chaining.
func (c *Config) WithDisableParamValidation(disable bool) *Config {
c.DisableParamValidation = &disable
return c
}
// WithDisableComputeChecksums sets a config DisableComputeChecksums value
// returning a Config pointer for chaining.
func (c *Config) WithDisableComputeChecksums(disable bool) *Config {
c.DisableComputeChecksums = &disable
return c
}
// WithLogLevel sets a config LogLevel value returning a Config pointer for
// chaining.
func (c *Config) WithLogLevel(level LogLevelType) *Config {
c.LogLevel = &level
return c
}
// WithLogger sets a config Logger value returning a Config pointer for
// chaining.
func (c *Config) WithLogger(logger Logger) *Config {
c.Logger = logger
return c
}
// WithS3ForcePathStyle sets a config S3ForcePathStyle value returning a Config
// pointer for chaining.
func (c *Config) WithS3ForcePathStyle(force bool) *Config {
c.S3ForcePathStyle = &force
return c
}
// WithSleepDelay overrides the function used to sleep while waiting for the
// next retry. Defaults to time.Sleep.
func (c *Config) WithSleepDelay(fn func(time.Duration)) *Config {
c.SleepDelay = fn
return c
}
// MergeIn merges the passed in configs into the existing config object.
func (c *Config) MergeIn(cfgs ...*Config) {
for _, other := range cfgs {
mergeInConfig(c, other)
}
}
func mergeInConfig(dst *Config, other *Config) {
if other == nil {
return
}
if other.Credentials != nil {
dst.Credentials = other.Credentials
}
if other.Endpoint != nil {
dst.Endpoint = other.Endpoint
}
if other.Region != nil {
dst.Region = other.Region
}
if other.DisableSSL != nil {
dst.DisableSSL = other.DisableSSL
}
if other.HTTPClient != nil {
dst.HTTPClient = other.HTTPClient
}
if other.LogLevel != nil {
dst.LogLevel = other.LogLevel
}
if other.Logger != nil {
dst.Logger = other.Logger
}
if other.MaxRetries != nil {
dst.MaxRetries = other.MaxRetries
}
if other.Retryer != nil {
dst.Retryer = other.Retryer
}
if other.DisableParamValidation != nil {
dst.DisableParamValidation = other.DisableParamValidation
}
if other.DisableComputeChecksums != nil {
dst.DisableComputeChecksums = other.DisableComputeChecksums
}
if other.S3ForcePathStyle != nil {
dst.S3ForcePathStyle = other.S3ForcePathStyle
}
if other.SleepDelay != nil {
dst.SleepDelay = other.SleepDelay
}
}
// Copy will return a shallow copy of the Config object. If any additional
// configurations are provided they will be merged into the new config returned.
func (c *Config) Copy(cfgs ...*Config) *Config {
dst := &Config{}
dst.MergeIn(c)
for _, cfg := range cfgs {
dst.MergeIn(cfg)
}
return dst
}

View File

@@ -0,0 +1,86 @@
package aws
import (
"net/http"
"reflect"
"testing"
"github.com/aws/aws-sdk-go/aws/credentials"
)
var testCredentials = credentials.NewStaticCredentials("AKID", "SECRET", "SESSION")
var copyTestConfig = Config{
Credentials: testCredentials,
Endpoint: String("CopyTestEndpoint"),
Region: String("COPY_TEST_AWS_REGION"),
DisableSSL: Bool(true),
HTTPClient: http.DefaultClient,
LogLevel: LogLevel(LogDebug),
Logger: NewDefaultLogger(),
MaxRetries: Int(3),
DisableParamValidation: Bool(true),
DisableComputeChecksums: Bool(true),
S3ForcePathStyle: Bool(true),
}
func TestCopy(t *testing.T) {
want := copyTestConfig
got := copyTestConfig.Copy()
if !reflect.DeepEqual(*got, want) {
t.Errorf("Copy() = %+v", got)
t.Errorf(" want %+v", want)
}
got.Region = String("other")
if got.Region == want.Region {
t.Errorf("Expect setting copy values not not reflect in source")
}
}
func TestCopyReturnsNewInstance(t *testing.T) {
want := copyTestConfig
got := copyTestConfig.Copy()
if got == &want {
t.Errorf("Copy() = %p; want different instance as source %p", got, &want)
}
}
var mergeTestZeroValueConfig = Config{}
var mergeTestConfig = Config{
Credentials: testCredentials,
Endpoint: String("MergeTestEndpoint"),
Region: String("MERGE_TEST_AWS_REGION"),
DisableSSL: Bool(true),
HTTPClient: http.DefaultClient,
LogLevel: LogLevel(LogDebug),
Logger: NewDefaultLogger(),
MaxRetries: Int(10),
DisableParamValidation: Bool(true),
DisableComputeChecksums: Bool(true),
S3ForcePathStyle: Bool(true),
}
var mergeTests = []struct {
cfg *Config
in *Config
want *Config
}{
{&Config{}, nil, &Config{}},
{&Config{}, &mergeTestZeroValueConfig, &Config{}},
{&Config{}, &mergeTestConfig, &mergeTestConfig},
}
func TestMerge(t *testing.T) {
for i, tt := range mergeTests {
got := tt.cfg.Copy()
got.MergeIn(tt.in)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Config %d %+v", i, tt.cfg)
t.Errorf(" Merge(%+v)", tt.in)
t.Errorf(" got %+v", got)
t.Errorf(" want %+v", tt.want)
}
}
}

View File

@@ -0,0 +1,357 @@
package aws
import "time"
// String returns a pointer to of the string value passed in.
func String(v string) *string {
return &v
}
// StringValue returns the value of the string pointer passed in or
// "" if the pointer is nil.
func StringValue(v *string) string {
if v != nil {
return *v
}
return ""
}
// StringSlice converts a slice of string values into a slice of
// string pointers
func StringSlice(src []string) []*string {
dst := make([]*string, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// StringValueSlice converts a slice of string pointers into a slice of
// string values
func StringValueSlice(src []*string) []string {
dst := make([]string, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// StringMap converts a string map of string values into a string
// map of string pointers
func StringMap(src map[string]string) map[string]*string {
dst := make(map[string]*string)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// StringValueMap converts a string map of string pointers into a string
// map of string values
func StringValueMap(src map[string]*string) map[string]string {
dst := make(map[string]string)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Bool returns a pointer to of the bool value passed in.
func Bool(v bool) *bool {
return &v
}
// BoolValue returns the value of the bool pointer passed in or
// false if the pointer is nil.
func BoolValue(v *bool) bool {
if v != nil {
return *v
}
return false
}
// BoolSlice converts a slice of bool values into a slice of
// bool pointers
func BoolSlice(src []bool) []*bool {
dst := make([]*bool, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// BoolValueSlice converts a slice of bool pointers into a slice of
// bool values
func BoolValueSlice(src []*bool) []bool {
dst := make([]bool, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// BoolMap converts a string map of bool values into a string
// map of bool pointers
func BoolMap(src map[string]bool) map[string]*bool {
dst := make(map[string]*bool)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// BoolValueMap converts a string map of bool pointers into a string
// map of bool values
func BoolValueMap(src map[string]*bool) map[string]bool {
dst := make(map[string]bool)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Int returns a pointer to of the int value passed in.
func Int(v int) *int {
return &v
}
// IntValue returns the value of the int pointer passed in or
// 0 if the pointer is nil.
func IntValue(v *int) int {
if v != nil {
return *v
}
return 0
}
// IntSlice converts a slice of int values into a slice of
// int pointers
func IntSlice(src []int) []*int {
dst := make([]*int, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// IntValueSlice converts a slice of int pointers into a slice of
// int values
func IntValueSlice(src []*int) []int {
dst := make([]int, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// IntMap converts a string map of int values into a string
// map of int pointers
func IntMap(src map[string]int) map[string]*int {
dst := make(map[string]*int)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// IntValueMap converts a string map of int pointers into a string
// map of int values
func IntValueMap(src map[string]*int) map[string]int {
dst := make(map[string]int)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Int64 returns a pointer to of the int64 value passed in.
func Int64(v int64) *int64 {
return &v
}
// Int64Value returns the value of the int64 pointer passed in or
// 0 if the pointer is nil.
func Int64Value(v *int64) int64 {
if v != nil {
return *v
}
return 0
}
// Int64Slice converts a slice of int64 values into a slice of
// int64 pointers
func Int64Slice(src []int64) []*int64 {
dst := make([]*int64, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// Int64ValueSlice converts a slice of int64 pointers into a slice of
// int64 values
func Int64ValueSlice(src []*int64) []int64 {
dst := make([]int64, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// Int64Map converts a string map of int64 values into a string
// map of int64 pointers
func Int64Map(src map[string]int64) map[string]*int64 {
dst := make(map[string]*int64)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// Int64ValueMap converts a string map of int64 pointers into a string
// map of int64 values
func Int64ValueMap(src map[string]*int64) map[string]int64 {
dst := make(map[string]int64)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Float64 returns a pointer to of the float64 value passed in.
func Float64(v float64) *float64 {
return &v
}
// Float64Value returns the value of the float64 pointer passed in or
// 0 if the pointer is nil.
func Float64Value(v *float64) float64 {
if v != nil {
return *v
}
return 0
}
// Float64Slice converts a slice of float64 values into a slice of
// float64 pointers
func Float64Slice(src []float64) []*float64 {
dst := make([]*float64, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// Float64ValueSlice converts a slice of float64 pointers into a slice of
// float64 values
func Float64ValueSlice(src []*float64) []float64 {
dst := make([]float64, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// Float64Map converts a string map of float64 values into a string
// map of float64 pointers
func Float64Map(src map[string]float64) map[string]*float64 {
dst := make(map[string]*float64)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// Float64ValueMap converts a string map of float64 pointers into a string
// map of float64 values
func Float64ValueMap(src map[string]*float64) map[string]float64 {
dst := make(map[string]float64)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}
// Time returns a pointer to of the time.Time value passed in.
func Time(v time.Time) *time.Time {
return &v
}
// TimeValue returns the value of the time.Time pointer passed in or
// time.Time{} if the pointer is nil.
func TimeValue(v *time.Time) time.Time {
if v != nil {
return *v
}
return time.Time{}
}
// TimeSlice converts a slice of time.Time values into a slice of
// time.Time pointers
func TimeSlice(src []time.Time) []*time.Time {
dst := make([]*time.Time, len(src))
for i := 0; i < len(src); i++ {
dst[i] = &(src[i])
}
return dst
}
// TimeValueSlice converts a slice of time.Time pointers into a slice of
// time.Time values
func TimeValueSlice(src []*time.Time) []time.Time {
dst := make([]time.Time, len(src))
for i := 0; i < len(src); i++ {
if src[i] != nil {
dst[i] = *(src[i])
}
}
return dst
}
// TimeMap converts a string map of time.Time values into a string
// map of time.Time pointers
func TimeMap(src map[string]time.Time) map[string]*time.Time {
dst := make(map[string]*time.Time)
for k, val := range src {
v := val
dst[k] = &v
}
return dst
}
// TimeValueMap converts a string map of time.Time pointers into a string
// map of time.Time values
func TimeValueMap(src map[string]*time.Time) map[string]time.Time {
dst := make(map[string]time.Time)
for k, val := range src {
if val != nil {
dst[k] = *val
}
}
return dst
}

View File

@@ -0,0 +1,437 @@
package aws
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
var testCasesStringSlice = [][]string{
{"a", "b", "c", "d", "e"},
{"a", "b", "", "", "e"},
}
func TestStringSlice(t *testing.T) {
for idx, in := range testCasesStringSlice {
if in == nil {
continue
}
out := StringSlice(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
}
out2 := StringValueSlice(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
}
}
var testCasesStringValueSlice = [][]*string{
{String("a"), String("b"), nil, String("c")},
}
func TestStringValueSlice(t *testing.T) {
for idx, in := range testCasesStringValueSlice {
if in == nil {
continue
}
out := StringValueSlice(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
if in[i] == nil {
assert.Empty(t, out[i], "Unexpected value at idx %d", idx)
} else {
assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx)
}
}
out2 := StringSlice(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
for i := range out2 {
if in[i] == nil {
assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx)
} else {
assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx)
}
}
}
}
var testCasesStringMap = []map[string]string{
{"a": "1", "b": "2", "c": "3"},
}
func TestStringMap(t *testing.T) {
for idx, in := range testCasesStringMap {
if in == nil {
continue
}
out := StringMap(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
}
out2 := StringValueMap(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
}
}
var testCasesBoolSlice = [][]bool{
{true, true, false, false},
}
func TestBoolSlice(t *testing.T) {
for idx, in := range testCasesBoolSlice {
if in == nil {
continue
}
out := BoolSlice(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
}
out2 := BoolValueSlice(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
}
}
var testCasesBoolValueSlice = [][]*bool{}
func TestBoolValueSlice(t *testing.T) {
for idx, in := range testCasesBoolValueSlice {
if in == nil {
continue
}
out := BoolValueSlice(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
if in[i] == nil {
assert.Empty(t, out[i], "Unexpected value at idx %d", idx)
} else {
assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx)
}
}
out2 := BoolSlice(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
for i := range out2 {
if in[i] == nil {
assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx)
} else {
assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx)
}
}
}
}
var testCasesBoolMap = []map[string]bool{
{"a": true, "b": false, "c": true},
}
func TestBoolMap(t *testing.T) {
for idx, in := range testCasesBoolMap {
if in == nil {
continue
}
out := BoolMap(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
}
out2 := BoolValueMap(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
}
}
var testCasesIntSlice = [][]int{
{1, 2, 3, 4},
}
func TestIntSlice(t *testing.T) {
for idx, in := range testCasesIntSlice {
if in == nil {
continue
}
out := IntSlice(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
}
out2 := IntValueSlice(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
}
}
var testCasesIntValueSlice = [][]*int{}
func TestIntValueSlice(t *testing.T) {
for idx, in := range testCasesIntValueSlice {
if in == nil {
continue
}
out := IntValueSlice(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
if in[i] == nil {
assert.Empty(t, out[i], "Unexpected value at idx %d", idx)
} else {
assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx)
}
}
out2 := IntSlice(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
for i := range out2 {
if in[i] == nil {
assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx)
} else {
assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx)
}
}
}
}
var testCasesIntMap = []map[string]int{
{"a": 3, "b": 2, "c": 1},
}
func TestIntMap(t *testing.T) {
for idx, in := range testCasesIntMap {
if in == nil {
continue
}
out := IntMap(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
}
out2 := IntValueMap(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
}
}
var testCasesInt64Slice = [][]int64{
{1, 2, 3, 4},
}
func TestInt64Slice(t *testing.T) {
for idx, in := range testCasesInt64Slice {
if in == nil {
continue
}
out := Int64Slice(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
}
out2 := Int64ValueSlice(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
}
}
var testCasesInt64ValueSlice = [][]*int64{}
func TestInt64ValueSlice(t *testing.T) {
for idx, in := range testCasesInt64ValueSlice {
if in == nil {
continue
}
out := Int64ValueSlice(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
if in[i] == nil {
assert.Empty(t, out[i], "Unexpected value at idx %d", idx)
} else {
assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx)
}
}
out2 := Int64Slice(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
for i := range out2 {
if in[i] == nil {
assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx)
} else {
assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx)
}
}
}
}
var testCasesInt64Map = []map[string]int64{
{"a": 3, "b": 2, "c": 1},
}
func TestInt64Map(t *testing.T) {
for idx, in := range testCasesInt64Map {
if in == nil {
continue
}
out := Int64Map(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
}
out2 := Int64ValueMap(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
}
}
var testCasesFloat64Slice = [][]float64{
{1, 2, 3, 4},
}
func TestFloat64Slice(t *testing.T) {
for idx, in := range testCasesFloat64Slice {
if in == nil {
continue
}
out := Float64Slice(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
}
out2 := Float64ValueSlice(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
}
}
var testCasesFloat64ValueSlice = [][]*float64{}
func TestFloat64ValueSlice(t *testing.T) {
for idx, in := range testCasesFloat64ValueSlice {
if in == nil {
continue
}
out := Float64ValueSlice(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
if in[i] == nil {
assert.Empty(t, out[i], "Unexpected value at idx %d", idx)
} else {
assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx)
}
}
out2 := Float64Slice(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
for i := range out2 {
if in[i] == nil {
assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx)
} else {
assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx)
}
}
}
}
var testCasesFloat64Map = []map[string]float64{
{"a": 3, "b": 2, "c": 1},
}
func TestFloat64Map(t *testing.T) {
for idx, in := range testCasesFloat64Map {
if in == nil {
continue
}
out := Float64Map(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
}
out2 := Float64ValueMap(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
}
}
var testCasesTimeSlice = [][]time.Time{
{time.Now(), time.Now().AddDate(100, 0, 0)},
}
func TestTimeSlice(t *testing.T) {
for idx, in := range testCasesTimeSlice {
if in == nil {
continue
}
out := TimeSlice(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
}
out2 := TimeValueSlice(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
}
}
var testCasesTimeValueSlice = [][]*time.Time{}
func TestTimeValueSlice(t *testing.T) {
for idx, in := range testCasesTimeValueSlice {
if in == nil {
continue
}
out := TimeValueSlice(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
if in[i] == nil {
assert.Empty(t, out[i], "Unexpected value at idx %d", idx)
} else {
assert.Equal(t, *(in[i]), out[i], "Unexpected value at idx %d", idx)
}
}
out2 := TimeSlice(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
for i := range out2 {
if in[i] == nil {
assert.Empty(t, *(out2[i]), "Unexpected value at idx %d", idx)
} else {
assert.Equal(t, in[i], out2[i], "Unexpected value at idx %d", idx)
}
}
}
}
var testCasesTimeMap = []map[string]time.Time{
{"a": time.Now().AddDate(-100, 0, 0), "b": time.Now()},
}
func TestTimeMap(t *testing.T) {
for idx, in := range testCasesTimeMap {
if in == nil {
continue
}
out := TimeMap(in)
assert.Len(t, out, len(in), "Unexpected len at idx %d", idx)
for i := range out {
assert.Equal(t, in[i], *(out[i]), "Unexpected value at idx %d", idx)
}
out2 := TimeValueMap(out)
assert.Len(t, out2, len(in), "Unexpected len at idx %d", idx)
assert.Equal(t, in, out2, "Unexpected value at idx %d", idx)
}
}

View File

@@ -0,0 +1,139 @@
package corehandlers
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"regexp"
"runtime"
"strconv"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
)
// Interface for matching types which also have a Len method.
type lener interface {
Len() int
}
// BuildContentLengthHandler builds the content length of a request based on the body,
// or will use the HTTPRequest.Header's "Content-Length" if defined. If unable
// to determine request body length and no "Content-Length" was specified it will panic.
var BuildContentLengthHandler = request.NamedHandler{Name: "core.BuildContentLengthHandler", Fn: func(r *request.Request) {
if slength := r.HTTPRequest.Header.Get("Content-Length"); slength != "" {
length, _ := strconv.ParseInt(slength, 10, 64)
r.HTTPRequest.ContentLength = length
return
}
var length int64
switch body := r.Body.(type) {
case nil:
length = 0
case lener:
length = int64(body.Len())
case io.Seeker:
r.BodyStart, _ = body.Seek(0, 1)
end, _ := body.Seek(0, 2)
body.Seek(r.BodyStart, 0) // make sure to seek back to original location
length = end - r.BodyStart
default:
panic("Cannot get length of body, must provide `ContentLength`")
}
r.HTTPRequest.ContentLength = length
r.HTTPRequest.Header.Set("Content-Length", fmt.Sprintf("%d", length))
}}
// SDKVersionUserAgentHandler is a request handler for adding the SDK Version to the user agent.
var SDKVersionUserAgentHandler = request.NamedHandler{
Name: "core.SDKVersionUserAgentHandler",
Fn: request.MakeAddToUserAgentHandler(aws.SDKName, aws.SDKVersion,
runtime.Version(), runtime.GOOS, runtime.GOARCH),
}
var reStatusCode = regexp.MustCompile(`^(\d{3})`)
// SendHandler is a request handler to send service request using HTTP client.
var SendHandler = request.NamedHandler{Name: "core.SendHandler", Fn: func(r *request.Request) {
var err error
r.HTTPResponse, err = r.Config.HTTPClient.Do(r.HTTPRequest)
if err != nil {
// Capture the case where url.Error is returned for error processing
// response. e.g. 301 without location header comes back as string
// error and r.HTTPResponse is nil. Other url redirect errors will
// comeback in a similar method.
if e, ok := err.(*url.Error); ok && e.Err != nil {
if s := reStatusCode.FindStringSubmatch(e.Err.Error()); s != nil {
code, _ := strconv.ParseInt(s[1], 10, 64)
r.HTTPResponse = &http.Response{
StatusCode: int(code),
Status: http.StatusText(int(code)),
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
}
return
}
}
if r.HTTPResponse == nil {
// Add a dummy request response object to ensure the HTTPResponse
// value is consistent.
r.HTTPResponse = &http.Response{
StatusCode: int(0),
Status: http.StatusText(int(0)),
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
}
}
// Catch all other request errors.
r.Error = awserr.New("RequestError", "send request failed", err)
r.Retryable = aws.Bool(true) // network errors are retryable
}
}}
// ValidateResponseHandler is a request handler to validate service response.
var ValidateResponseHandler = request.NamedHandler{Name: "core.ValidateResponseHandler", Fn: func(r *request.Request) {
if r.HTTPResponse.StatusCode == 0 || r.HTTPResponse.StatusCode >= 300 {
// this may be replaced by an UnmarshalError handler
r.Error = awserr.New("UnknownError", "unknown error", nil)
}
}}
// AfterRetryHandler performs final checks to determine if the request should
// be retried and how long to delay.
var AfterRetryHandler = request.NamedHandler{Name: "core.AfterRetryHandler", Fn: func(r *request.Request) {
// If one of the other handlers already set the retry state
// we don't want to override it based on the service's state
if r.Retryable == nil {
r.Retryable = aws.Bool(r.ShouldRetry(r))
}
if r.WillRetry() {
r.RetryDelay = r.RetryRules(r)
r.Config.SleepDelay(r.RetryDelay)
// when the expired token exception occurs the credentials
// need to be expired locally so that the next request to
// get credentials will trigger a credentials refresh.
if r.IsErrorExpired() {
r.Config.Credentials.Expire()
}
r.RetryCount++
r.Error = nil
}
}}
// ValidateEndpointHandler is a request handler to validate a request had the
// appropriate Region and Endpoint set. Will set r.Error if the endpoint or
// region is not valid.
var ValidateEndpointHandler = request.NamedHandler{Name: "core.ValidateEndpointHandler", Fn: func(r *request.Request) {
if r.ClientInfo.SigningRegion == "" && aws.StringValue(r.Config.Region) == "" {
r.Error = aws.ErrMissingRegion
} else if r.ClientInfo.Endpoint == "" {
r.Error = aws.ErrMissingEndpoint
}
}}

View File

@@ -0,0 +1,113 @@
package corehandlers_test
import (
"fmt"
"net/http"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/corehandlers"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/awstesting"
)
func TestValidateEndpointHandler(t *testing.T) {
os.Clearenv()
svc := awstesting.NewClient(aws.NewConfig().WithRegion("us-west-2"))
svc.Handlers.Clear()
svc.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
err := req.Build()
assert.NoError(t, err)
}
func TestValidateEndpointHandlerErrorRegion(t *testing.T) {
os.Clearenv()
svc := awstesting.NewClient()
svc.Handlers.Clear()
svc.Handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
err := req.Build()
assert.Error(t, err)
assert.Equal(t, aws.ErrMissingRegion, err)
}
type mockCredsProvider struct {
expired bool
retrieveCalled bool
}
func (m *mockCredsProvider) Retrieve() (credentials.Value, error) {
m.retrieveCalled = true
return credentials.Value{}, nil
}
func (m *mockCredsProvider) IsExpired() bool {
return m.expired
}
func TestAfterRetryRefreshCreds(t *testing.T) {
os.Clearenv()
credProvider := &mockCredsProvider{}
svc := awstesting.NewClient(&aws.Config{
Credentials: credentials.NewCredentials(credProvider),
MaxRetries: aws.Int(1),
})
svc.Handlers.Clear()
svc.Handlers.ValidateResponse.PushBack(func(r *request.Request) {
r.Error = awserr.New("UnknownError", "", nil)
r.HTTPResponse = &http.Response{StatusCode: 400}
})
svc.Handlers.UnmarshalError.PushBack(func(r *request.Request) {
r.Error = awserr.New("ExpiredTokenException", "", nil)
})
svc.Handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
assert.True(t, svc.Config.Credentials.IsExpired(), "Expect to start out expired")
assert.False(t, credProvider.retrieveCalled)
req := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
req.Send()
assert.True(t, svc.Config.Credentials.IsExpired())
assert.False(t, credProvider.retrieveCalled)
_, err := svc.Config.Credentials.Get()
assert.NoError(t, err)
assert.True(t, credProvider.retrieveCalled)
}
type testSendHandlerTransport struct{}
func (t *testSendHandlerTransport) RoundTrip(r *http.Request) (*http.Response, error) {
return nil, fmt.Errorf("mock error")
}
func TestSendHandlerError(t *testing.T) {
svc := awstesting.NewClient(&aws.Config{
HTTPClient: &http.Client{
Transport: &testSendHandlerTransport{},
},
})
svc.Handlers.Clear()
svc.Handlers.Send.PushBackNamed(corehandlers.SendHandler)
r := svc.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
r.Send()
assert.Error(t, r.Error)
assert.NotNil(t, r.HTTPResponse)
}

View File

@@ -0,0 +1,144 @@
package corehandlers
import (
"fmt"
"reflect"
"strconv"
"strings"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/request"
)
// ValidateParametersHandler is a request handler to validate the input parameters.
// Validating parameters only has meaning if done prior to the request being sent.
var ValidateParametersHandler = request.NamedHandler{Name: "core.ValidateParametersHandler", Fn: func(r *request.Request) {
if r.ParamsFilled() {
v := validator{errors: []string{}}
v.validateAny(reflect.ValueOf(r.Params), "")
if count := len(v.errors); count > 0 {
format := "%d validation errors:\n- %s"
msg := fmt.Sprintf(format, count, strings.Join(v.errors, "\n- "))
r.Error = awserr.New("InvalidParameter", msg, nil)
}
}
}}
// A validator validates values. Collects validations errors which occurs.
type validator struct {
errors []string
}
// validateAny will validate any struct, slice or map type. All validations
// are also performed recursively for nested types.
func (v *validator) validateAny(value reflect.Value, path string) {
value = reflect.Indirect(value)
if !value.IsValid() {
return
}
switch value.Kind() {
case reflect.Struct:
v.validateStruct(value, path)
case reflect.Slice:
for i := 0; i < value.Len(); i++ {
v.validateAny(value.Index(i), path+fmt.Sprintf("[%d]", i))
}
case reflect.Map:
for _, n := range value.MapKeys() {
v.validateAny(value.MapIndex(n), path+fmt.Sprintf("[%q]", n.String()))
}
}
}
// validateStruct will validate the struct value's fields. If the structure has
// nested types those types will be validated also.
func (v *validator) validateStruct(value reflect.Value, path string) {
prefix := "."
if path == "" {
prefix = ""
}
for i := 0; i < value.Type().NumField(); i++ {
f := value.Type().Field(i)
if strings.ToLower(f.Name[0:1]) == f.Name[0:1] {
continue
}
fvalue := value.FieldByName(f.Name)
err := validateField(f, fvalue, validateFieldRequired, validateFieldMin)
if err != nil {
v.errors = append(v.errors, fmt.Sprintf("%s: %s", err.Error(), path+prefix+f.Name))
continue
}
v.validateAny(fvalue, path+prefix+f.Name)
}
}
type validatorFunc func(f reflect.StructField, fvalue reflect.Value) error
func validateField(f reflect.StructField, fvalue reflect.Value, funcs ...validatorFunc) error {
for _, fn := range funcs {
if err := fn(f, fvalue); err != nil {
return err
}
}
return nil
}
// Validates that a field has a valid value provided for required fields.
func validateFieldRequired(f reflect.StructField, fvalue reflect.Value) error {
if f.Tag.Get("required") == "" {
return nil
}
switch fvalue.Kind() {
case reflect.Ptr, reflect.Slice, reflect.Map:
if fvalue.IsNil() {
return fmt.Errorf("missing required parameter")
}
default:
if !fvalue.IsValid() {
return fmt.Errorf("missing required parameter")
}
}
return nil
}
// Validates that if a value is provided for a field, that value must be at
// least a minimum length.
func validateFieldMin(f reflect.StructField, fvalue reflect.Value) error {
minStr := f.Tag.Get("min")
if minStr == "" {
return nil
}
min, _ := strconv.ParseInt(minStr, 10, 64)
kind := fvalue.Kind()
if kind == reflect.Ptr {
if fvalue.IsNil() {
return nil
}
fvalue = fvalue.Elem()
}
switch fvalue.Kind() {
case reflect.String:
if int64(fvalue.Len()) < min {
return fmt.Errorf("field too short, minimum length %d", min)
}
case reflect.Slice, reflect.Map:
if fvalue.IsNil() {
return nil
}
if int64(fvalue.Len()) < min {
return fmt.Errorf("field too short, minimum length %d", min)
}
// TODO min can also apply to number minimum value.
}
return nil
}

View File

@@ -0,0 +1,134 @@
package corehandlers_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/client/metadata"
"github.com/aws/aws-sdk-go/aws/corehandlers"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/stretchr/testify/require"
)
var testSvc = func() *client.Client {
s := &client.Client{
Config: aws.Config{},
ClientInfo: metadata.ClientInfo{
ServiceName: "mock-service",
APIVersion: "2015-01-01",
},
}
return s
}()
type StructShape struct {
RequiredList []*ConditionalStructShape `required:"true"`
RequiredMap map[string]*ConditionalStructShape `required:"true"`
RequiredBool *bool `required:"true"`
OptionalStruct *ConditionalStructShape
hiddenParameter *string
metadataStructureShape
}
type metadataStructureShape struct {
SDKShapeTraits bool
}
type ConditionalStructShape struct {
Name *string `required:"true"`
SDKShapeTraits bool
}
func TestNoErrors(t *testing.T) {
input := &StructShape{
RequiredList: []*ConditionalStructShape{},
RequiredMap: map[string]*ConditionalStructShape{
"key1": {Name: aws.String("Name")},
"key2": {Name: aws.String("Name")},
},
RequiredBool: aws.Bool(true),
OptionalStruct: &ConditionalStructShape{Name: aws.String("Name")},
}
req := testSvc.NewRequest(&request.Operation{}, input, nil)
corehandlers.ValidateParametersHandler.Fn(req)
require.NoError(t, req.Error)
}
func TestMissingRequiredParameters(t *testing.T) {
input := &StructShape{}
req := testSvc.NewRequest(&request.Operation{}, input, nil)
corehandlers.ValidateParametersHandler.Fn(req)
require.Error(t, req.Error)
assert.Equal(t, "InvalidParameter", req.Error.(awserr.Error).Code())
assert.Equal(t, "3 validation errors:\n- missing required parameter: RequiredList\n- missing required parameter: RequiredMap\n- missing required parameter: RequiredBool", req.Error.(awserr.Error).Message())
}
func TestNestedMissingRequiredParameters(t *testing.T) {
input := &StructShape{
RequiredList: []*ConditionalStructShape{{}},
RequiredMap: map[string]*ConditionalStructShape{
"key1": {Name: aws.String("Name")},
"key2": {},
},
RequiredBool: aws.Bool(true),
OptionalStruct: &ConditionalStructShape{},
}
req := testSvc.NewRequest(&request.Operation{}, input, nil)
corehandlers.ValidateParametersHandler.Fn(req)
require.Error(t, req.Error)
assert.Equal(t, "InvalidParameter", req.Error.(awserr.Error).Code())
assert.Equal(t, "3 validation errors:\n- missing required parameter: RequiredList[0].Name\n- missing required parameter: RequiredMap[\"key2\"].Name\n- missing required parameter: OptionalStruct.Name", req.Error.(awserr.Error).Message())
}
type testInput struct {
StringField string `min:"5"`
PtrStrField *string `min:"2"`
ListField []string `min:"3"`
MapField map[string]string `min:"4"`
}
var testsFieldMin = []struct {
err awserr.Error
in testInput
}{
{
err: awserr.New("InvalidParameter", "1 validation errors:\n- field too short, minimum length 5: StringField", nil),
in: testInput{StringField: "abcd"},
},
{
err: awserr.New("InvalidParameter", "2 validation errors:\n- field too short, minimum length 5: StringField\n- field too short, minimum length 3: ListField", nil),
in: testInput{StringField: "abcd", ListField: []string{"a", "b"}},
},
{
err: awserr.New("InvalidParameter", "3 validation errors:\n- field too short, minimum length 5: StringField\n- field too short, minimum length 3: ListField\n- field too short, minimum length 4: MapField", nil),
in: testInput{StringField: "abcd", ListField: []string{"a", "b"}, MapField: map[string]string{"a": "a", "b": "b"}},
},
{
err: awserr.New("InvalidParameter", "1 validation errors:\n- field too short, minimum length 2: PtrStrField", nil),
in: testInput{StringField: "abcde", PtrStrField: aws.String("v")},
},
{
err: nil,
in: testInput{StringField: "abcde", PtrStrField: aws.String("value"),
ListField: []string{"a", "b", "c"}, MapField: map[string]string{"a": "a", "b": "b", "c": "c", "d": "d"}},
},
}
func TestValidateFieldMinParameter(t *testing.T) {
for i, c := range testsFieldMin {
req := testSvc.NewRequest(&request.Operation{}, &c.in, nil)
corehandlers.ValidateParametersHandler.Fn(req)
require.Equal(t, c.err, req.Error, "%d case failed", i)
}
}

View File

@@ -0,0 +1,85 @@
package credentials
import (
"github.com/aws/aws-sdk-go/aws/awserr"
)
var (
// ErrNoValidProvidersFoundInChain Is returned when there are no valid
// providers in the ChainProvider.
//
// @readonly
ErrNoValidProvidersFoundInChain = awserr.New("NoCredentialProviders", "no valid providers in chain", nil)
)
// A ChainProvider will search for a provider which returns credentials
// and cache that provider until Retrieve is called again.
//
// The ChainProvider provides a way of chaining multiple providers together
// which will pick the first available using priority order of the Providers
// in the list.
//
// If none of the Providers retrieve valid credentials Value, ChainProvider's
// Retrieve() will return the error ErrNoValidProvidersFoundInChain.
//
// If a Provider is found which returns valid credentials Value ChainProvider
// will cache that Provider for all calls to IsExpired(), until Retrieve is
// called again.
//
// Example of ChainProvider to be used with an EnvProvider and EC2RoleProvider.
// In this example EnvProvider will first check if any credentials are available
// vai the environment variables. If there are none ChainProvider will check
// the next Provider in the list, EC2RoleProvider in this case. If EC2RoleProvider
// does not return any credentials ChainProvider will return the error
// ErrNoValidProvidersFoundInChain
//
// creds := NewChainCredentials(
// []Provider{
// &EnvProvider{},
// &EC2RoleProvider{},
// })
//
// // Usage of ChainCredentials with aws.Config
// svc := ec2.New(&aws.Config{Credentials: creds})
//
type ChainProvider struct {
Providers []Provider
curr Provider
}
// NewChainCredentials returns a pointer to a new Credentials object
// wrapping a chain of providers.
func NewChainCredentials(providers []Provider) *Credentials {
return NewCredentials(&ChainProvider{
Providers: append([]Provider{}, providers...),
})
}
// Retrieve returns the credentials value or error if no provider returned
// without error.
//
// If a provider is found it will be cached and any calls to IsExpired()
// will return the expired state of the cached provider.
func (c *ChainProvider) Retrieve() (Value, error) {
for _, p := range c.Providers {
if creds, err := p.Retrieve(); err == nil {
c.curr = p
return creds, nil
}
}
c.curr = nil
// TODO better error reporting. maybe report error for each failed retrieve?
return Value{}, ErrNoValidProvidersFoundInChain
}
// IsExpired will returned the expired state of the currently cached provider
// if there is one. If there is no current provider, true will be returned.
func (c *ChainProvider) IsExpired() bool {
if c.curr != nil {
return c.curr.IsExpired()
}
return true
}

View File

@@ -0,0 +1,73 @@
package credentials
import (
"testing"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/stretchr/testify/assert"
)
func TestChainProviderGet(t *testing.T) {
p := &ChainProvider{
Providers: []Provider{
&stubProvider{err: awserr.New("FirstError", "first provider error", nil)},
&stubProvider{err: awserr.New("SecondError", "second provider error", nil)},
&stubProvider{
creds: Value{
AccessKeyID: "AKID",
SecretAccessKey: "SECRET",
SessionToken: "",
},
},
},
}
creds, err := p.Retrieve()
assert.Nil(t, err, "Expect no error")
assert.Equal(t, "AKID", creds.AccessKeyID, "Expect access key ID to match")
assert.Equal(t, "SECRET", creds.SecretAccessKey, "Expect secret access key to match")
assert.Empty(t, creds.SessionToken, "Expect session token to be empty")
}
func TestChainProviderIsExpired(t *testing.T) {
stubProvider := &stubProvider{expired: true}
p := &ChainProvider{
Providers: []Provider{
stubProvider,
},
}
assert.True(t, p.IsExpired(), "Expect expired to be true before any Retrieve")
_, err := p.Retrieve()
assert.Nil(t, err, "Expect no error")
assert.False(t, p.IsExpired(), "Expect not expired after retrieve")
stubProvider.expired = true
assert.True(t, p.IsExpired(), "Expect return of expired provider")
_, err = p.Retrieve()
assert.False(t, p.IsExpired(), "Expect not expired after retrieve")
}
func TestChainProviderWithNoProvider(t *testing.T) {
p := &ChainProvider{
Providers: []Provider{},
}
assert.True(t, p.IsExpired(), "Expect expired with no providers")
_, err := p.Retrieve()
assert.Equal(t, ErrNoValidProvidersFoundInChain, err, "Expect no providers error returned")
}
func TestChainProviderWithNoValidProvider(t *testing.T) {
p := &ChainProvider{
Providers: []Provider{
&stubProvider{err: awserr.New("FirstError", "first provider error", nil)},
&stubProvider{err: awserr.New("SecondError", "second provider error", nil)},
},
}
assert.True(t, p.IsExpired(), "Expect expired with no providers")
_, err := p.Retrieve()
assert.Equal(t, ErrNoValidProvidersFoundInChain, err, "Expect no providers error returned")
}

View File

@@ -0,0 +1,220 @@
// Package credentials provides credential retrieval and management
//
// The Credentials is the primary method of getting access to and managing
// credentials Values. Using dependency injection retrieval of the credential
// values is handled by a object which satisfies the Provider interface.
//
// By default the Credentials.Get() will cache the successful result of a
// Provider's Retrieve() until Provider.IsExpired() returns true. At which
// point Credentials will call Provider's Retrieve() to get new credential Value.
//
// The Provider is responsible for determining when credentials Value have expired.
// It is also important to note that Credentials will always call Retrieve the
// first time Credentials.Get() is called.
//
// Example of using the environment variable credentials.
//
// creds := NewEnvCredentials()
//
// // Retrieve the credentials value
// credValue, err := creds.Get()
// if err != nil {
// // handle error
// }
//
// Example of forcing credentials to expire and be refreshed on the next Get().
// This may be helpful to proactively expire credentials and refresh them sooner
// than they would naturally expire on their own.
//
// creds := NewCredentials(&EC2RoleProvider{})
// creds.Expire()
// credsValue, err := creds.Get()
// // New credentials will be retrieved instead of from cache.
//
//
// Custom Provider
//
// Each Provider built into this package also provides a helper method to generate
// a Credentials pointer setup with the provider. To use a custom Provider just
// create a type which satisfies the Provider interface and pass it to the
// NewCredentials method.
//
// type MyProvider struct{}
// func (m *MyProvider) Retrieve() (Value, error) {...}
// func (m *MyProvider) IsExpired() bool {...}
//
// creds := NewCredentials(&MyProvider{})
// credValue, err := creds.Get()
//
package credentials
import (
"sync"
"time"
)
// AnonymousCredentials is an empty Credential object that can be used as
// dummy placeholder credentials for requests that do not need signed.
//
// This Credentials can be used to configure a service to not sign requests
// when making service API calls. For example, when accessing public
// s3 buckets.
//
// svc := s3.New(&aws.Config{Credentials: AnonymousCredentials})
// // Access public S3 buckets.
//
// @readonly
var AnonymousCredentials = NewStaticCredentials("", "", "")
// A Value is the AWS credentials value for individual credential fields.
type Value struct {
// AWS Access key ID
AccessKeyID string
// AWS Secret Access Key
SecretAccessKey string
// AWS Session Token
SessionToken string
}
// A Provider is the interface for any component which will provide credentials
// Value. A provider is required to manage its own Expired state, and what to
// be expired means.
//
// The Provider should not need to implement its own mutexes, because
// that will be managed by Credentials.
type Provider interface {
// Refresh returns nil if it successfully retrieved the value.
// Error is returned if the value were not obtainable, or empty.
Retrieve() (Value, error)
// IsExpired returns if the credentials are no longer valid, and need
// to be retrieved.
IsExpired() bool
}
// A Expiry provides shared expiration logic to be used by credentials
// providers to implement expiry functionality.
//
// The best method to use this struct is as an anonymous field within the
// provider's struct.
//
// Example:
// type EC2RoleProvider struct {
// Expiry
// ...
// }
type Expiry struct {
// The date/time when to expire on
expiration time.Time
// If set will be used by IsExpired to determine the current time.
// Defaults to time.Now if CurrentTime is not set. Available for testing
// to be able to mock out the current time.
CurrentTime func() time.Time
}
// SetExpiration sets the expiration IsExpired will check when called.
//
// If window is greater than 0 the expiration time will be reduced by the
// window value.
//
// Using a window is helpful to trigger credentials to expire sooner than
// the expiration time given to ensure no requests are made with expired
// tokens.
func (e *Expiry) SetExpiration(expiration time.Time, window time.Duration) {
e.expiration = expiration
if window > 0 {
e.expiration = e.expiration.Add(-window)
}
}
// IsExpired returns if the credentials are expired.
func (e *Expiry) IsExpired() bool {
if e.CurrentTime == nil {
e.CurrentTime = time.Now
}
return e.expiration.Before(e.CurrentTime())
}
// A Credentials provides synchronous safe retrieval of AWS credentials Value.
// Credentials will cache the credentials value until they expire. Once the value
// expires the next Get will attempt to retrieve valid credentials.
//
// Credentials is safe to use across multiple goroutines and will manage the
// synchronous state so the Providers do not need to implement their own
// synchronization.
//
// The first Credentials.Get() will always call Provider.Retrieve() to get the
// first instance of the credentials Value. All calls to Get() after that
// will return the cached credentials Value until IsExpired() returns true.
type Credentials struct {
creds Value
forceRefresh bool
m sync.Mutex
provider Provider
}
// NewCredentials returns a pointer to a new Credentials with the provider set.
func NewCredentials(provider Provider) *Credentials {
return &Credentials{
provider: provider,
forceRefresh: true,
}
}
// Get returns the credentials value, or error if the credentials Value failed
// to be retrieved.
//
// Will return the cached credentials Value if it has not expired. If the
// credentials Value has expired the Provider's Retrieve() will be called
// to refresh the credentials.
//
// If Credentials.Expire() was called the credentials Value will be force
// expired, and the next call to Get() will cause them to be refreshed.
func (c *Credentials) Get() (Value, error) {
c.m.Lock()
defer c.m.Unlock()
if c.isExpired() {
creds, err := c.provider.Retrieve()
if err != nil {
return Value{}, err
}
c.creds = creds
c.forceRefresh = false
}
return c.creds, nil
}
// Expire expires the credentials and forces them to be retrieved on the
// next call to Get().
//
// This will override the Provider's expired state, and force Credentials
// to call the Provider's Retrieve().
func (c *Credentials) Expire() {
c.m.Lock()
defer c.m.Unlock()
c.forceRefresh = true
}
// IsExpired returns if the credentials are no longer valid, and need
// to be retrieved.
//
// If the Credentials were forced to be expired with Expire() this will
// reflect that override.
func (c *Credentials) IsExpired() bool {
c.m.Lock()
defer c.m.Unlock()
return c.isExpired()
}
// isExpired helper method wrapping the definition of expired credentials.
func (c *Credentials) isExpired() bool {
return c.forceRefresh || c.provider.IsExpired()
}

View File

@@ -0,0 +1,62 @@
package credentials
import (
"testing"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/stretchr/testify/assert"
)
type stubProvider struct {
creds Value
expired bool
err error
}
func (s *stubProvider) Retrieve() (Value, error) {
s.expired = false
return s.creds, s.err
}
func (s *stubProvider) IsExpired() bool {
return s.expired
}
func TestCredentialsGet(t *testing.T) {
c := NewCredentials(&stubProvider{
creds: Value{
AccessKeyID: "AKID",
SecretAccessKey: "SECRET",
SessionToken: "",
},
expired: true,
})
creds, err := c.Get()
assert.Nil(t, err, "Expected no error")
assert.Equal(t, "AKID", creds.AccessKeyID, "Expect access key ID to match")
assert.Equal(t, "SECRET", creds.SecretAccessKey, "Expect secret access key to match")
assert.Empty(t, creds.SessionToken, "Expect session token to be empty")
}
func TestCredentialsGetWithError(t *testing.T) {
c := NewCredentials(&stubProvider{err: awserr.New("provider error", "", nil), expired: true})
_, err := c.Get()
assert.Equal(t, "provider error", err.(awserr.Error).Code(), "Expected provider error")
}
func TestCredentialsExpire(t *testing.T) {
stub := &stubProvider{}
c := NewCredentials(stub)
stub.expired = false
assert.True(t, c.IsExpired(), "Expected to start out expired")
c.Expire()
assert.True(t, c.IsExpired(), "Expected to be expired")
c.forceRefresh = false
assert.False(t, c.IsExpired(), "Expected not to be expired")
stub.expired = true
assert.True(t, c.IsExpired(), "Expected to be expired")
}

View File

@@ -0,0 +1,173 @@
package ec2rolecreds
import (
"bufio"
"encoding/json"
"fmt"
"path"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
)
// A EC2RoleProvider retrieves credentials from the EC2 service, and keeps track if
// those credentials are expired.
//
// Example how to configure the EC2RoleProvider with custom http Client, Endpoint
// or ExpiryWindow
//
// p := &ec2rolecreds.EC2RoleProvider{
// // Pass in a custom timeout to be used when requesting
// // IAM EC2 Role credentials.
// Client: &http.Client{
// Timeout: 10 * time.Second,
// },
// // Do not use early expiry of credentials. If a non zero value is
// // specified the credentials will be expired early
// ExpiryWindow: 0,
// }
type EC2RoleProvider struct {
credentials.Expiry
// Required EC2Metadata client to use when connecting to EC2 metadata service.
Client *ec2metadata.EC2Metadata
// ExpiryWindow will allow the credentials to trigger refreshing prior to
// the credentials actually expiring. This is beneficial so race conditions
// with expiring credentials do not cause request to fail unexpectedly
// due to ExpiredTokenException exceptions.
//
// So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
// 10 seconds before the credentials are actually expired.
//
// If ExpiryWindow is 0 or less it will be ignored.
ExpiryWindow time.Duration
}
// NewCredentials returns a pointer to a new Credentials object wrapping
// the EC2RoleProvider. Takes a ConfigProvider to create a EC2Metadata client.
// The ConfigProvider is satisfied by the session.Session type.
func NewCredentials(c client.ConfigProvider, options ...func(*EC2RoleProvider)) *credentials.Credentials {
p := &EC2RoleProvider{
Client: ec2metadata.New(c),
}
for _, option := range options {
option(p)
}
return credentials.NewCredentials(p)
}
// NewCredentialsWithClient returns a pointer to a new Credentials object wrapping
// the EC2RoleProvider. Takes a EC2Metadata client to use when connecting to EC2
// metadata service.
func NewCredentialsWithClient(client *ec2metadata.EC2Metadata, options ...func(*EC2RoleProvider)) *credentials.Credentials {
p := &EC2RoleProvider{
Client: client,
}
for _, option := range options {
option(p)
}
return credentials.NewCredentials(p)
}
// Retrieve retrieves credentials from the EC2 service.
// Error will be returned if the request fails, or unable to extract
// the desired credentials.
func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
credsList, err := requestCredList(m.Client)
if err != nil {
return credentials.Value{}, err
}
if len(credsList) == 0 {
return credentials.Value{}, awserr.New("EmptyEC2RoleList", "empty EC2 Role list", nil)
}
credsName := credsList[0]
roleCreds, err := requestCred(m.Client, credsName)
if err != nil {
return credentials.Value{}, err
}
m.SetExpiration(roleCreds.Expiration, m.ExpiryWindow)
return credentials.Value{
AccessKeyID: roleCreds.AccessKeyID,
SecretAccessKey: roleCreds.SecretAccessKey,
SessionToken: roleCreds.Token,
}, nil
}
// A ec2RoleCredRespBody provides the shape for unmarshalling credential
// request responses.
type ec2RoleCredRespBody struct {
// Success State
Expiration time.Time
AccessKeyID string
SecretAccessKey string
Token string
// Error state
Code string
Message string
}
const iamSecurityCredsPath = "/iam/security-credentials"
// requestCredList requests a list of credentials from the EC2 service.
// If there are no credentials, or there is an error making or receiving the request
func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) {
resp, err := client.GetMetadata(iamSecurityCredsPath)
if err != nil {
return nil, awserr.New("EC2RoleRequestError", "failed to list EC2 Roles", err)
}
credsList := []string{}
s := bufio.NewScanner(strings.NewReader(resp))
for s.Scan() {
credsList = append(credsList, s.Text())
}
if err := s.Err(); err != nil {
return nil, awserr.New("SerializationError", "failed to read list of EC2 Roles", err)
}
return credsList, nil
}
// requestCred requests the credentials for a specific credentials from the EC2 service.
//
// If the credentials cannot be found, or there is an error reading the response
// and error will be returned.
func requestCred(client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) {
resp, err := client.GetMetadata(path.Join(iamSecurityCredsPath, credsName))
if err != nil {
return ec2RoleCredRespBody{},
awserr.New("EC2RoleRequestError",
fmt.Sprintf("failed to get %s EC2 Role credentials", credsName),
err)
}
respCreds := ec2RoleCredRespBody{}
if err := json.NewDecoder(strings.NewReader(resp)).Decode(&respCreds); err != nil {
return ec2RoleCredRespBody{},
awserr.New("SerializationError",
fmt.Sprintf("failed to decode %s EC2 Role credentials", credsName),
err)
}
if respCreds.Code != "Success" {
// If an error code was returned something failed requesting the role.
return ec2RoleCredRespBody{}, awserr.New(respCreds.Code, respCreds.Message, nil)
}
return respCreds, nil
}

View File

@@ -0,0 +1,159 @@
package ec2rolecreds_test
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
"github.com/aws/aws-sdk-go/aws/session"
)
const credsRespTmpl = `{
"Code": "Success",
"Type": "AWS-HMAC",
"AccessKeyId" : "accessKey",
"SecretAccessKey" : "secret",
"Token" : "token",
"Expiration" : "%s",
"LastUpdated" : "2009-11-23T0:00:00Z"
}`
const credsFailRespTmpl = `{
"Code": "ErrorCode",
"Message": "ErrorMsg",
"LastUpdated": "2009-11-23T0:00:00Z"
}`
func initTestServer(expireOn string, failAssume bool) *httptest.Server {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/latest/meta-data/iam/security-credentials" {
fmt.Fprintln(w, "RoleName")
} else if r.URL.Path == "/latest/meta-data/iam/security-credentials/RoleName" {
if failAssume {
fmt.Fprintf(w, credsFailRespTmpl)
} else {
fmt.Fprintf(w, credsRespTmpl, expireOn)
}
} else {
http.Error(w, "bad request", http.StatusBadRequest)
}
}))
return server
}
func TestEC2RoleProvider(t *testing.T) {
server := initTestServer("2014-12-16T01:51:37Z", false)
defer server.Close()
p := &ec2rolecreds.EC2RoleProvider{
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
}
creds, err := p.Retrieve()
assert.Nil(t, err, "Expect no error, %v", err)
assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match")
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
assert.Equal(t, "token", creds.SessionToken, "Expect session token to match")
}
func TestEC2RoleProviderFailAssume(t *testing.T) {
server := initTestServer("2014-12-16T01:51:37Z", true)
defer server.Close()
p := &ec2rolecreds.EC2RoleProvider{
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
}
creds, err := p.Retrieve()
assert.Error(t, err, "Expect error")
e := err.(awserr.Error)
assert.Equal(t, "ErrorCode", e.Code())
assert.Equal(t, "ErrorMsg", e.Message())
assert.Nil(t, e.OrigErr())
assert.Equal(t, "", creds.AccessKeyID, "Expect access key ID to match")
assert.Equal(t, "", creds.SecretAccessKey, "Expect secret access key to match")
assert.Equal(t, "", creds.SessionToken, "Expect session token to match")
}
func TestEC2RoleProviderIsExpired(t *testing.T) {
server := initTestServer("2014-12-16T01:51:37Z", false)
defer server.Close()
p := &ec2rolecreds.EC2RoleProvider{
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
}
p.CurrentTime = func() time.Time {
return time.Date(2014, 12, 15, 21, 26, 0, 0, time.UTC)
}
assert.True(t, p.IsExpired(), "Expect creds to be expired before retrieve.")
_, err := p.Retrieve()
assert.Nil(t, err, "Expect no error, %v", err)
assert.False(t, p.IsExpired(), "Expect creds to not be expired after retrieve.")
p.CurrentTime = func() time.Time {
return time.Date(3014, 12, 15, 21, 26, 0, 0, time.UTC)
}
assert.True(t, p.IsExpired(), "Expect creds to be expired.")
}
func TestEC2RoleProviderExpiryWindowIsExpired(t *testing.T) {
server := initTestServer("2014-12-16T01:51:37Z", false)
defer server.Close()
p := &ec2rolecreds.EC2RoleProvider{
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
ExpiryWindow: time.Hour * 1,
}
p.CurrentTime = func() time.Time {
return time.Date(2014, 12, 15, 0, 51, 37, 0, time.UTC)
}
assert.True(t, p.IsExpired(), "Expect creds to be expired before retrieve.")
_, err := p.Retrieve()
assert.Nil(t, err, "Expect no error, %v", err)
assert.False(t, p.IsExpired(), "Expect creds to not be expired after retrieve.")
p.CurrentTime = func() time.Time {
return time.Date(2014, 12, 16, 0, 55, 37, 0, time.UTC)
}
assert.True(t, p.IsExpired(), "Expect creds to be expired.")
}
func BenchmarkEC3RoleProvider(b *testing.B) {
server := initTestServer("2014-12-16T01:51:37Z", false)
defer server.Close()
p := &ec2rolecreds.EC2RoleProvider{
Client: ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")}),
}
_, err := p.Retrieve()
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := p.Retrieve(); err != nil {
b.Fatal(err)
}
}
}

View File

@@ -0,0 +1,73 @@
package credentials
import (
"os"
"github.com/aws/aws-sdk-go/aws/awserr"
)
var (
// ErrAccessKeyIDNotFound is returned when the AWS Access Key ID can't be
// found in the process's environment.
//
// @readonly
ErrAccessKeyIDNotFound = awserr.New("EnvAccessKeyNotFound", "AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment", nil)
// ErrSecretAccessKeyNotFound is returned when the AWS Secret Access Key
// can't be found in the process's environment.
//
// @readonly
ErrSecretAccessKeyNotFound = awserr.New("EnvSecretNotFound", "AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment", nil)
)
// A EnvProvider retrieves credentials from the environment variables of the
// running process. Environment credentials never expire.
//
// Environment variables used:
//
// * Access Key ID: AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY
// * Secret Access Key: AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY
type EnvProvider struct {
retrieved bool
}
// NewEnvCredentials returns a pointer to a new Credentials object
// wrapping the environment variable provider.
func NewEnvCredentials() *Credentials {
return NewCredentials(&EnvProvider{})
}
// Retrieve retrieves the keys from the environment.
func (e *EnvProvider) Retrieve() (Value, error) {
e.retrieved = false
id := os.Getenv("AWS_ACCESS_KEY_ID")
if id == "" {
id = os.Getenv("AWS_ACCESS_KEY")
}
secret := os.Getenv("AWS_SECRET_ACCESS_KEY")
if secret == "" {
secret = os.Getenv("AWS_SECRET_KEY")
}
if id == "" {
return Value{}, ErrAccessKeyIDNotFound
}
if secret == "" {
return Value{}, ErrSecretAccessKeyNotFound
}
e.retrieved = true
return Value{
AccessKeyID: id,
SecretAccessKey: secret,
SessionToken: os.Getenv("AWS_SESSION_TOKEN"),
}, nil
}
// IsExpired returns if the credentials have been retrieved.
func (e *EnvProvider) IsExpired() bool {
return !e.retrieved
}

View File

@@ -0,0 +1,70 @@
package credentials
import (
"github.com/stretchr/testify/assert"
"os"
"testing"
)
func TestEnvProviderRetrieve(t *testing.T) {
os.Clearenv()
os.Setenv("AWS_ACCESS_KEY_ID", "access")
os.Setenv("AWS_SECRET_ACCESS_KEY", "secret")
os.Setenv("AWS_SESSION_TOKEN", "token")
e := EnvProvider{}
creds, err := e.Retrieve()
assert.Nil(t, err, "Expect no error")
assert.Equal(t, "access", creds.AccessKeyID, "Expect access key ID to match")
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
assert.Equal(t, "token", creds.SessionToken, "Expect session token to match")
}
func TestEnvProviderIsExpired(t *testing.T) {
os.Clearenv()
os.Setenv("AWS_ACCESS_KEY_ID", "access")
os.Setenv("AWS_SECRET_ACCESS_KEY", "secret")
os.Setenv("AWS_SESSION_TOKEN", "token")
e := EnvProvider{}
assert.True(t, e.IsExpired(), "Expect creds to be expired before retrieve.")
_, err := e.Retrieve()
assert.Nil(t, err, "Expect no error")
assert.False(t, e.IsExpired(), "Expect creds to not be expired after retrieve.")
}
func TestEnvProviderNoAccessKeyID(t *testing.T) {
os.Clearenv()
os.Setenv("AWS_SECRET_ACCESS_KEY", "secret")
e := EnvProvider{}
creds, err := e.Retrieve()
assert.Equal(t, ErrAccessKeyIDNotFound, err, "ErrAccessKeyIDNotFound expected, but was %#v error: %#v", creds, err)
}
func TestEnvProviderNoSecretAccessKey(t *testing.T) {
os.Clearenv()
os.Setenv("AWS_ACCESS_KEY_ID", "access")
e := EnvProvider{}
creds, err := e.Retrieve()
assert.Equal(t, ErrSecretAccessKeyNotFound, err, "ErrSecretAccessKeyNotFound expected, but was %#v error: %#v", creds, err)
}
func TestEnvProviderAlternateNames(t *testing.T) {
os.Clearenv()
os.Setenv("AWS_ACCESS_KEY", "access")
os.Setenv("AWS_SECRET_KEY", "secret")
e := EnvProvider{}
creds, err := e.Retrieve()
assert.Nil(t, err, "Expect no error")
assert.Equal(t, "access", creds.AccessKeyID, "Expected access key ID")
assert.Equal(t, "secret", creds.SecretAccessKey, "Expected secret access key")
assert.Empty(t, creds.SessionToken, "Expected no token")
}

View File

@@ -0,0 +1,12 @@
[default]
aws_access_key_id = accessKey
aws_secret_access_key = secret
aws_session_token = token
[no_token]
aws_access_key_id = accessKey
aws_secret_access_key = secret
[with_colon]
aws_access_key_id: accessKey
aws_secret_access_key: secret

View File

@@ -0,0 +1,147 @@
package credentials
import (
"fmt"
"os"
"path/filepath"
"github.com/go-ini/ini"
"github.com/aws/aws-sdk-go/aws/awserr"
)
var (
// ErrSharedCredentialsHomeNotFound is emitted when the user directory cannot be found.
//
// @readonly
ErrSharedCredentialsHomeNotFound = awserr.New("UserHomeNotFound", "user home directory not found.", nil)
)
// A SharedCredentialsProvider retrieves credentials from the current user's home
// directory, and keeps track if those credentials are expired.
//
// Profile ini file example: $HOME/.aws/credentials
type SharedCredentialsProvider struct {
// Path to the shared credentials file.
//
// If empty will look for "AWS_SHARED_CREDENTIALS_FILE" env variable. If the
// env value is empty will default to current user's home directory.
// Linux/OSX: "$HOME/.aws/credentials"
// Windows: "%USERPROFILE%\.aws\credentials"
Filename string
// AWS Profile to extract credentials from the shared credentials file. If empty
// will default to environment variable "AWS_PROFILE" or "default" if
// environment variable is also not set.
Profile string
// retrieved states if the credentials have been successfully retrieved.
retrieved bool
}
// NewSharedCredentials returns a pointer to a new Credentials object
// wrapping the Profile file provider.
func NewSharedCredentials(filename, profile string) *Credentials {
return NewCredentials(&SharedCredentialsProvider{
Filename: filename,
Profile: profile,
})
}
// Retrieve reads and extracts the shared credentials from the current
// users home directory.
func (p *SharedCredentialsProvider) Retrieve() (Value, error) {
p.retrieved = false
filename, err := p.filename()
if err != nil {
return Value{}, err
}
creds, err := loadProfile(filename, p.profile())
if err != nil {
return Value{}, err
}
p.retrieved = true
return creds, nil
}
// IsExpired returns if the shared credentials have expired.
func (p *SharedCredentialsProvider) IsExpired() bool {
return !p.retrieved
}
// loadProfiles loads from the file pointed to by shared credentials filename for profile.
// The credentials retrieved from the profile will be returned or error. Error will be
// returned if it fails to read from the file, or the data is invalid.
func loadProfile(filename, profile string) (Value, error) {
config, err := ini.Load(filename)
if err != nil {
return Value{}, awserr.New("SharedCredsLoad", "failed to load shared credentials file", err)
}
iniProfile, err := config.GetSection(profile)
if err != nil {
return Value{}, awserr.New("SharedCredsLoad", "failed to get profile", err)
}
id, err := iniProfile.GetKey("aws_access_key_id")
if err != nil {
return Value{}, awserr.New("SharedCredsAccessKey",
fmt.Sprintf("shared credentials %s in %s did not contain aws_access_key_id", profile, filename),
err)
}
secret, err := iniProfile.GetKey("aws_secret_access_key")
if err != nil {
return Value{}, awserr.New("SharedCredsSecret",
fmt.Sprintf("shared credentials %s in %s did not contain aws_secret_access_key", profile, filename),
nil)
}
// Default to empty string if not found
token := iniProfile.Key("aws_session_token")
return Value{
AccessKeyID: id.String(),
SecretAccessKey: secret.String(),
SessionToken: token.String(),
}, nil
}
// filename returns the filename to use to read AWS shared credentials.
//
// Will return an error if the user's home directory path cannot be found.
func (p *SharedCredentialsProvider) filename() (string, error) {
if p.Filename == "" {
if p.Filename = os.Getenv("AWS_SHARED_CREDENTIALS_FILE"); p.Filename != "" {
return p.Filename, nil
}
homeDir := os.Getenv("HOME") // *nix
if homeDir == "" { // Windows
homeDir = os.Getenv("USERPROFILE")
}
if homeDir == "" {
return "", ErrSharedCredentialsHomeNotFound
}
p.Filename = filepath.Join(homeDir, ".aws", "credentials")
}
return p.Filename, nil
}
// profile returns the AWS shared credentials profile. If empty will read
// environment variable "AWS_PROFILE". If that is not set profile will
// return "default".
func (p *SharedCredentialsProvider) profile() string {
if p.Profile == "" {
p.Profile = os.Getenv("AWS_PROFILE")
}
if p.Profile == "" {
p.Profile = "default"
}
return p.Profile
}

View File

@@ -0,0 +1,100 @@
package credentials
import (
"github.com/stretchr/testify/assert"
"os"
"testing"
)
func TestSharedCredentialsProvider(t *testing.T) {
os.Clearenv()
p := SharedCredentialsProvider{Filename: "example.ini", Profile: ""}
creds, err := p.Retrieve()
assert.Nil(t, err, "Expect no error")
assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match")
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
assert.Equal(t, "token", creds.SessionToken, "Expect session token to match")
}
func TestSharedCredentialsProviderIsExpired(t *testing.T) {
os.Clearenv()
p := SharedCredentialsProvider{Filename: "example.ini", Profile: ""}
assert.True(t, p.IsExpired(), "Expect creds to be expired before retrieve")
_, err := p.Retrieve()
assert.Nil(t, err, "Expect no error")
assert.False(t, p.IsExpired(), "Expect creds to not be expired after retrieve")
}
func TestSharedCredentialsProviderWithAWS_SHARED_CREDENTIALS_FILE(t *testing.T) {
os.Clearenv()
os.Setenv("AWS_SHARED_CREDENTIALS_FILE", "example.ini")
p := SharedCredentialsProvider{}
creds, err := p.Retrieve()
assert.Nil(t, err, "Expect no error")
assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match")
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
assert.Equal(t, "token", creds.SessionToken, "Expect session token to match")
}
func TestSharedCredentialsProviderWithAWS_PROFILE(t *testing.T) {
os.Clearenv()
os.Setenv("AWS_PROFILE", "no_token")
p := SharedCredentialsProvider{Filename: "example.ini", Profile: ""}
creds, err := p.Retrieve()
assert.Nil(t, err, "Expect no error")
assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match")
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
assert.Empty(t, creds.SessionToken, "Expect no token")
}
func TestSharedCredentialsProviderWithoutTokenFromProfile(t *testing.T) {
os.Clearenv()
p := SharedCredentialsProvider{Filename: "example.ini", Profile: "no_token"}
creds, err := p.Retrieve()
assert.Nil(t, err, "Expect no error")
assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match")
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
assert.Empty(t, creds.SessionToken, "Expect no token")
}
func TestSharedCredentialsProviderColonInCredFile(t *testing.T) {
os.Clearenv()
p := SharedCredentialsProvider{Filename: "example.ini", Profile: "with_colon"}
creds, err := p.Retrieve()
assert.Nil(t, err, "Expect no error")
assert.Equal(t, "accessKey", creds.AccessKeyID, "Expect access key ID to match")
assert.Equal(t, "secret", creds.SecretAccessKey, "Expect secret access key to match")
assert.Empty(t, creds.SessionToken, "Expect no token")
}
func BenchmarkSharedCredentialsProvider(b *testing.B) {
os.Clearenv()
p := SharedCredentialsProvider{Filename: "example.ini", Profile: ""}
_, err := p.Retrieve()
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := p.Retrieve()
if err != nil {
b.Fatal(err)
}
}
}

View File

@@ -0,0 +1,44 @@
package credentials
import (
"github.com/aws/aws-sdk-go/aws/awserr"
)
var (
// ErrStaticCredentialsEmpty is emitted when static credentials are empty.
//
// @readonly
ErrStaticCredentialsEmpty = awserr.New("EmptyStaticCreds", "static credentials are empty", nil)
)
// A StaticProvider is a set of credentials which are set pragmatically,
// and will never expire.
type StaticProvider struct {
Value
}
// NewStaticCredentials returns a pointer to a new Credentials object
// wrapping a static credentials value provider.
func NewStaticCredentials(id, secret, token string) *Credentials {
return NewCredentials(&StaticProvider{Value: Value{
AccessKeyID: id,
SecretAccessKey: secret,
SessionToken: token,
}})
}
// Retrieve returns the credentials or error if the credentials are invalid.
func (s *StaticProvider) Retrieve() (Value, error) {
if s.AccessKeyID == "" || s.SecretAccessKey == "" {
return Value{}, ErrStaticCredentialsEmpty
}
return s.Value, nil
}
// IsExpired returns if the credentials are expired.
//
// For StaticProvider, the credentials never expired.
func (s *StaticProvider) IsExpired() bool {
return false
}

View File

@@ -0,0 +1,34 @@
package credentials
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestStaticProviderGet(t *testing.T) {
s := StaticProvider{
Value: Value{
AccessKeyID: "AKID",
SecretAccessKey: "SECRET",
SessionToken: "",
},
}
creds, err := s.Retrieve()
assert.Nil(t, err, "Expect no error")
assert.Equal(t, "AKID", creds.AccessKeyID, "Expect access key ID to match")
assert.Equal(t, "SECRET", creds.SecretAccessKey, "Expect secret access key to match")
assert.Empty(t, creds.SessionToken, "Expect no session token")
}
func TestStaticProviderIsExpired(t *testing.T) {
s := StaticProvider{
Value: Value{
AccessKeyID: "AKID",
SecretAccessKey: "SECRET",
SessionToken: "",
},
}
assert.False(t, s.IsExpired(), "Expect static credentials to never expire")
}

View File

@@ -0,0 +1,130 @@
// Package stscreds are credential Providers to retrieve STS AWS credentials.
//
// STS provides multiple ways to retrieve credentials which can be used when making
// future AWS service API operation calls.
package stscreds
import (
"fmt"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/service/sts"
)
// AssumeRoler represents the minimal subset of the STS client API used by this provider.
type AssumeRoler interface {
AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error)
}
// DefaultDuration is the default amount of time in minutes that the credentials
// will be valid for.
var DefaultDuration = time.Duration(15) * time.Minute
// AssumeRoleProvider retrieves temporary credentials from the STS service, and
// keeps track of their expiration time. This provider must be used explicitly,
// as it is not included in the credentials chain.
type AssumeRoleProvider struct {
credentials.Expiry
// STS client to make assume role request with.
Client AssumeRoler
// Role to be assumed.
RoleARN string
// Session name, if you wish to reuse the credentials elsewhere.
RoleSessionName string
// Expiry duration of the STS credentials. Defaults to 15 minutes if not set.
Duration time.Duration
// Optional ExternalID to pass along, defaults to nil if not set.
ExternalID *string
// ExpiryWindow will allow the credentials to trigger refreshing prior to
// the credentials actually expiring. This is beneficial so race conditions
// with expiring credentials do not cause request to fail unexpectedly
// due to ExpiredTokenException exceptions.
//
// So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
// 10 seconds before the credentials are actually expired.
//
// If ExpiryWindow is 0 or less it will be ignored.
ExpiryWindow time.Duration
}
// NewCredentials returns a pointer to a new Credentials object wrapping the
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
// role will be named after a nanosecond timestamp of this operation.
//
// Takes a Config provider to create the STS client. The ConfigProvider is
// satisfied by the session.Session type.
func NewCredentials(c client.ConfigProvider, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials {
p := &AssumeRoleProvider{
Client: sts.New(c),
RoleARN: roleARN,
Duration: DefaultDuration,
}
for _, option := range options {
option(p)
}
return credentials.NewCredentials(p)
}
// NewCredentialsWithClient returns a pointer to a new Credentials object wrapping the
// AssumeRoleProvider. The credentials will expire every 15 minutes and the
// role will be named after a nanosecond timestamp of this operation.
//
// Takes an AssumeRoler which can be satisfiede by the STS client.
func NewCredentialsWithClient(svc AssumeRoler, roleARN string, options ...func(*AssumeRoleProvider)) *credentials.Credentials {
p := &AssumeRoleProvider{
Client: svc,
RoleARN: roleARN,
Duration: DefaultDuration,
}
for _, option := range options {
option(p)
}
return credentials.NewCredentials(p)
}
// Retrieve generates a new set of temporary credentials using STS.
func (p *AssumeRoleProvider) Retrieve() (credentials.Value, error) {
// Apply defaults where parameters are not set.
if p.RoleSessionName == "" {
// Try to work out a role name that will hopefully end up unique.
p.RoleSessionName = fmt.Sprintf("%d", time.Now().UTC().UnixNano())
}
if p.Duration == 0 {
// Expire as often as AWS permits.
p.Duration = DefaultDuration
}
roleOutput, err := p.Client.AssumeRole(&sts.AssumeRoleInput{
DurationSeconds: aws.Int64(int64(p.Duration / time.Second)),
RoleArn: aws.String(p.RoleARN),
RoleSessionName: aws.String(p.RoleSessionName),
ExternalId: p.ExternalID,
})
if err != nil {
return credentials.Value{}, err
}
// We will proactively generate new credentials before they expire.
p.SetExpiration(*roleOutput.Credentials.Expiration, p.ExpiryWindow)
return credentials.Value{
AccessKeyID: *roleOutput.Credentials.AccessKeyId,
SecretAccessKey: *roleOutput.Credentials.SecretAccessKey,
SessionToken: *roleOutput.Credentials.SessionToken,
}, nil
}

View File

@@ -0,0 +1,56 @@
package stscreds
import (
"testing"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/sts"
"github.com/stretchr/testify/assert"
)
type stubSTS struct {
}
func (s *stubSTS) AssumeRole(input *sts.AssumeRoleInput) (*sts.AssumeRoleOutput, error) {
expiry := time.Now().Add(60 * time.Minute)
return &sts.AssumeRoleOutput{
Credentials: &sts.Credentials{
// Just reflect the role arn to the provider.
AccessKeyId: input.RoleArn,
SecretAccessKey: aws.String("assumedSecretAccessKey"),
SessionToken: aws.String("assumedSessionToken"),
Expiration: &expiry,
},
}, nil
}
func TestAssumeRoleProvider(t *testing.T) {
stub := &stubSTS{}
p := &AssumeRoleProvider{
Client: stub,
RoleARN: "roleARN",
}
creds, err := p.Retrieve()
assert.Nil(t, err, "Expect no error")
assert.Equal(t, "roleARN", creds.AccessKeyID, "Expect access key ID to be reflected role ARN")
assert.Equal(t, "assumedSecretAccessKey", creds.SecretAccessKey, "Expect secret access key to match")
assert.Equal(t, "assumedSessionToken", creds.SessionToken, "Expect session token to match")
}
func BenchmarkAssumeRoleProvider(b *testing.B) {
stub := &stubSTS{}
p := &AssumeRoleProvider{
Client: stub,
RoleARN: "roleARN",
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if _, err := p.Retrieve(); err != nil {
b.Fatal(err)
}
}
}

View File

@@ -0,0 +1,76 @@
// Package defaults is a collection of helpers to retrieve the SDK's default
// configuration and handlers.
package defaults
import (
"net/http"
"os"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/corehandlers"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/private/endpoints"
)
// A Defaults provides a collection of default values for SDK clients.
type Defaults struct {
Config *aws.Config
Handlers request.Handlers
}
// Get returns the SDK's default values with Config and handlers pre-configured.
func Get() Defaults {
cfg := Config()
handlers := Handlers()
cfg.Credentials = CredChain(cfg, handlers)
return Defaults{
Config: cfg,
Handlers: handlers,
}
}
// Config returns the default configuration.
func Config() *aws.Config {
return aws.NewConfig().
WithCredentials(credentials.AnonymousCredentials).
WithRegion(os.Getenv("AWS_REGION")).
WithHTTPClient(http.DefaultClient).
WithMaxRetries(aws.UseServiceDefaultRetries).
WithLogger(aws.NewDefaultLogger()).
WithLogLevel(aws.LogOff).
WithSleepDelay(time.Sleep)
}
// Handlers returns the default request handlers.
func Handlers() request.Handlers {
var handlers request.Handlers
handlers.Validate.PushBackNamed(corehandlers.ValidateEndpointHandler)
handlers.Build.PushBackNamed(corehandlers.SDKVersionUserAgentHandler)
handlers.Sign.PushBackNamed(corehandlers.BuildContentLengthHandler)
handlers.Send.PushBackNamed(corehandlers.SendHandler)
handlers.AfterRetry.PushBackNamed(corehandlers.AfterRetryHandler)
handlers.ValidateResponse.PushBackNamed(corehandlers.ValidateResponseHandler)
return handlers
}
// CredChain returns the default credential chain.
func CredChain(cfg *aws.Config, handlers request.Handlers) *credentials.Credentials {
endpoint, signingRegion := endpoints.EndpointForRegion(ec2metadata.ServiceName, *cfg.Region, true)
return credentials.NewChainCredentials(
[]credentials.Provider{
&credentials.EnvProvider{},
&credentials.SharedCredentialsProvider{Filename: "", Profile: ""},
&ec2rolecreds.EC2RoleProvider{
Client: ec2metadata.NewClient(*cfg, handlers, endpoint, signingRegion),
ExpiryWindow: 5 * time.Minute,
},
})
}

View File

@@ -0,0 +1,43 @@
package ec2metadata
import (
"path"
"github.com/aws/aws-sdk-go/aws/request"
)
// GetMetadata uses the path provided to request
func (c *EC2Metadata) GetMetadata(p string) (string, error) {
op := &request.Operation{
Name: "GetMetadata",
HTTPMethod: "GET",
HTTPPath: path.Join("/", "meta-data", p),
}
output := &metadataOutput{}
req := c.NewRequest(op, nil, output)
return output.Content, req.Send()
}
// Region returns the region the instance is running in.
func (c *EC2Metadata) Region() (string, error) {
resp, err := c.GetMetadata("placement/availability-zone")
if err != nil {
return "", err
}
// returns region without the suffix. Eg: us-west-2a becomes us-west-2
return resp[:len(resp)-1], nil
}
// Available returns if the application has access to the EC2 Metadata service.
// Can be used to determine if application is running within an EC2 Instance and
// the metadata service is available.
func (c *EC2Metadata) Available() bool {
if _, err := c.GetMetadata("instance-id"); err != nil {
return false
}
return true
}

View File

@@ -0,0 +1,101 @@
package ec2metadata_test
import (
"bytes"
"io/ioutil"
"net/http"
"net/http/httptest"
"path"
"testing"
"github.com/stretchr/testify/assert"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/aws/session"
)
func initTestServer(path string, resp string) *httptest.Server {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.RequestURI != path {
http.Error(w, "not found", http.StatusNotFound)
return
}
w.Write([]byte(resp))
}))
}
func TestEndpoint(t *testing.T) {
c := ec2metadata.New(session.New())
op := &request.Operation{
Name: "GetMetadata",
HTTPMethod: "GET",
HTTPPath: path.Join("/", "meta-data", "testpath"),
}
req := c.NewRequest(op, nil, nil)
assert.Equal(t, "http://169.254.169.254/latest", req.ClientInfo.Endpoint)
assert.Equal(t, "http://169.254.169.254/latest/meta-data/testpath", req.HTTPRequest.URL.String())
}
func TestGetMetadata(t *testing.T) {
server := initTestServer(
"/latest/meta-data/some/path",
"success", // real response includes suffix
)
defer server.Close()
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
resp, err := c.GetMetadata("some/path")
assert.NoError(t, err)
assert.Equal(t, "success", resp)
}
func TestGetRegion(t *testing.T) {
server := initTestServer(
"/latest/meta-data/placement/availability-zone",
"us-west-2a", // real response includes suffix
)
defer server.Close()
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
region, err := c.Region()
assert.NoError(t, err)
assert.Equal(t, "us-west-2", region)
}
func TestMetadataAvailable(t *testing.T) {
server := initTestServer(
"/latest/meta-data/instance-id",
"instance-id",
)
defer server.Close()
c := ec2metadata.New(session.New(), &aws.Config{Endpoint: aws.String(server.URL + "/latest")})
available := c.Available()
assert.True(t, available)
}
func TestMetadataNotAvailable(t *testing.T) {
c := ec2metadata.New(session.New())
c.Handlers.Send.Clear()
c.Handlers.Send.PushBack(func(r *request.Request) {
r.HTTPResponse = &http.Response{
StatusCode: int(0),
Status: http.StatusText(int(0)),
Body: ioutil.NopCloser(bytes.NewReader([]byte{})),
}
r.Error = awserr.New("RequestError", "send request failed", nil)
r.Retryable = aws.Bool(true) // network errors are retryable
})
available := c.Available()
assert.False(t, available)
}

View File

@@ -0,0 +1,116 @@
// Package ec2metadata provides the client for making API calls to the
// EC2 Metadata service.
package ec2metadata
import (
"io/ioutil"
"net"
"net/http"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/client/metadata"
"github.com/aws/aws-sdk-go/aws/request"
)
// ServiceName is the name of the service.
const ServiceName = "ec2metadata"
// A EC2Metadata is an EC2 Metadata service Client.
type EC2Metadata struct {
*client.Client
}
// New creates a new instance of the EC2Metadata client with a session.
// This client is safe to use across multiple goroutines.
//
// Example:
// // Create a EC2Metadata client from just a session.
// svc := ec2metadata.New(mySession)
//
// // Create a EC2Metadata client with additional configuration
// svc := ec2metadata.New(mySession, aws.NewConfig().WithLogLevel(aws.LogDebugHTTPBody))
func New(p client.ConfigProvider, cfgs ...*aws.Config) *EC2Metadata {
c := p.ClientConfig(ServiceName, cfgs...)
return NewClient(*c.Config, c.Handlers, c.Endpoint, c.SigningRegion)
}
// NewClient returns a new EC2Metadata client. Should be used to create
// a client when not using a session. Generally using just New with a session
// is preferred.
func NewClient(cfg aws.Config, handlers request.Handlers, endpoint, signingRegion string, opts ...func(*client.Client)) *EC2Metadata {
// If the default http client is provided, replace it with a custom
// client using default timeouts.
if cfg.HTTPClient == http.DefaultClient {
cfg.HTTPClient = &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
Dial: (&net.Dialer{
// use a shorter timeout than default because the metadata
// service is local if it is running, and to fail faster
// if not running on an ec2 instance.
Timeout: 5 * time.Second,
KeepAlive: 30 * time.Second,
}).Dial,
TLSHandshakeTimeout: 10 * time.Second,
},
}
}
svc := &EC2Metadata{
Client: client.New(
cfg,
metadata.ClientInfo{
ServiceName: ServiceName,
Endpoint: endpoint,
APIVersion: "latest",
},
handlers,
),
}
svc.Handlers.Unmarshal.PushBack(unmarshalHandler)
svc.Handlers.UnmarshalError.PushBack(unmarshalError)
svc.Handlers.Validate.Clear()
svc.Handlers.Validate.PushBack(validateEndpointHandler)
// Add additional options to the service config
for _, option := range opts {
option(svc.Client)
}
return svc
}
type metadataOutput struct {
Content string
}
func unmarshalHandler(r *request.Request) {
defer r.HTTPResponse.Body.Close()
b, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata respose", err)
}
data := r.Data.(*metadataOutput)
data.Content = string(b)
}
func unmarshalError(r *request.Request) {
defer r.HTTPResponse.Body.Close()
_, err := ioutil.ReadAll(r.HTTPResponse.Body)
if err != nil {
r.Error = awserr.New("SerializationError", "unable to unmarshal EC2 metadata error respose", err)
}
// TODO extract the error...
}
func validateEndpointHandler(r *request.Request) {
if r.ClientInfo.Endpoint == "" {
r.Error = aws.ErrMissingEndpoint
}
}

View File

@@ -0,0 +1,17 @@
package aws
import "github.com/aws/aws-sdk-go/aws/awserr"
var (
// ErrMissingRegion is an error that is returned if region configuration is
// not found.
//
// @readonly
ErrMissingRegion = awserr.New("MissingRegion", "could not find region configuration", nil)
// ErrMissingEndpoint is an error that is returned if an endpoint cannot be
// resolved for a service.
//
// @readonly
ErrMissingEndpoint = awserr.New("MissingEndpoint", "'Endpoint' configuration is required for this service", nil)
)

View File

@@ -0,0 +1,98 @@
package aws
import (
"log"
"os"
)
// A LogLevelType defines the level logging should be performed at. Used to instruct
// the SDK which statements should be logged.
type LogLevelType uint
// LogLevel returns the pointer to a LogLevel. Should be used to workaround
// not being able to take the address of a non-composite literal.
func LogLevel(l LogLevelType) *LogLevelType {
return &l
}
// Value returns the LogLevel value or the default value LogOff if the LogLevel
// is nil. Safe to use on nil value LogLevelTypes.
func (l *LogLevelType) Value() LogLevelType {
if l != nil {
return *l
}
return LogOff
}
// Matches returns true if the v LogLevel is enabled by this LogLevel. Should be
// used with logging sub levels. Is safe to use on nil value LogLevelTypes. If
// LogLevel is nill, will default to LogOff comparison.
func (l *LogLevelType) Matches(v LogLevelType) bool {
c := l.Value()
return c&v == v
}
// AtLeast returns true if this LogLevel is at least high enough to satisfies v.
// Is safe to use on nil value LogLevelTypes. If LogLevel is nill, will default
// to LogOff comparison.
func (l *LogLevelType) AtLeast(v LogLevelType) bool {
c := l.Value()
return c >= v
}
const (
// LogOff states that no logging should be performed by the SDK. This is the
// default state of the SDK, and should be use to disable all logging.
LogOff LogLevelType = iota * 0x1000
// LogDebug state that debug output should be logged by the SDK. This should
// be used to inspect request made and responses received.
LogDebug
)
// Debug Logging Sub Levels
const (
// LogDebugWithSigning states that the SDK should log request signing and
// presigning events. This should be used to log the signing details of
// requests for debugging. Will also enable LogDebug.
LogDebugWithSigning LogLevelType = LogDebug | (1 << iota)
// LogDebugWithHTTPBody states the SDK should log HTTP request and response
// HTTP bodys in addition to the headers and path. This should be used to
// see the body content of requests and responses made while using the SDK
// Will also enable LogDebug.
LogDebugWithHTTPBody
// LogDebugWithRequestRetries states the SDK should log when service requests will
// be retried. This should be used to log when you want to log when service
// requests are being retried. Will also enable LogDebug.
LogDebugWithRequestRetries
// LogDebugWithRequestErrors states the SDK should log when service requests fail
// to build, send, validate, or unmarshal.
LogDebugWithRequestErrors
)
// A Logger is a minimalistic interface for the SDK to log messages to. Should
// be used to provide custom logging writers for the SDK to use.
type Logger interface {
Log(...interface{})
}
// NewDefaultLogger returns a Logger which will write log messages to stdout, and
// use same formatting runes as the stdlib log.Logger
func NewDefaultLogger() Logger {
return &defaultLogger{
logger: log.New(os.Stdout, "", log.LstdFlags),
}
}
// A defaultLogger provides a minimalistic logger satisfying the Logger interface.
type defaultLogger struct {
logger *log.Logger
}
// Log logs the parameters to the stdlib logger. See log.Println.
func (l defaultLogger) Log(args ...interface{}) {
l.logger.Println(args...)
}

View File

@@ -0,0 +1,140 @@
package request
import (
"fmt"
"strings"
)
// A Handlers provides a collection of request handlers for various
// stages of handling requests.
type Handlers struct {
Validate HandlerList
Build HandlerList
Sign HandlerList
Send HandlerList
ValidateResponse HandlerList
Unmarshal HandlerList
UnmarshalMeta HandlerList
UnmarshalError HandlerList
Retry HandlerList
AfterRetry HandlerList
}
// Copy returns of this handler's lists.
func (h *Handlers) Copy() Handlers {
return Handlers{
Validate: h.Validate.copy(),
Build: h.Build.copy(),
Sign: h.Sign.copy(),
Send: h.Send.copy(),
ValidateResponse: h.ValidateResponse.copy(),
Unmarshal: h.Unmarshal.copy(),
UnmarshalError: h.UnmarshalError.copy(),
UnmarshalMeta: h.UnmarshalMeta.copy(),
Retry: h.Retry.copy(),
AfterRetry: h.AfterRetry.copy(),
}
}
// Clear removes callback functions for all handlers
func (h *Handlers) Clear() {
h.Validate.Clear()
h.Build.Clear()
h.Send.Clear()
h.Sign.Clear()
h.Unmarshal.Clear()
h.UnmarshalMeta.Clear()
h.UnmarshalError.Clear()
h.ValidateResponse.Clear()
h.Retry.Clear()
h.AfterRetry.Clear()
}
// A HandlerList manages zero or more handlers in a list.
type HandlerList struct {
list []NamedHandler
}
// A NamedHandler is a struct that contains a name and function callback.
type NamedHandler struct {
Name string
Fn func(*Request)
}
// copy creates a copy of the handler list.
func (l *HandlerList) copy() HandlerList {
var n HandlerList
n.list = append([]NamedHandler{}, l.list...)
return n
}
// Clear clears the handler list.
func (l *HandlerList) Clear() {
l.list = []NamedHandler{}
}
// Len returns the number of handlers in the list.
func (l *HandlerList) Len() int {
return len(l.list)
}
// PushBack pushes handler f to the back of the handler list.
func (l *HandlerList) PushBack(f func(*Request)) {
l.list = append(l.list, NamedHandler{"__anonymous", f})
}
// PushFront pushes handler f to the front of the handler list.
func (l *HandlerList) PushFront(f func(*Request)) {
l.list = append([]NamedHandler{{"__anonymous", f}}, l.list...)
}
// PushBackNamed pushes named handler f to the back of the handler list.
func (l *HandlerList) PushBackNamed(n NamedHandler) {
l.list = append(l.list, n)
}
// PushFrontNamed pushes named handler f to the front of the handler list.
func (l *HandlerList) PushFrontNamed(n NamedHandler) {
l.list = append([]NamedHandler{n}, l.list...)
}
// Remove removes a NamedHandler n
func (l *HandlerList) Remove(n NamedHandler) {
newlist := []NamedHandler{}
for _, m := range l.list {
if m.Name != n.Name {
newlist = append(newlist, m)
}
}
l.list = newlist
}
// Run executes all handlers in the list with a given request object.
func (l *HandlerList) Run(r *Request) {
for _, f := range l.list {
f.Fn(r)
}
}
// MakeAddToUserAgentHandler will add the name/version pair to the User-Agent request
// header. If the extra parameters are provided they will be added as metadata to the
// name/version pair resulting in the following format.
// "name/version (extra0; extra1; ...)"
// The user agent part will be concatenated with this current request's user agent string.
func MakeAddToUserAgentHandler(name, version string, extra ...string) func(*Request) {
ua := fmt.Sprintf("%s/%s", name, version)
if len(extra) > 0 {
ua += fmt.Sprintf(" (%s)", strings.Join(extra, "; "))
}
return func(r *Request) {
AddToUserAgent(r, ua)
}
}
// MakeAddToUserAgentFreeFormHandler adds the input to the User-Agent request header.
// The input string will be concatenated with the current request's user agent string.
func MakeAddToUserAgentFreeFormHandler(s string) func(*Request) {
return func(r *Request) {
AddToUserAgent(r, s)
}
}

View File

@@ -0,0 +1,47 @@
package request_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/request"
)
func TestHandlerList(t *testing.T) {
s := ""
r := &request.Request{}
l := request.HandlerList{}
l.PushBack(func(r *request.Request) {
s += "a"
r.Data = s
})
l.Run(r)
assert.Equal(t, "a", s)
assert.Equal(t, "a", r.Data)
}
func TestMultipleHandlers(t *testing.T) {
r := &request.Request{}
l := request.HandlerList{}
l.PushBack(func(r *request.Request) { r.Data = nil })
l.PushFront(func(r *request.Request) { r.Data = aws.Bool(true) })
l.Run(r)
if r.Data != nil {
t.Error("Expected handler to execute")
}
}
func TestNamedHandlers(t *testing.T) {
l := request.HandlerList{}
named := request.NamedHandler{Name: "Name", Fn: func(r *request.Request) {}}
named2 := request.NamedHandler{Name: "NotName", Fn: func(r *request.Request) {}}
l.PushBackNamed(named)
l.PushBackNamed(named)
l.PushBackNamed(named2)
l.PushBack(func(r *request.Request) {})
assert.Equal(t, 4, l.Len())
l.Remove(named)
assert.Equal(t, 2, l.Len())
}

View File

@@ -0,0 +1,279 @@
package request
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"reflect"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/client/metadata"
)
// A Request is the service request to be made.
type Request struct {
Config aws.Config
ClientInfo metadata.ClientInfo
Handlers Handlers
Retryer
Time time.Time
ExpireTime time.Duration
Operation *Operation
HTTPRequest *http.Request
HTTPResponse *http.Response
Body io.ReadSeeker
BodyStart int64 // offset from beginning of Body that the request body starts
Params interface{}
Error error
Data interface{}
RequestID string
RetryCount int
Retryable *bool
RetryDelay time.Duration
built bool
}
// An Operation is the service API operation to be made.
type Operation struct {
Name string
HTTPMethod string
HTTPPath string
*Paginator
}
// Paginator keeps track of pagination configuration for an API operation.
type Paginator struct {
InputTokens []string
OutputTokens []string
LimitToken string
TruncationToken string
}
// New returns a new Request pointer for the service API
// operation and parameters.
//
// Params is any value of input parameters to be the request payload.
// Data is pointer value to an object which the request's response
// payload will be deserialized to.
func New(cfg aws.Config, clientInfo metadata.ClientInfo, handlers Handlers,
retryer Retryer, operation *Operation, params interface{}, data interface{}) *Request {
method := operation.HTTPMethod
if method == "" {
method = "POST"
}
p := operation.HTTPPath
if p == "" {
p = "/"
}
httpReq, _ := http.NewRequest(method, "", nil)
httpReq.URL, _ = url.Parse(clientInfo.Endpoint + p)
r := &Request{
Config: cfg,
ClientInfo: clientInfo,
Handlers: handlers.Copy(),
Retryer: retryer,
Time: time.Now(),
ExpireTime: 0,
Operation: operation,
HTTPRequest: httpReq,
Body: nil,
Params: params,
Error: nil,
Data: data,
}
r.SetBufferBody([]byte{})
return r
}
// WillRetry returns if the request's can be retried.
func (r *Request) WillRetry() bool {
return r.Error != nil && aws.BoolValue(r.Retryable) && r.RetryCount < r.MaxRetries()
}
// ParamsFilled returns if the request's parameters have been populated
// and the parameters are valid. False is returned if no parameters are
// provided or invalid.
func (r *Request) ParamsFilled() bool {
return r.Params != nil && reflect.ValueOf(r.Params).Elem().IsValid()
}
// DataFilled returns true if the request's data for response deserialization
// target has been set and is a valid. False is returned if data is not
// set, or is invalid.
func (r *Request) DataFilled() bool {
return r.Data != nil && reflect.ValueOf(r.Data).Elem().IsValid()
}
// SetBufferBody will set the request's body bytes that will be sent to
// the service API.
func (r *Request) SetBufferBody(buf []byte) {
r.SetReaderBody(bytes.NewReader(buf))
}
// SetStringBody sets the body of the request to be backed by a string.
func (r *Request) SetStringBody(s string) {
r.SetReaderBody(strings.NewReader(s))
}
// SetReaderBody will set the request's body reader.
func (r *Request) SetReaderBody(reader io.ReadSeeker) {
r.HTTPRequest.Body = ioutil.NopCloser(reader)
r.Body = reader
}
// Presign returns the request's signed URL. Error will be returned
// if the signing fails.
func (r *Request) Presign(expireTime time.Duration) (string, error) {
r.ExpireTime = expireTime
r.Sign()
if r.Error != nil {
return "", r.Error
}
return r.HTTPRequest.URL.String(), nil
}
func debugLogReqError(r *Request, stage string, retrying bool, err error) {
if !r.Config.LogLevel.Matches(aws.LogDebugWithRequestErrors) {
return
}
retryStr := "not retrying"
if retrying {
retryStr = "will retry"
}
r.Config.Logger.Log(fmt.Sprintf("DEBUG: %s %s/%s failed, %s, error %v",
stage, r.ClientInfo.ServiceName, r.Operation.Name, retryStr, err))
}
// Build will build the request's object so it can be signed and sent
// to the service. Build will also validate all the request's parameters.
// Anny additional build Handlers set on this request will be run
// in the order they were set.
//
// The request will only be built once. Multiple calls to build will have
// no effect.
//
// If any Validate or Build errors occur the build will stop and the error
// which occurred will be returned.
func (r *Request) Build() error {
if !r.built {
r.Error = nil
r.Handlers.Validate.Run(r)
if r.Error != nil {
debugLogReqError(r, "Validate Request", false, r.Error)
return r.Error
}
r.Handlers.Build.Run(r)
r.built = true
}
return r.Error
}
// Sign will sign the request retuning error if errors are encountered.
//
// Send will build the request prior to signing. All Sign Handlers will
// be executed in the order they were set.
func (r *Request) Sign() error {
r.Build()
if r.Error != nil {
debugLogReqError(r, "Build Request", false, r.Error)
return r.Error
}
r.Handlers.Sign.Run(r)
return r.Error
}
// Send will send the request returning error if errors are encountered.
//
// Send will sign the request prior to sending. All Send Handlers will
// be executed in the order they were set.
func (r *Request) Send() error {
for {
r.Sign()
if r.Error != nil {
return r.Error
}
if aws.BoolValue(r.Retryable) {
if r.Config.LogLevel.Matches(aws.LogDebugWithRequestRetries) {
r.Config.Logger.Log(fmt.Sprintf("DEBUG: Retrying Request %s/%s, attempt %d",
r.ClientInfo.ServiceName, r.Operation.Name, r.RetryCount))
}
// Re-seek the body back to the original point in for a retry so that
// send will send the body's contents again in the upcoming request.
r.Body.Seek(r.BodyStart, 0)
r.HTTPRequest.Body = ioutil.NopCloser(r.Body)
}
r.Retryable = nil
r.Handlers.Send.Run(r)
if r.Error != nil {
err := r.Error
r.Handlers.Retry.Run(r)
r.Handlers.AfterRetry.Run(r)
if r.Error != nil {
debugLogReqError(r, "Send Request", false, r.Error)
return r.Error
}
debugLogReqError(r, "Send Request", true, err)
continue
}
r.Handlers.UnmarshalMeta.Run(r)
r.Handlers.ValidateResponse.Run(r)
if r.Error != nil {
err := r.Error
r.Handlers.UnmarshalError.Run(r)
r.Handlers.Retry.Run(r)
r.Handlers.AfterRetry.Run(r)
if r.Error != nil {
debugLogReqError(r, "Validate Response", false, r.Error)
return r.Error
}
debugLogReqError(r, "Validate Response", true, err)
continue
}
r.Handlers.Unmarshal.Run(r)
if r.Error != nil {
err := r.Error
r.Handlers.Retry.Run(r)
r.Handlers.AfterRetry.Run(r)
if r.Error != nil {
debugLogReqError(r, "Unmarshal Response", false, r.Error)
return r.Error
}
debugLogReqError(r, "Unmarshal Response", true, err)
continue
}
break
}
return nil
}
// AddToUserAgent adds the string to the end of the request's current user agent.
func AddToUserAgent(r *Request, s string) {
curUA := r.HTTPRequest.Header.Get("User-Agent")
if len(curUA) > 0 {
s = curUA + " " + s
}
r.HTTPRequest.Header.Set("User-Agent", s)
}

View File

@@ -0,0 +1,104 @@
package request
import (
"reflect"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awsutil"
)
//type Paginater interface {
// HasNextPage() bool
// NextPage() *Request
// EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error
//}
// HasNextPage returns true if this request has more pages of data available.
func (r *Request) HasNextPage() bool {
return len(r.nextPageTokens()) > 0
}
// nextPageTokens returns the tokens to use when asking for the next page of
// data.
func (r *Request) nextPageTokens() []interface{} {
if r.Operation.Paginator == nil {
return nil
}
if r.Operation.TruncationToken != "" {
tr, _ := awsutil.ValuesAtPath(r.Data, r.Operation.TruncationToken)
if len(tr) == 0 {
return nil
}
switch v := tr[0].(type) {
case *bool:
if !aws.BoolValue(v) {
return nil
}
case bool:
if v == false {
return nil
}
}
}
tokens := []interface{}{}
tokenAdded := false
for _, outToken := range r.Operation.OutputTokens {
v, _ := awsutil.ValuesAtPath(r.Data, outToken)
if len(v) > 0 {
tokens = append(tokens, v[0])
tokenAdded = true
} else {
tokens = append(tokens, nil)
}
}
if !tokenAdded {
return nil
}
return tokens
}
// NextPage returns a new Request that can be executed to return the next
// page of result data. Call .Send() on this request to execute it.
func (r *Request) NextPage() *Request {
tokens := r.nextPageTokens()
if len(tokens) == 0 {
return nil
}
data := reflect.New(reflect.TypeOf(r.Data).Elem()).Interface()
nr := New(r.Config, r.ClientInfo, r.Handlers, r.Retryer, r.Operation, awsutil.CopyOf(r.Params), data)
for i, intok := range nr.Operation.InputTokens {
awsutil.SetValueAtPath(nr.Params, intok, tokens[i])
}
return nr
}
// EachPage iterates over each page of a paginated request object. The fn
// parameter should be a function with the following sample signature:
//
// func(page *T, lastPage bool) bool {
// return true // return false to stop iterating
// }
//
// Where "T" is the structure type matching the output structure of the given
// operation. For example, a request object generated by
// DynamoDB.ListTablesRequest() would expect to see dynamodb.ListTablesOutput
// as the structure "T". The lastPage value represents whether the page is
// the last page of data or not. The return value of this function should
// return true to keep iterating or false to stop.
func (r *Request) EachPage(fn func(data interface{}, isLastPage bool) (shouldContinue bool)) error {
for page := r; page != nil; page = page.NextPage() {
if err := page.Send(); err != nil {
return err
}
if getNextPage := fn(page.Data, !page.HasNextPage()); !getNextPage {
return page.Error
}
}
return nil
}

View File

@@ -0,0 +1,455 @@
package request_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/awstesting/unit"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/route53"
"github.com/aws/aws-sdk-go/service/s3"
)
// Use DynamoDB methods for simplicity
func TestPaginationQueryPage(t *testing.T) {
db := dynamodb.New(unit.Session)
tokens, pages, numPages, gotToEnd := []map[string]*dynamodb.AttributeValue{}, []map[string]*dynamodb.AttributeValue{}, 0, false
reqNum := 0
resps := []*dynamodb.QueryOutput{
{
LastEvaluatedKey: map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key1")}},
Count: aws.Int64(1),
Items: []map[string]*dynamodb.AttributeValue{
map[string]*dynamodb.AttributeValue{
"key": {S: aws.String("key1")},
},
},
},
{
LastEvaluatedKey: map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key2")}},
Count: aws.Int64(1),
Items: []map[string]*dynamodb.AttributeValue{
map[string]*dynamodb.AttributeValue{
"key": {S: aws.String("key2")},
},
},
},
{
LastEvaluatedKey: map[string]*dynamodb.AttributeValue{},
Count: aws.Int64(1),
Items: []map[string]*dynamodb.AttributeValue{
map[string]*dynamodb.AttributeValue{
"key": {S: aws.String("key3")},
},
},
},
}
db.Handlers.Send.Clear() // mock sending
db.Handlers.Unmarshal.Clear()
db.Handlers.UnmarshalMeta.Clear()
db.Handlers.ValidateResponse.Clear()
db.Handlers.Build.PushBack(func(r *request.Request) {
in := r.Params.(*dynamodb.QueryInput)
if in == nil {
tokens = append(tokens, nil)
} else if len(in.ExclusiveStartKey) != 0 {
tokens = append(tokens, in.ExclusiveStartKey)
}
})
db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
r.Data = resps[reqNum]
reqNum++
})
params := &dynamodb.QueryInput{
Limit: aws.Int64(2),
TableName: aws.String("tablename"),
}
err := db.QueryPages(params, func(p *dynamodb.QueryOutput, last bool) bool {
numPages++
for _, item := range p.Items {
pages = append(pages, item)
}
if last {
if gotToEnd {
assert.Fail(t, "last=true happened twice")
}
gotToEnd = true
}
return true
})
assert.Nil(t, err)
assert.Equal(t,
[]map[string]*dynamodb.AttributeValue{
map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key1")}},
map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key2")}},
}, tokens)
assert.Equal(t,
[]map[string]*dynamodb.AttributeValue{
map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key1")}},
map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key2")}},
map[string]*dynamodb.AttributeValue{"key": {S: aws.String("key3")}},
}, pages)
assert.Equal(t, 3, numPages)
assert.True(t, gotToEnd)
assert.Nil(t, params.ExclusiveStartKey)
}
// Use DynamoDB methods for simplicity
func TestPagination(t *testing.T) {
db := dynamodb.New(unit.Session)
tokens, pages, numPages, gotToEnd := []string{}, []string{}, 0, false
reqNum := 0
resps := []*dynamodb.ListTablesOutput{
{TableNames: []*string{aws.String("Table1"), aws.String("Table2")}, LastEvaluatedTableName: aws.String("Table2")},
{TableNames: []*string{aws.String("Table3"), aws.String("Table4")}, LastEvaluatedTableName: aws.String("Table4")},
{TableNames: []*string{aws.String("Table5")}},
}
db.Handlers.Send.Clear() // mock sending
db.Handlers.Unmarshal.Clear()
db.Handlers.UnmarshalMeta.Clear()
db.Handlers.ValidateResponse.Clear()
db.Handlers.Build.PushBack(func(r *request.Request) {
in := r.Params.(*dynamodb.ListTablesInput)
if in == nil {
tokens = append(tokens, "")
} else if in.ExclusiveStartTableName != nil {
tokens = append(tokens, *in.ExclusiveStartTableName)
}
})
db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
r.Data = resps[reqNum]
reqNum++
})
params := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
err := db.ListTablesPages(params, func(p *dynamodb.ListTablesOutput, last bool) bool {
numPages++
for _, t := range p.TableNames {
pages = append(pages, *t)
}
if last {
if gotToEnd {
assert.Fail(t, "last=true happened twice")
}
gotToEnd = true
}
return true
})
assert.Equal(t, []string{"Table2", "Table4"}, tokens)
assert.Equal(t, []string{"Table1", "Table2", "Table3", "Table4", "Table5"}, pages)
assert.Equal(t, 3, numPages)
assert.True(t, gotToEnd)
assert.Nil(t, err)
assert.Nil(t, params.ExclusiveStartTableName)
}
// Use DynamoDB methods for simplicity
func TestPaginationEachPage(t *testing.T) {
db := dynamodb.New(unit.Session)
tokens, pages, numPages, gotToEnd := []string{}, []string{}, 0, false
reqNum := 0
resps := []*dynamodb.ListTablesOutput{
{TableNames: []*string{aws.String("Table1"), aws.String("Table2")}, LastEvaluatedTableName: aws.String("Table2")},
{TableNames: []*string{aws.String("Table3"), aws.String("Table4")}, LastEvaluatedTableName: aws.String("Table4")},
{TableNames: []*string{aws.String("Table5")}},
}
db.Handlers.Send.Clear() // mock sending
db.Handlers.Unmarshal.Clear()
db.Handlers.UnmarshalMeta.Clear()
db.Handlers.ValidateResponse.Clear()
db.Handlers.Build.PushBack(func(r *request.Request) {
in := r.Params.(*dynamodb.ListTablesInput)
if in == nil {
tokens = append(tokens, "")
} else if in.ExclusiveStartTableName != nil {
tokens = append(tokens, *in.ExclusiveStartTableName)
}
})
db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
r.Data = resps[reqNum]
reqNum++
})
params := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
req, _ := db.ListTablesRequest(params)
err := req.EachPage(func(p interface{}, last bool) bool {
numPages++
for _, t := range p.(*dynamodb.ListTablesOutput).TableNames {
pages = append(pages, *t)
}
if last {
if gotToEnd {
assert.Fail(t, "last=true happened twice")
}
gotToEnd = true
}
return true
})
assert.Equal(t, []string{"Table2", "Table4"}, tokens)
assert.Equal(t, []string{"Table1", "Table2", "Table3", "Table4", "Table5"}, pages)
assert.Equal(t, 3, numPages)
assert.True(t, gotToEnd)
assert.Nil(t, err)
}
// Use DynamoDB methods for simplicity
func TestPaginationEarlyExit(t *testing.T) {
db := dynamodb.New(unit.Session)
numPages, gotToEnd := 0, false
reqNum := 0
resps := []*dynamodb.ListTablesOutput{
{TableNames: []*string{aws.String("Table1"), aws.String("Table2")}, LastEvaluatedTableName: aws.String("Table2")},
{TableNames: []*string{aws.String("Table3"), aws.String("Table4")}, LastEvaluatedTableName: aws.String("Table4")},
{TableNames: []*string{aws.String("Table5")}},
}
db.Handlers.Send.Clear() // mock sending
db.Handlers.Unmarshal.Clear()
db.Handlers.UnmarshalMeta.Clear()
db.Handlers.ValidateResponse.Clear()
db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
r.Data = resps[reqNum]
reqNum++
})
params := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
err := db.ListTablesPages(params, func(p *dynamodb.ListTablesOutput, last bool) bool {
numPages++
if numPages == 2 {
return false
}
if last {
if gotToEnd {
assert.Fail(t, "last=true happened twice")
}
gotToEnd = true
}
return true
})
assert.Equal(t, 2, numPages)
assert.False(t, gotToEnd)
assert.Nil(t, err)
}
func TestSkipPagination(t *testing.T) {
client := s3.New(unit.Session)
client.Handlers.Send.Clear() // mock sending
client.Handlers.Unmarshal.Clear()
client.Handlers.UnmarshalMeta.Clear()
client.Handlers.ValidateResponse.Clear()
client.Handlers.Unmarshal.PushBack(func(r *request.Request) {
r.Data = &s3.HeadBucketOutput{}
})
req, _ := client.HeadBucketRequest(&s3.HeadBucketInput{Bucket: aws.String("bucket")})
numPages, gotToEnd := 0, false
req.EachPage(func(p interface{}, last bool) bool {
numPages++
if last {
gotToEnd = true
}
return true
})
assert.Equal(t, 1, numPages)
assert.True(t, gotToEnd)
}
// Use S3 for simplicity
func TestPaginationTruncation(t *testing.T) {
client := s3.New(unit.Session)
reqNum := 0
resps := []*s3.ListObjectsOutput{
{IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key1")}}},
{IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key2")}}},
{IsTruncated: aws.Bool(false), Contents: []*s3.Object{{Key: aws.String("Key3")}}},
{IsTruncated: aws.Bool(true), Contents: []*s3.Object{{Key: aws.String("Key4")}}},
}
client.Handlers.Send.Clear() // mock sending
client.Handlers.Unmarshal.Clear()
client.Handlers.UnmarshalMeta.Clear()
client.Handlers.ValidateResponse.Clear()
client.Handlers.Unmarshal.PushBack(func(r *request.Request) {
r.Data = resps[reqNum]
reqNum++
})
params := &s3.ListObjectsInput{Bucket: aws.String("bucket")}
results := []string{}
err := client.ListObjectsPages(params, func(p *s3.ListObjectsOutput, last bool) bool {
results = append(results, *p.Contents[0].Key)
return true
})
assert.Equal(t, []string{"Key1", "Key2", "Key3"}, results)
assert.Nil(t, err)
// Try again without truncation token at all
reqNum = 0
resps[1].IsTruncated = nil
resps[2].IsTruncated = aws.Bool(true)
results = []string{}
err = client.ListObjectsPages(params, func(p *s3.ListObjectsOutput, last bool) bool {
results = append(results, *p.Contents[0].Key)
return true
})
assert.Equal(t, []string{"Key1", "Key2"}, results)
assert.Nil(t, err)
}
func TestPaginationNilToken(t *testing.T) {
client := route53.New(unit.Session)
reqNum := 0
resps := []*route53.ListResourceRecordSetsOutput{
{
ResourceRecordSets: []*route53.ResourceRecordSet{
{Name: aws.String("first.example.com.")},
},
IsTruncated: aws.Bool(true),
NextRecordName: aws.String("second.example.com."),
NextRecordType: aws.String("MX"),
NextRecordIdentifier: aws.String("second"),
MaxItems: aws.String("1"),
},
{
ResourceRecordSets: []*route53.ResourceRecordSet{
{Name: aws.String("second.example.com.")},
},
IsTruncated: aws.Bool(true),
NextRecordName: aws.String("third.example.com."),
NextRecordType: aws.String("MX"),
MaxItems: aws.String("1"),
},
{
ResourceRecordSets: []*route53.ResourceRecordSet{
{Name: aws.String("third.example.com.")},
},
IsTruncated: aws.Bool(false),
MaxItems: aws.String("1"),
},
}
client.Handlers.Send.Clear() // mock sending
client.Handlers.Unmarshal.Clear()
client.Handlers.UnmarshalMeta.Clear()
client.Handlers.ValidateResponse.Clear()
idents := []string{}
client.Handlers.Build.PushBack(func(r *request.Request) {
p := r.Params.(*route53.ListResourceRecordSetsInput)
idents = append(idents, aws.StringValue(p.StartRecordIdentifier))
})
client.Handlers.Unmarshal.PushBack(func(r *request.Request) {
r.Data = resps[reqNum]
reqNum++
})
params := &route53.ListResourceRecordSetsInput{
HostedZoneId: aws.String("id-zone"),
}
results := []string{}
err := client.ListResourceRecordSetsPages(params, func(p *route53.ListResourceRecordSetsOutput, last bool) bool {
results = append(results, *p.ResourceRecordSets[0].Name)
return true
})
assert.NoError(t, err)
assert.Equal(t, []string{"", "second", ""}, idents)
assert.Equal(t, []string{"first.example.com.", "second.example.com.", "third.example.com."}, results)
}
// Benchmarks
var benchResps = []*dynamodb.ListTablesOutput{
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
{TableNames: []*string{aws.String("TABLE"), aws.String("NXT")}, LastEvaluatedTableName: aws.String("NXT")},
{TableNames: []*string{aws.String("TABLE")}},
}
var benchDb = func() *dynamodb.DynamoDB {
db := dynamodb.New(unit.Session)
db.Handlers.Send.Clear() // mock sending
db.Handlers.Unmarshal.Clear()
db.Handlers.UnmarshalMeta.Clear()
db.Handlers.ValidateResponse.Clear()
return db
}
func BenchmarkCodegenIterator(b *testing.B) {
reqNum := 0
db := benchDb()
db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
r.Data = benchResps[reqNum]
reqNum++
})
input := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
iter := func(fn func(*dynamodb.ListTablesOutput, bool) bool) error {
page, _ := db.ListTablesRequest(input)
for ; page != nil; page = page.NextPage() {
page.Send()
out := page.Data.(*dynamodb.ListTablesOutput)
if result := fn(out, !page.HasNextPage()); page.Error != nil || !result {
return page.Error
}
}
return nil
}
for i := 0; i < b.N; i++ {
reqNum = 0
iter(func(p *dynamodb.ListTablesOutput, last bool) bool {
return true
})
}
}
func BenchmarkEachPageIterator(b *testing.B) {
reqNum := 0
db := benchDb()
db.Handlers.Unmarshal.PushBack(func(r *request.Request) {
r.Data = benchResps[reqNum]
reqNum++
})
input := &dynamodb.ListTablesInput{Limit: aws.Int64(2)}
for i := 0; i < b.N; i++ {
reqNum = 0
req, _ := db.ListTablesRequest(input)
req.EachPage(func(p interface{}, last bool) bool {
return true
})
}
}

View File

@@ -0,0 +1,261 @@
package request_test
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"runtime"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/awstesting"
)
type testData struct {
Data string
}
func body(str string) io.ReadCloser {
return ioutil.NopCloser(bytes.NewReader([]byte(str)))
}
func unmarshal(req *request.Request) {
defer req.HTTPResponse.Body.Close()
if req.Data != nil {
json.NewDecoder(req.HTTPResponse.Body).Decode(req.Data)
}
return
}
func unmarshalError(req *request.Request) {
bodyBytes, err := ioutil.ReadAll(req.HTTPResponse.Body)
if err != nil {
req.Error = awserr.New("UnmarshaleError", req.HTTPResponse.Status, err)
return
}
if len(bodyBytes) == 0 {
req.Error = awserr.NewRequestFailure(
awserr.New("UnmarshaleError", req.HTTPResponse.Status, fmt.Errorf("empty body")),
req.HTTPResponse.StatusCode,
"",
)
return
}
var jsonErr jsonErrorResponse
if err := json.Unmarshal(bodyBytes, &jsonErr); err != nil {
req.Error = awserr.New("UnmarshaleError", "JSON unmarshal", err)
return
}
req.Error = awserr.NewRequestFailure(
awserr.New(jsonErr.Code, jsonErr.Message, nil),
req.HTTPResponse.StatusCode,
"",
)
}
type jsonErrorResponse struct {
Code string `json:"__type"`
Message string `json:"message"`
}
// test that retries occur for 5xx status codes
func TestRequestRecoverRetry5xx(t *testing.T) {
reqNum := 0
reqs := []http.Response{
{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
{StatusCode: 501, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
{StatusCode: 200, Body: body(`{"data":"valid"}`)},
}
s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10))
s.Handlers.Validate.Clear()
s.Handlers.Unmarshal.PushBack(unmarshal)
s.Handlers.UnmarshalError.PushBack(unmarshalError)
s.Handlers.Send.Clear() // mock sending
s.Handlers.Send.PushBack(func(r *request.Request) {
r.HTTPResponse = &reqs[reqNum]
reqNum++
})
out := &testData{}
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
err := r.Send()
assert.Nil(t, err)
assert.Equal(t, 2, int(r.RetryCount))
assert.Equal(t, "valid", out.Data)
}
// test that retries occur for 4xx status codes with a response type that can be retried - see `shouldRetry`
func TestRequestRecoverRetry4xxRetryable(t *testing.T) {
reqNum := 0
reqs := []http.Response{
{StatusCode: 400, Body: body(`{"__type":"Throttling","message":"Rate exceeded."}`)},
{StatusCode: 429, Body: body(`{"__type":"ProvisionedThroughputExceededException","message":"Rate exceeded."}`)},
{StatusCode: 200, Body: body(`{"data":"valid"}`)},
}
s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10))
s.Handlers.Validate.Clear()
s.Handlers.Unmarshal.PushBack(unmarshal)
s.Handlers.UnmarshalError.PushBack(unmarshalError)
s.Handlers.Send.Clear() // mock sending
s.Handlers.Send.PushBack(func(r *request.Request) {
r.HTTPResponse = &reqs[reqNum]
reqNum++
})
out := &testData{}
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
err := r.Send()
assert.Nil(t, err)
assert.Equal(t, 2, int(r.RetryCount))
assert.Equal(t, "valid", out.Data)
}
// test that retries don't occur for 4xx status codes with a response type that can't be retried
func TestRequest4xxUnretryable(t *testing.T) {
s := awstesting.NewClient(aws.NewConfig().WithMaxRetries(10))
s.Handlers.Validate.Clear()
s.Handlers.Unmarshal.PushBack(unmarshal)
s.Handlers.UnmarshalError.PushBack(unmarshalError)
s.Handlers.Send.Clear() // mock sending
s.Handlers.Send.PushBack(func(r *request.Request) {
r.HTTPResponse = &http.Response{StatusCode: 401, Body: body(`{"__type":"SignatureDoesNotMatch","message":"Signature does not match."}`)}
})
out := &testData{}
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
err := r.Send()
assert.NotNil(t, err)
if e, ok := err.(awserr.RequestFailure); ok {
assert.Equal(t, 401, e.StatusCode())
} else {
assert.Fail(t, "Expected error to be a service failure")
}
assert.Equal(t, "SignatureDoesNotMatch", err.(awserr.Error).Code())
assert.Equal(t, "Signature does not match.", err.(awserr.Error).Message())
assert.Equal(t, 0, int(r.RetryCount))
}
func TestRequestExhaustRetries(t *testing.T) {
delays := []time.Duration{}
sleepDelay := func(delay time.Duration) {
delays = append(delays, delay)
}
reqNum := 0
reqs := []http.Response{
{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
{StatusCode: 500, Body: body(`{"__type":"UnknownError","message":"An error occurred."}`)},
}
s := awstesting.NewClient(aws.NewConfig().WithSleepDelay(sleepDelay))
s.Handlers.Validate.Clear()
s.Handlers.Unmarshal.PushBack(unmarshal)
s.Handlers.UnmarshalError.PushBack(unmarshalError)
s.Handlers.Send.Clear() // mock sending
s.Handlers.Send.PushBack(func(r *request.Request) {
r.HTTPResponse = &reqs[reqNum]
reqNum++
})
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, nil)
err := r.Send()
assert.NotNil(t, err)
if e, ok := err.(awserr.RequestFailure); ok {
assert.Equal(t, 500, e.StatusCode())
} else {
assert.Fail(t, "Expected error to be a service failure")
}
assert.Equal(t, "UnknownError", err.(awserr.Error).Code())
assert.Equal(t, "An error occurred.", err.(awserr.Error).Message())
assert.Equal(t, 3, int(r.RetryCount))
expectDelays := []struct{ min, max time.Duration }{{30, 59}, {60, 118}, {120, 236}}
for i, v := range delays {
min := expectDelays[i].min * time.Millisecond
max := expectDelays[i].max * time.Millisecond
assert.True(t, min <= v && v <= max,
"Expect delay to be within range, i:%d, v:%s, min:%s, max:%s", i, v, min, max)
}
}
// test that the request is retried after the credentials are expired.
func TestRequestRecoverExpiredCreds(t *testing.T) {
reqNum := 0
reqs := []http.Response{
{StatusCode: 400, Body: body(`{"__type":"ExpiredTokenException","message":"expired token"}`)},
{StatusCode: 200, Body: body(`{"data":"valid"}`)},
}
s := awstesting.NewClient(&aws.Config{MaxRetries: aws.Int(10), Credentials: credentials.NewStaticCredentials("AKID", "SECRET", "")})
s.Handlers.Validate.Clear()
s.Handlers.Unmarshal.PushBack(unmarshal)
s.Handlers.UnmarshalError.PushBack(unmarshalError)
credExpiredBeforeRetry := false
credExpiredAfterRetry := false
s.Handlers.AfterRetry.PushBack(func(r *request.Request) {
credExpiredAfterRetry = r.Config.Credentials.IsExpired()
})
s.Handlers.Sign.Clear()
s.Handlers.Sign.PushBack(func(r *request.Request) {
r.Config.Credentials.Get()
})
s.Handlers.Send.Clear() // mock sending
s.Handlers.Send.PushBack(func(r *request.Request) {
r.HTTPResponse = &reqs[reqNum]
reqNum++
})
out := &testData{}
r := s.NewRequest(&request.Operation{Name: "Operation"}, nil, out)
err := r.Send()
assert.Nil(t, err)
assert.False(t, credExpiredBeforeRetry, "Expect valid creds before retry check")
assert.True(t, credExpiredAfterRetry, "Expect expired creds after retry check")
assert.False(t, s.Config.Credentials.IsExpired(), "Expect valid creds after cred expired recovery")
assert.Equal(t, 1, int(r.RetryCount))
assert.Equal(t, "valid", out.Data)
}
func TestMakeAddtoUserAgentHandler(t *testing.T) {
fn := request.MakeAddToUserAgentHandler("name", "version", "extra1", "extra2")
r := &request.Request{HTTPRequest: &http.Request{Header: http.Header{}}}
r.HTTPRequest.Header.Set("User-Agent", "foo/bar")
fn(r)
assert.Equal(t, "foo/bar name/version (extra1; extra2)", r.HTTPRequest.Header.Get("User-Agent"))
}
func TestMakeAddtoUserAgentFreeFormHandler(t *testing.T) {
fn := request.MakeAddToUserAgentFreeFormHandler("name/version (extra1; extra2)")
r := &request.Request{HTTPRequest: &http.Request{Header: http.Header{}}}
r.HTTPRequest.Header.Set("User-Agent", "foo/bar")
fn(r)
assert.Equal(t, "foo/bar name/version (extra1; extra2)", r.HTTPRequest.Header.Get("User-Agent"))
}
func TestRequestUserAgent(t *testing.T) {
s := awstesting.NewClient(&aws.Config{Region: aws.String("us-east-1")})
// s.Handlers.Validate.Clear()
req := s.NewRequest(&request.Operation{Name: "Operation"}, nil, &testData{})
req.HTTPRequest.Header.Set("User-Agent", "foo/bar")
assert.NoError(t, req.Build())
expectUA := fmt.Sprintf("foo/bar %s/%s (%s; %s; %s)",
aws.SDKName, aws.SDKVersion, runtime.Version(), runtime.GOOS, runtime.GOARCH)
assert.Equal(t, expectUA, req.HTTPRequest.Header.Get("User-Agent"))
}

View File

@@ -0,0 +1,82 @@
package request
import (
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
)
// Retryer is an interface to control retry logic for a given service.
// The default implementation used by most services is the service.DefaultRetryer
// structure, which contains basic retry logic using exponential backoff.
type Retryer interface {
RetryRules(*Request) time.Duration
ShouldRetry(*Request) bool
MaxRetries() int
}
// WithRetryer sets a config Retryer value to the given Config returning it
// for chaining.
func WithRetryer(cfg *aws.Config, retryer Retryer) *aws.Config {
cfg.Retryer = retryer
return cfg
}
// retryableCodes is a collection of service response codes which are retry-able
// without any further action.
var retryableCodes = map[string]struct{}{
"RequestError": {},
"RequestTimeout": {},
"ProvisionedThroughputExceededException": {},
"Throttling": {},
"ThrottlingException": {},
"RequestLimitExceeded": {},
"RequestThrottled": {},
"LimitExceededException": {}, // Deleting 10+ DynamoDb tables at once
"TooManyRequestsException": {}, // Lambda functions
}
// credsExpiredCodes is a collection of error codes which signify the credentials
// need to be refreshed. Expired tokens require refreshing of credentials, and
// resigning before the request can be retried.
var credsExpiredCodes = map[string]struct{}{
"ExpiredToken": {},
"ExpiredTokenException": {},
"RequestExpired": {}, // EC2 Only
}
func isCodeRetryable(code string) bool {
if _, ok := retryableCodes[code]; ok {
return true
}
return isCodeExpiredCreds(code)
}
func isCodeExpiredCreds(code string) bool {
_, ok := credsExpiredCodes[code]
return ok
}
// IsErrorRetryable returns whether the error is retryable, based on its Code.
// Returns false if the request has no Error set.
func (r *Request) IsErrorRetryable() bool {
if r.Error != nil {
if err, ok := r.Error.(awserr.Error); ok {
return isCodeRetryable(err.Code())
}
}
return false
}
// IsErrorExpired returns whether the error code is a credential expiry error.
// Returns false if the request has no Error set.
func (r *Request) IsErrorExpired() bool {
if r.Error != nil {
if err, ok := r.Error.(awserr.Error); ok {
return isCodeExpiredCreds(err.Code())
}
}
return false
}

View File

@@ -0,0 +1,105 @@
// Package session provides a way to create service clients with shared configuration
// and handlers.
package session
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/client"
"github.com/aws/aws-sdk-go/aws/corehandlers"
"github.com/aws/aws-sdk-go/aws/defaults"
"github.com/aws/aws-sdk-go/aws/request"
"github.com/aws/aws-sdk-go/private/endpoints"
)
// A Session provides a central location to create service clients from and
// store configurations and request handlers for those services.
//
// Sessions are safe to create service clients concurrently, but it is not safe
// to mutate the session concurrently.
type Session struct {
Config *aws.Config
Handlers request.Handlers
}
// New creates a new instance of the handlers merging in the provided Configs
// on top of the SDK's default configurations. Once the session is created it
// can be mutated to modify Configs or Handlers. The session is safe to be read
// concurrently, but it should not be written to concurrently.
//
// Example:
// // Create a session with the default config and request handlers.
// sess := session.New()
//
// // Create a session with a custom region
// sess := session.New(&aws.Config{Region: aws.String("us-east-1")})
//
// // Create a session, and add additional handlers for all service
// // clients created with the session to inherit. Adds logging handler.
// sess := session.New()
// sess.Handlers.Send.PushFront(func(r *request.Request) {
// // Log every request made and its payload
// logger.Println("Request: %s/%s, Payload: %s", r.ClientInfo.ServiceName, r.Operation, r.Params)
// })
//
// // Create a S3 client instance from a session
// sess := session.New()
// svc := s3.New(sess)
func New(cfgs ...*aws.Config) *Session {
def := defaults.Get()
s := &Session{
Config: def.Config,
Handlers: def.Handlers,
}
s.Config.MergeIn(cfgs...)
initHandlers(s)
return s
}
func initHandlers(s *Session) {
// Add the Validate parameter handler if it is not disabled.
s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler)
if !aws.BoolValue(s.Config.DisableParamValidation) {
s.Handlers.Validate.PushBackNamed(corehandlers.ValidateParametersHandler)
}
}
// Copy creates and returns a copy of the current session, coping the config
// and handlers. If any additional configs are provided they will be merged
// on top of the session's copied config.
//
// Example:
// // Create a copy of the current session, configured for the us-west-2 region.
// sess.Copy(&aws.Config{Region: aws.String("us-west-2"})
func (s *Session) Copy(cfgs ...*aws.Config) *Session {
newSession := &Session{
Config: s.Config.Copy(cfgs...),
Handlers: s.Handlers.Copy(),
}
initHandlers(newSession)
return newSession
}
// ClientConfig satisfies the client.ConfigProvider interface and is used to
// configure the service client instances. Passing the Session to the service
// client's constructor (New) will use this method to configure the client.
//
// Example:
// sess := session.New()
// s3.New(sess)
func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config {
s = s.Copy(cfgs...)
endpoint, signingRegion := endpoints.NormalizeEndpoint(
aws.StringValue(s.Config.Endpoint), serviceName,
aws.StringValue(s.Config.Region), aws.BoolValue(s.Config.DisableSSL))
return client.Config{
Config: s.Config,
Handlers: s.Handlers,
Endpoint: endpoint,
SigningRegion: signingRegion,
}
}

View File

@@ -0,0 +1,20 @@
package session_test
import (
"net/http"
"testing"
"github.com/stretchr/testify/assert"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
)
func TestNewDefaultSession(t *testing.T) {
s := session.New(&aws.Config{Region: aws.String("region")})
assert.Equal(t, "region", *s.Config.Region)
assert.Equal(t, http.DefaultClient, s.Config.HTTPClient)
assert.NotNil(t, s.Config.Logger)
assert.Equal(t, aws.LogOff, *s.Config.LogLevel)
}

View File

@@ -0,0 +1,88 @@
package aws
import (
"io"
"sync"
)
// ReadSeekCloser wraps a io.Reader returning a ReaderSeekerCloser
func ReadSeekCloser(r io.Reader) ReaderSeekerCloser {
return ReaderSeekerCloser{r}
}
// ReaderSeekerCloser represents a reader that can also delegate io.Seeker and
// io.Closer interfaces to the underlying object if they are available.
type ReaderSeekerCloser struct {
r io.Reader
}
// Read reads from the reader up to size of p. The number of bytes read, and
// error if it occurred will be returned.
//
// If the reader is not an io.Reader zero bytes read, and nil error will be returned.
//
// Performs the same functionality as io.Reader Read
func (r ReaderSeekerCloser) Read(p []byte) (int, error) {
switch t := r.r.(type) {
case io.Reader:
return t.Read(p)
}
return 0, nil
}
// Seek sets the offset for the next Read to offset, interpreted according to
// whence: 0 means relative to the origin of the file, 1 means relative to the
// current offset, and 2 means relative to the end. Seek returns the new offset
// and an error, if any.
//
// If the ReaderSeekerCloser is not an io.Seeker nothing will be done.
func (r ReaderSeekerCloser) Seek(offset int64, whence int) (int64, error) {
switch t := r.r.(type) {
case io.Seeker:
return t.Seek(offset, whence)
}
return int64(0), nil
}
// Close closes the ReaderSeekerCloser.
//
// If the ReaderSeekerCloser is not an io.Closer nothing will be done.
func (r ReaderSeekerCloser) Close() error {
switch t := r.r.(type) {
case io.Closer:
return t.Close()
}
return nil
}
// A WriteAtBuffer provides a in memory buffer supporting the io.WriterAt interface
// Can be used with the s3manager.Downloader to download content to a buffer
// in memory. Safe to use concurrently.
type WriteAtBuffer struct {
buf []byte
m sync.Mutex
}
// WriteAt writes a slice of bytes to a buffer starting at the position provided
// The number of bytes written will be returned, or error. Can overwrite previous
// written slices if the write ats overlap.
func (b *WriteAtBuffer) WriteAt(p []byte, pos int64) (n int, err error) {
b.m.Lock()
defer b.m.Unlock()
expLen := pos + int64(len(p))
if int64(len(b.buf)) < expLen {
newBuf := make([]byte, expLen)
copy(newBuf, b.buf)
b.buf = newBuf
}
copy(b.buf[pos:], p)
return len(p), nil
}
// Bytes returns a slice of bytes written to the buffer.
func (b *WriteAtBuffer) Bytes() []byte {
b.m.Lock()
defer b.m.Unlock()
return b.buf[:len(b.buf):len(b.buf)]
}

View File

@@ -0,0 +1,56 @@
package aws
import (
"math/rand"
"testing"
"github.com/stretchr/testify/assert"
)
func TestWriteAtBuffer(t *testing.T) {
b := &WriteAtBuffer{}
n, err := b.WriteAt([]byte{1}, 0)
assert.NoError(t, err)
assert.Equal(t, 1, n)
n, err = b.WriteAt([]byte{1, 1, 1}, 5)
assert.NoError(t, err)
assert.Equal(t, 3, n)
n, err = b.WriteAt([]byte{2}, 1)
assert.NoError(t, err)
assert.Equal(t, 1, n)
n, err = b.WriteAt([]byte{3}, 2)
assert.NoError(t, err)
assert.Equal(t, 1, n)
assert.Equal(t, []byte{1, 2, 3, 0, 0, 1, 1, 1}, b.Bytes())
}
func BenchmarkWriteAtBuffer(b *testing.B) {
buf := &WriteAtBuffer{}
r := rand.New(rand.NewSource(1))
b.ResetTimer()
for i := 0; i < b.N; i++ {
to := r.Intn(10) * 4096
bs := make([]byte, to)
buf.WriteAt(bs, r.Int63n(10)*4096)
}
}
func BenchmarkWriteAtBufferParallel(b *testing.B) {
buf := &WriteAtBuffer{}
r := rand.New(rand.NewSource(1))
b.ResetTimer()
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
to := r.Intn(10) * 4096
bs := make([]byte, to)
buf.WriteAt(bs, r.Int63n(10)*4096)
}
})
}

View File

@@ -0,0 +1,8 @@
// Package aws provides core functionality for making requests to AWS services.
package aws
// SDKName is the name of this AWS SDK
const SDKName = "aws-sdk-go"
// SDKVersion is the version of this SDK
const SDKVersion = "1.0.0"

View File

@@ -0,0 +1,31 @@
// Package endpoints validates regional endpoints for services.
package endpoints
//go:generate go run ../model/cli/gen-endpoints/main.go endpoints.json endpoints_map.go
//go:generate gofmt -s -w endpoints_map.go
import "strings"
// EndpointForRegion returns an endpoint and its signing region for a service and region.
// if the service and region pair are not found endpoint and signingRegion will be empty.
func EndpointForRegion(svcName, region string) (endpoint, signingRegion string) {
derivedKeys := []string{
region + "/" + svcName,
region + "/*",
"*/" + svcName,
"*/*",
}
for _, key := range derivedKeys {
if val, ok := endpointsMap.Endpoints[key]; ok {
ep := val.Endpoint
ep = strings.Replace(ep, "{region}", region, -1)
ep = strings.Replace(ep, "{service}", svcName, -1)
endpoint = ep
signingRegion = val.SigningRegion
return
}
}
return
}

View File

@@ -0,0 +1,77 @@
{
"version": 2,
"endpoints": {
"*/*": {
"endpoint": "{service}.{region}.amazonaws.com"
},
"cn-north-1/*": {
"endpoint": "{service}.{region}.amazonaws.com.cn",
"signatureVersion": "v4"
},
"us-gov-west-1/iam": {
"endpoint": "iam.us-gov.amazonaws.com"
},
"us-gov-west-1/sts": {
"endpoint": "sts.us-gov-west-1.amazonaws.com"
},
"us-gov-west-1/s3": {
"endpoint": "s3-{region}.amazonaws.com"
},
"*/cloudfront": {
"endpoint": "cloudfront.amazonaws.com",
"signingRegion": "us-east-1"
},
"*/cloudsearchdomain": {
"endpoint": "",
"signingRegion": "us-east-1"
},
"*/iam": {
"endpoint": "iam.amazonaws.com",
"signingRegion": "us-east-1"
},
"*/importexport": {
"endpoint": "importexport.amazonaws.com",
"signingRegion": "us-east-1"
},
"*/route53": {
"endpoint": "route53.amazonaws.com",
"signingRegion": "us-east-1"
},
"*/sts": {
"endpoint": "sts.amazonaws.com",
"signingRegion": "us-east-1"
},
"us-east-1/sdb": {
"endpoint": "sdb.amazonaws.com",
"signingRegion": "us-east-1"
},
"us-east-1/s3": {
"endpoint": "s3.amazonaws.com"
},
"us-west-1/s3": {
"endpoint": "s3-{region}.amazonaws.com"
},
"us-west-2/s3": {
"endpoint": "s3-{region}.amazonaws.com"
},
"eu-west-1/s3": {
"endpoint": "s3-{region}.amazonaws.com"
},
"ap-southeast-1/s3": {
"endpoint": "s3-{region}.amazonaws.com"
},
"ap-southeast-2/s3": {
"endpoint": "s3-{region}.amazonaws.com"
},
"ap-northeast-1/s3": {
"endpoint": "s3-{region}.amazonaws.com"
},
"sa-east-1/s3": {
"endpoint": "s3-{region}.amazonaws.com"
},
"eu-central-1/s3": {
"endpoint": "{service}.{region}.amazonaws.com",
"signatureVersion": "v4"
}
}
}

View File

@@ -0,0 +1,89 @@
package endpoints
// THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT.
type endpointStruct struct {
Version int
Endpoints map[string]endpointEntry
}
type endpointEntry struct {
Endpoint string
SigningRegion string
}
var endpointsMap = endpointStruct{
Version: 2,
Endpoints: map[string]endpointEntry{
"*/*": {
Endpoint: "{service}.{region}.amazonaws.com",
},
"*/cloudfront": {
Endpoint: "cloudfront.amazonaws.com",
SigningRegion: "us-east-1",
},
"*/cloudsearchdomain": {
Endpoint: "",
SigningRegion: "us-east-1",
},
"*/iam": {
Endpoint: "iam.amazonaws.com",
SigningRegion: "us-east-1",
},
"*/importexport": {
Endpoint: "importexport.amazonaws.com",
SigningRegion: "us-east-1",
},
"*/route53": {
Endpoint: "route53.amazonaws.com",
SigningRegion: "us-east-1",
},
"*/sts": {
Endpoint: "sts.amazonaws.com",
SigningRegion: "us-east-1",
},
"ap-northeast-1/s3": {
Endpoint: "s3-{region}.amazonaws.com",
},
"ap-southeast-1/s3": {
Endpoint: "s3-{region}.amazonaws.com",
},
"ap-southeast-2/s3": {
Endpoint: "s3-{region}.amazonaws.com",
},
"cn-north-1/*": {
Endpoint: "{service}.{region}.amazonaws.com.cn",
},
"eu-central-1/s3": {
Endpoint: "{service}.{region}.amazonaws.com",
},
"eu-west-1/s3": {
Endpoint: "s3-{region}.amazonaws.com",
},
"sa-east-1/s3": {
Endpoint: "s3-{region}.amazonaws.com",
},
"us-east-1/s3": {
Endpoint: "s3.amazonaws.com",
},
"us-east-1/sdb": {
Endpoint: "sdb.amazonaws.com",
SigningRegion: "us-east-1",
},
"us-gov-west-1/iam": {
Endpoint: "iam.us-gov.amazonaws.com",
},
"us-gov-west-1/s3": {
Endpoint: "s3-{region}.amazonaws.com",
},
"us-gov-west-1/sts": {
Endpoint: "sts.us-gov-west-1.amazonaws.com",
},
"us-west-1/s3": {
Endpoint: "s3-{region}.amazonaws.com",
},
"us-west-2/s3": {
Endpoint: "s3-{region}.amazonaws.com",
},
},
}

View File

@@ -0,0 +1,28 @@
package endpoints
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGlobalEndpoints(t *testing.T) {
region := "mock-region-1"
svcs := []string{"cloudfront", "iam", "importexport", "route53", "sts"}
for _, name := range svcs {
ep, sr := EndpointForRegion(name, region)
assert.Equal(t, name+".amazonaws.com", ep)
assert.Equal(t, "us-east-1", sr)
}
}
func TestServicesInCN(t *testing.T) {
region := "cn-north-1"
svcs := []string{"cloudfront", "iam", "importexport", "route53", "sts", "s3"}
for _, name := range svcs {
ep, _ := EndpointForRegion(name, region)
assert.Equal(t, name+"."+region+".amazonaws.com.cn", ep)
}
}

View File

@@ -0,0 +1,32 @@
// Package ec2query provides serialisation of AWS EC2 requests and responses.
package ec2query
//go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/input/ec2.json build_test.go
import (
"net/url"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/internal/protocol/query/queryutil"
)
// Build builds a request for the EC2 protocol.
func Build(r *aws.Request) {
body := url.Values{
"Action": {r.Operation.Name},
"Version": {r.Service.APIVersion},
}
if err := queryutil.Parse(body, r.Params, true); err != nil {
r.Error = awserr.New("SerializationError", "failed encoding EC2 Query request", err)
}
if r.ExpireTime == 0 {
r.HTTPRequest.Method = "POST"
r.HTTPRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
r.SetBufferBody([]byte(body.Encode()))
} else { // This is a pre-signed request
r.HTTPRequest.Method = "GET"
r.HTTPRequest.URL.RawQuery = body.Encode()
}
}

View File

@@ -0,0 +1,860 @@
package ec2query_test
import (
"bytes"
"encoding/json"
"encoding/xml"
"io"
"io/ioutil"
"net/http"
"net/url"
"testing"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/protocol/ec2query"
"github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil"
"github.com/aws/aws-sdk-go/internal/signer/v4"
"github.com/aws/aws-sdk-go/internal/util"
"github.com/stretchr/testify/assert"
)
var _ bytes.Buffer // always import bytes
var _ http.Request
var _ json.Marshaler
var _ time.Time
var _ xmlutil.XMLNode
var _ xml.Attr
var _ = ioutil.Discard
var _ = util.Trim("")
var _ = url.Values{}
var _ = io.EOF
type InputService1ProtocolTest struct {
*aws.Service
}
// New returns a new InputService1ProtocolTest client.
func NewInputService1ProtocolTest(config *aws.Config) *InputService1ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice1protocoltest",
APIVersion: "2014-01-01",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &InputService1ProtocolTest{service}
}
// newRequest creates a new request for a InputService1ProtocolTest operation and runs any
// custom request initialization.
func (c *InputService1ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opInputService1TestCaseOperation1 = "OperationName"
// InputService1TestCaseOperation1Request generates a request for the InputService1TestCaseOperation1 operation.
func (c *InputService1ProtocolTest) InputService1TestCaseOperation1Request(input *InputService1TestShapeInputShape) (req *aws.Request, output *InputService1TestShapeInputService1TestCaseOperation1Output) {
op := &aws.Operation{
Name: opInputService1TestCaseOperation1,
}
if input == nil {
input = &InputService1TestShapeInputShape{}
}
req = c.newRequest(op, input, output)
output = &InputService1TestShapeInputService1TestCaseOperation1Output{}
req.Data = output
return
}
func (c *InputService1ProtocolTest) InputService1TestCaseOperation1(input *InputService1TestShapeInputShape) (*InputService1TestShapeInputService1TestCaseOperation1Output, error) {
req, out := c.InputService1TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type InputService1TestShapeInputService1TestCaseOperation1Output struct {
metadataInputService1TestShapeInputService1TestCaseOperation1Output `json:"-" xml:"-"`
}
type metadataInputService1TestShapeInputService1TestCaseOperation1Output struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService1TestShapeInputShape struct {
Bar *string `type:"string"`
Foo *string `type:"string"`
metadataInputService1TestShapeInputShape `json:"-" xml:"-"`
}
type metadataInputService1TestShapeInputShape struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService2ProtocolTest struct {
*aws.Service
}
// New returns a new InputService2ProtocolTest client.
func NewInputService2ProtocolTest(config *aws.Config) *InputService2ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice2protocoltest",
APIVersion: "2014-01-01",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &InputService2ProtocolTest{service}
}
// newRequest creates a new request for a InputService2ProtocolTest operation and runs any
// custom request initialization.
func (c *InputService2ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opInputService2TestCaseOperation1 = "OperationName"
// InputService2TestCaseOperation1Request generates a request for the InputService2TestCaseOperation1 operation.
func (c *InputService2ProtocolTest) InputService2TestCaseOperation1Request(input *InputService2TestShapeInputShape) (req *aws.Request, output *InputService2TestShapeInputService2TestCaseOperation1Output) {
op := &aws.Operation{
Name: opInputService2TestCaseOperation1,
}
if input == nil {
input = &InputService2TestShapeInputShape{}
}
req = c.newRequest(op, input, output)
output = &InputService2TestShapeInputService2TestCaseOperation1Output{}
req.Data = output
return
}
func (c *InputService2ProtocolTest) InputService2TestCaseOperation1(input *InputService2TestShapeInputShape) (*InputService2TestShapeInputService2TestCaseOperation1Output, error) {
req, out := c.InputService2TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type InputService2TestShapeInputService2TestCaseOperation1Output struct {
metadataInputService2TestShapeInputService2TestCaseOperation1Output `json:"-" xml:"-"`
}
type metadataInputService2TestShapeInputService2TestCaseOperation1Output struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService2TestShapeInputShape struct {
Bar *string `locationName:"barLocationName" type:"string"`
Foo *string `type:"string"`
Yuck *string `locationName:"yuckLocationName" queryName:"yuckQueryName" type:"string"`
metadataInputService2TestShapeInputShape `json:"-" xml:"-"`
}
type metadataInputService2TestShapeInputShape struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService3ProtocolTest struct {
*aws.Service
}
// New returns a new InputService3ProtocolTest client.
func NewInputService3ProtocolTest(config *aws.Config) *InputService3ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice3protocoltest",
APIVersion: "2014-01-01",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &InputService3ProtocolTest{service}
}
// newRequest creates a new request for a InputService3ProtocolTest operation and runs any
// custom request initialization.
func (c *InputService3ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opInputService3TestCaseOperation1 = "OperationName"
// InputService3TestCaseOperation1Request generates a request for the InputService3TestCaseOperation1 operation.
func (c *InputService3ProtocolTest) InputService3TestCaseOperation1Request(input *InputService3TestShapeInputShape) (req *aws.Request, output *InputService3TestShapeInputService3TestCaseOperation1Output) {
op := &aws.Operation{
Name: opInputService3TestCaseOperation1,
}
if input == nil {
input = &InputService3TestShapeInputShape{}
}
req = c.newRequest(op, input, output)
output = &InputService3TestShapeInputService3TestCaseOperation1Output{}
req.Data = output
return
}
func (c *InputService3ProtocolTest) InputService3TestCaseOperation1(input *InputService3TestShapeInputShape) (*InputService3TestShapeInputService3TestCaseOperation1Output, error) {
req, out := c.InputService3TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type InputService3TestShapeInputService3TestCaseOperation1Output struct {
metadataInputService3TestShapeInputService3TestCaseOperation1Output `json:"-" xml:"-"`
}
type metadataInputService3TestShapeInputService3TestCaseOperation1Output struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService3TestShapeInputShape struct {
StructArg *InputService3TestShapeStructType `locationName:"Struct" type:"structure"`
metadataInputService3TestShapeInputShape `json:"-" xml:"-"`
}
type metadataInputService3TestShapeInputShape struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService3TestShapeStructType struct {
ScalarArg *string `locationName:"Scalar" type:"string"`
metadataInputService3TestShapeStructType `json:"-" xml:"-"`
}
type metadataInputService3TestShapeStructType struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService4ProtocolTest struct {
*aws.Service
}
// New returns a new InputService4ProtocolTest client.
func NewInputService4ProtocolTest(config *aws.Config) *InputService4ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice4protocoltest",
APIVersion: "2014-01-01",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &InputService4ProtocolTest{service}
}
// newRequest creates a new request for a InputService4ProtocolTest operation and runs any
// custom request initialization.
func (c *InputService4ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opInputService4TestCaseOperation1 = "OperationName"
// InputService4TestCaseOperation1Request generates a request for the InputService4TestCaseOperation1 operation.
func (c *InputService4ProtocolTest) InputService4TestCaseOperation1Request(input *InputService4TestShapeInputShape) (req *aws.Request, output *InputService4TestShapeInputService4TestCaseOperation1Output) {
op := &aws.Operation{
Name: opInputService4TestCaseOperation1,
}
if input == nil {
input = &InputService4TestShapeInputShape{}
}
req = c.newRequest(op, input, output)
output = &InputService4TestShapeInputService4TestCaseOperation1Output{}
req.Data = output
return
}
func (c *InputService4ProtocolTest) InputService4TestCaseOperation1(input *InputService4TestShapeInputShape) (*InputService4TestShapeInputService4TestCaseOperation1Output, error) {
req, out := c.InputService4TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type InputService4TestShapeInputService4TestCaseOperation1Output struct {
metadataInputService4TestShapeInputService4TestCaseOperation1Output `json:"-" xml:"-"`
}
type metadataInputService4TestShapeInputService4TestCaseOperation1Output struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService4TestShapeInputShape struct {
ListArg []*string `type:"list"`
metadataInputService4TestShapeInputShape `json:"-" xml:"-"`
}
type metadataInputService4TestShapeInputShape struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService5ProtocolTest struct {
*aws.Service
}
// New returns a new InputService5ProtocolTest client.
func NewInputService5ProtocolTest(config *aws.Config) *InputService5ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice5protocoltest",
APIVersion: "2014-01-01",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &InputService5ProtocolTest{service}
}
// newRequest creates a new request for a InputService5ProtocolTest operation and runs any
// custom request initialization.
func (c *InputService5ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opInputService5TestCaseOperation1 = "OperationName"
// InputService5TestCaseOperation1Request generates a request for the InputService5TestCaseOperation1 operation.
func (c *InputService5ProtocolTest) InputService5TestCaseOperation1Request(input *InputService5TestShapeInputShape) (req *aws.Request, output *InputService5TestShapeInputService5TestCaseOperation1Output) {
op := &aws.Operation{
Name: opInputService5TestCaseOperation1,
}
if input == nil {
input = &InputService5TestShapeInputShape{}
}
req = c.newRequest(op, input, output)
output = &InputService5TestShapeInputService5TestCaseOperation1Output{}
req.Data = output
return
}
func (c *InputService5ProtocolTest) InputService5TestCaseOperation1(input *InputService5TestShapeInputShape) (*InputService5TestShapeInputService5TestCaseOperation1Output, error) {
req, out := c.InputService5TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type InputService5TestShapeInputService5TestCaseOperation1Output struct {
metadataInputService5TestShapeInputService5TestCaseOperation1Output `json:"-" xml:"-"`
}
type metadataInputService5TestShapeInputService5TestCaseOperation1Output struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService5TestShapeInputShape struct {
ListArg []*string `locationName:"ListMemberName" locationNameList:"item" type:"list"`
metadataInputService5TestShapeInputShape `json:"-" xml:"-"`
}
type metadataInputService5TestShapeInputShape struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService6ProtocolTest struct {
*aws.Service
}
// New returns a new InputService6ProtocolTest client.
func NewInputService6ProtocolTest(config *aws.Config) *InputService6ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice6protocoltest",
APIVersion: "2014-01-01",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &InputService6ProtocolTest{service}
}
// newRequest creates a new request for a InputService6ProtocolTest operation and runs any
// custom request initialization.
func (c *InputService6ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opInputService6TestCaseOperation1 = "OperationName"
// InputService6TestCaseOperation1Request generates a request for the InputService6TestCaseOperation1 operation.
func (c *InputService6ProtocolTest) InputService6TestCaseOperation1Request(input *InputService6TestShapeInputShape) (req *aws.Request, output *InputService6TestShapeInputService6TestCaseOperation1Output) {
op := &aws.Operation{
Name: opInputService6TestCaseOperation1,
}
if input == nil {
input = &InputService6TestShapeInputShape{}
}
req = c.newRequest(op, input, output)
output = &InputService6TestShapeInputService6TestCaseOperation1Output{}
req.Data = output
return
}
func (c *InputService6ProtocolTest) InputService6TestCaseOperation1(input *InputService6TestShapeInputShape) (*InputService6TestShapeInputService6TestCaseOperation1Output, error) {
req, out := c.InputService6TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type InputService6TestShapeInputService6TestCaseOperation1Output struct {
metadataInputService6TestShapeInputService6TestCaseOperation1Output `json:"-" xml:"-"`
}
type metadataInputService6TestShapeInputService6TestCaseOperation1Output struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService6TestShapeInputShape struct {
ListArg []*string `locationName:"ListMemberName" queryName:"ListQueryName" locationNameList:"item" type:"list"`
metadataInputService6TestShapeInputShape `json:"-" xml:"-"`
}
type metadataInputService6TestShapeInputShape struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService7ProtocolTest struct {
*aws.Service
}
// New returns a new InputService7ProtocolTest client.
func NewInputService7ProtocolTest(config *aws.Config) *InputService7ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice7protocoltest",
APIVersion: "2014-01-01",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &InputService7ProtocolTest{service}
}
// newRequest creates a new request for a InputService7ProtocolTest operation and runs any
// custom request initialization.
func (c *InputService7ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opInputService7TestCaseOperation1 = "OperationName"
// InputService7TestCaseOperation1Request generates a request for the InputService7TestCaseOperation1 operation.
func (c *InputService7ProtocolTest) InputService7TestCaseOperation1Request(input *InputService7TestShapeInputShape) (req *aws.Request, output *InputService7TestShapeInputService7TestCaseOperation1Output) {
op := &aws.Operation{
Name: opInputService7TestCaseOperation1,
}
if input == nil {
input = &InputService7TestShapeInputShape{}
}
req = c.newRequest(op, input, output)
output = &InputService7TestShapeInputService7TestCaseOperation1Output{}
req.Data = output
return
}
func (c *InputService7ProtocolTest) InputService7TestCaseOperation1(input *InputService7TestShapeInputShape) (*InputService7TestShapeInputService7TestCaseOperation1Output, error) {
req, out := c.InputService7TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type InputService7TestShapeInputService7TestCaseOperation1Output struct {
metadataInputService7TestShapeInputService7TestCaseOperation1Output `json:"-" xml:"-"`
}
type metadataInputService7TestShapeInputService7TestCaseOperation1Output struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService7TestShapeInputShape struct {
BlobArg []byte `type:"blob"`
metadataInputService7TestShapeInputShape `json:"-" xml:"-"`
}
type metadataInputService7TestShapeInputShape struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService8ProtocolTest struct {
*aws.Service
}
// New returns a new InputService8ProtocolTest client.
func NewInputService8ProtocolTest(config *aws.Config) *InputService8ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "inputservice8protocoltest",
APIVersion: "2014-01-01",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &InputService8ProtocolTest{service}
}
// newRequest creates a new request for a InputService8ProtocolTest operation and runs any
// custom request initialization.
func (c *InputService8ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opInputService8TestCaseOperation1 = "OperationName"
// InputService8TestCaseOperation1Request generates a request for the InputService8TestCaseOperation1 operation.
func (c *InputService8ProtocolTest) InputService8TestCaseOperation1Request(input *InputService8TestShapeInputShape) (req *aws.Request, output *InputService8TestShapeInputService8TestCaseOperation1Output) {
op := &aws.Operation{
Name: opInputService8TestCaseOperation1,
}
if input == nil {
input = &InputService8TestShapeInputShape{}
}
req = c.newRequest(op, input, output)
output = &InputService8TestShapeInputService8TestCaseOperation1Output{}
req.Data = output
return
}
func (c *InputService8ProtocolTest) InputService8TestCaseOperation1(input *InputService8TestShapeInputShape) (*InputService8TestShapeInputService8TestCaseOperation1Output, error) {
req, out := c.InputService8TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type InputService8TestShapeInputService8TestCaseOperation1Output struct {
metadataInputService8TestShapeInputService8TestCaseOperation1Output `json:"-" xml:"-"`
}
type metadataInputService8TestShapeInputService8TestCaseOperation1Output struct {
SDKShapeTraits bool `type:"structure"`
}
type InputService8TestShapeInputShape struct {
TimeArg *time.Time `type:"timestamp" timestampFormat:"iso8601"`
metadataInputService8TestShapeInputShape `json:"-" xml:"-"`
}
type metadataInputService8TestShapeInputShape struct {
SDKShapeTraits bool `type:"structure"`
}
//
// Tests begin here
//
func TestInputService1ProtocolTestScalarMembersCase1(t *testing.T) {
svc := NewInputService1ProtocolTest(nil)
svc.Endpoint = "https://test"
input := &InputService1TestShapeInputShape{
Bar: aws.String("val2"),
Foo: aws.String("val1"),
}
req, _ := svc.InputService1TestCaseOperation1Request(input)
r := req.HTTPRequest
// build request
ec2query.Build(req)
assert.NoError(t, req.Error)
// assert body
assert.NotNil(t, r.Body)
body, _ := ioutil.ReadAll(r.Body)
assert.Equal(t, util.Trim(`Action=OperationName&Bar=val2&Foo=val1&Version=2014-01-01`), util.Trim(string(body)))
// assert URL
assert.Equal(t, "https://test/", r.URL.String())
// assert headers
}
func TestInputService2ProtocolTestStructureWithLocationNameAndQueryNameAppliedToMembersCase1(t *testing.T) {
svc := NewInputService2ProtocolTest(nil)
svc.Endpoint = "https://test"
input := &InputService2TestShapeInputShape{
Bar: aws.String("val2"),
Foo: aws.String("val1"),
Yuck: aws.String("val3"),
}
req, _ := svc.InputService2TestCaseOperation1Request(input)
r := req.HTTPRequest
// build request
ec2query.Build(req)
assert.NoError(t, req.Error)
// assert body
assert.NotNil(t, r.Body)
body, _ := ioutil.ReadAll(r.Body)
assert.Equal(t, util.Trim(`Action=OperationName&BarLocationName=val2&Foo=val1&Version=2014-01-01&yuckQueryName=val3`), util.Trim(string(body)))
// assert URL
assert.Equal(t, "https://test/", r.URL.String())
// assert headers
}
func TestInputService3ProtocolTestNestedStructureMembersCase1(t *testing.T) {
svc := NewInputService3ProtocolTest(nil)
svc.Endpoint = "https://test"
input := &InputService3TestShapeInputShape{
StructArg: &InputService3TestShapeStructType{
ScalarArg: aws.String("foo"),
},
}
req, _ := svc.InputService3TestCaseOperation1Request(input)
r := req.HTTPRequest
// build request
ec2query.Build(req)
assert.NoError(t, req.Error)
// assert body
assert.NotNil(t, r.Body)
body, _ := ioutil.ReadAll(r.Body)
assert.Equal(t, util.Trim(`Action=OperationName&Struct.Scalar=foo&Version=2014-01-01`), util.Trim(string(body)))
// assert URL
assert.Equal(t, "https://test/", r.URL.String())
// assert headers
}
func TestInputService4ProtocolTestListTypesCase1(t *testing.T) {
svc := NewInputService4ProtocolTest(nil)
svc.Endpoint = "https://test"
input := &InputService4TestShapeInputShape{
ListArg: []*string{
aws.String("foo"),
aws.String("bar"),
aws.String("baz"),
},
}
req, _ := svc.InputService4TestCaseOperation1Request(input)
r := req.HTTPRequest
// build request
ec2query.Build(req)
assert.NoError(t, req.Error)
// assert body
assert.NotNil(t, r.Body)
body, _ := ioutil.ReadAll(r.Body)
assert.Equal(t, util.Trim(`Action=OperationName&ListArg.1=foo&ListArg.2=bar&ListArg.3=baz&Version=2014-01-01`), util.Trim(string(body)))
// assert URL
assert.Equal(t, "https://test/", r.URL.String())
// assert headers
}
func TestInputService5ProtocolTestListWithLocationNameAppliedToMemberCase1(t *testing.T) {
svc := NewInputService5ProtocolTest(nil)
svc.Endpoint = "https://test"
input := &InputService5TestShapeInputShape{
ListArg: []*string{
aws.String("a"),
aws.String("b"),
aws.String("c"),
},
}
req, _ := svc.InputService5TestCaseOperation1Request(input)
r := req.HTTPRequest
// build request
ec2query.Build(req)
assert.NoError(t, req.Error)
// assert body
assert.NotNil(t, r.Body)
body, _ := ioutil.ReadAll(r.Body)
assert.Equal(t, util.Trim(`Action=OperationName&ListMemberName.1=a&ListMemberName.2=b&ListMemberName.3=c&Version=2014-01-01`), util.Trim(string(body)))
// assert URL
assert.Equal(t, "https://test/", r.URL.String())
// assert headers
}
func TestInputService6ProtocolTestListWithLocationNameAndQueryNameCase1(t *testing.T) {
svc := NewInputService6ProtocolTest(nil)
svc.Endpoint = "https://test"
input := &InputService6TestShapeInputShape{
ListArg: []*string{
aws.String("a"),
aws.String("b"),
aws.String("c"),
},
}
req, _ := svc.InputService6TestCaseOperation1Request(input)
r := req.HTTPRequest
// build request
ec2query.Build(req)
assert.NoError(t, req.Error)
// assert body
assert.NotNil(t, r.Body)
body, _ := ioutil.ReadAll(r.Body)
assert.Equal(t, util.Trim(`Action=OperationName&ListQueryName.1=a&ListQueryName.2=b&ListQueryName.3=c&Version=2014-01-01`), util.Trim(string(body)))
// assert URL
assert.Equal(t, "https://test/", r.URL.String())
// assert headers
}
func TestInputService7ProtocolTestBase64EncodedBlobsCase1(t *testing.T) {
svc := NewInputService7ProtocolTest(nil)
svc.Endpoint = "https://test"
input := &InputService7TestShapeInputShape{
BlobArg: []byte("foo"),
}
req, _ := svc.InputService7TestCaseOperation1Request(input)
r := req.HTTPRequest
// build request
ec2query.Build(req)
assert.NoError(t, req.Error)
// assert body
assert.NotNil(t, r.Body)
body, _ := ioutil.ReadAll(r.Body)
assert.Equal(t, util.Trim(`Action=OperationName&BlobArg=Zm9v&Version=2014-01-01`), util.Trim(string(body)))
// assert URL
assert.Equal(t, "https://test/", r.URL.String())
// assert headers
}
func TestInputService8ProtocolTestTimestampValuesCase1(t *testing.T) {
svc := NewInputService8ProtocolTest(nil)
svc.Endpoint = "https://test"
input := &InputService8TestShapeInputShape{
TimeArg: aws.Time(time.Unix(1422172800, 0)),
}
req, _ := svc.InputService8TestCaseOperation1Request(input)
r := req.HTTPRequest
// build request
ec2query.Build(req)
assert.NoError(t, req.Error)
// assert body
assert.NotNil(t, r.Body)
body, _ := ioutil.ReadAll(r.Body)
assert.Equal(t, util.Trim(`Action=OperationName&TimeArg=2015-01-25T08%3A00%3A00Z&Version=2014-01-01`), util.Trim(string(body)))
// assert URL
assert.Equal(t, "https://test/", r.URL.String())
// assert headers
}

View File

@@ -0,0 +1,54 @@
package ec2query
//go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/output/ec2.json unmarshal_test.go
import (
"encoding/xml"
"io"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil"
)
// Unmarshal unmarshals a response body for the EC2 protocol.
func Unmarshal(r *aws.Request) {
defer r.HTTPResponse.Body.Close()
if r.DataFilled() {
decoder := xml.NewDecoder(r.HTTPResponse.Body)
err := xmlutil.UnmarshalXML(r.Data, decoder, "")
if err != nil {
r.Error = awserr.New("SerializationError", "failed decoding EC2 Query response", err)
return
}
}
}
// UnmarshalMeta unmarshals response headers for the EC2 protocol.
func UnmarshalMeta(r *aws.Request) {
// TODO implement unmarshaling of request IDs
}
type xmlErrorResponse struct {
XMLName xml.Name `xml:"Response"`
Code string `xml:"Errors>Error>Code"`
Message string `xml:"Errors>Error>Message"`
RequestID string `xml:"RequestId"`
}
// UnmarshalError unmarshals a response error for the EC2 protocol.
func UnmarshalError(r *aws.Request) {
defer r.HTTPResponse.Body.Close()
resp := &xmlErrorResponse{}
err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp)
if err != nil && err != io.EOF {
r.Error = awserr.New("SerializationError", "failed decoding EC2 Query error response", err)
} else {
r.Error = awserr.NewRequestFailure(
awserr.New(resp.Code, resp.Message, nil),
r.HTTPResponse.StatusCode,
resp.RequestID,
)
}
}

View File

@@ -0,0 +1,816 @@
package ec2query_test
import (
"bytes"
"encoding/json"
"encoding/xml"
"io"
"io/ioutil"
"net/http"
"net/url"
"testing"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/internal/protocol/ec2query"
"github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil"
"github.com/aws/aws-sdk-go/internal/signer/v4"
"github.com/aws/aws-sdk-go/internal/util"
"github.com/stretchr/testify/assert"
)
var _ bytes.Buffer // always import bytes
var _ http.Request
var _ json.Marshaler
var _ time.Time
var _ xmlutil.XMLNode
var _ xml.Attr
var _ = ioutil.Discard
var _ = util.Trim("")
var _ = url.Values{}
var _ = io.EOF
type OutputService1ProtocolTest struct {
*aws.Service
}
// New returns a new OutputService1ProtocolTest client.
func NewOutputService1ProtocolTest(config *aws.Config) *OutputService1ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "outputservice1protocoltest",
APIVersion: "",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &OutputService1ProtocolTest{service}
}
// newRequest creates a new request for a OutputService1ProtocolTest operation and runs any
// custom request initialization.
func (c *OutputService1ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opOutputService1TestCaseOperation1 = "OperationName"
// OutputService1TestCaseOperation1Request generates a request for the OutputService1TestCaseOperation1 operation.
func (c *OutputService1ProtocolTest) OutputService1TestCaseOperation1Request(input *OutputService1TestShapeOutputService1TestCaseOperation1Input) (req *aws.Request, output *OutputService1TestShapeOutputShape) {
op := &aws.Operation{
Name: opOutputService1TestCaseOperation1,
}
if input == nil {
input = &OutputService1TestShapeOutputService1TestCaseOperation1Input{}
}
req = c.newRequest(op, input, output)
output = &OutputService1TestShapeOutputShape{}
req.Data = output
return
}
func (c *OutputService1ProtocolTest) OutputService1TestCaseOperation1(input *OutputService1TestShapeOutputService1TestCaseOperation1Input) (*OutputService1TestShapeOutputShape, error) {
req, out := c.OutputService1TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type OutputService1TestShapeOutputService1TestCaseOperation1Input struct {
metadataOutputService1TestShapeOutputService1TestCaseOperation1Input `json:"-" xml:"-"`
}
type metadataOutputService1TestShapeOutputService1TestCaseOperation1Input struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService1TestShapeOutputShape struct {
Char *string `type:"character"`
Double *float64 `type:"double"`
FalseBool *bool `type:"boolean"`
Float *float64 `type:"float"`
Long *int64 `type:"long"`
Num *int64 `locationName:"FooNum" type:"integer"`
Str *string `type:"string"`
TrueBool *bool `type:"boolean"`
metadataOutputService1TestShapeOutputShape `json:"-" xml:"-"`
}
type metadataOutputService1TestShapeOutputShape struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService2ProtocolTest struct {
*aws.Service
}
// New returns a new OutputService2ProtocolTest client.
func NewOutputService2ProtocolTest(config *aws.Config) *OutputService2ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "outputservice2protocoltest",
APIVersion: "",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &OutputService2ProtocolTest{service}
}
// newRequest creates a new request for a OutputService2ProtocolTest operation and runs any
// custom request initialization.
func (c *OutputService2ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opOutputService2TestCaseOperation1 = "OperationName"
// OutputService2TestCaseOperation1Request generates a request for the OutputService2TestCaseOperation1 operation.
func (c *OutputService2ProtocolTest) OutputService2TestCaseOperation1Request(input *OutputService2TestShapeOutputService2TestCaseOperation1Input) (req *aws.Request, output *OutputService2TestShapeOutputShape) {
op := &aws.Operation{
Name: opOutputService2TestCaseOperation1,
}
if input == nil {
input = &OutputService2TestShapeOutputService2TestCaseOperation1Input{}
}
req = c.newRequest(op, input, output)
output = &OutputService2TestShapeOutputShape{}
req.Data = output
return
}
func (c *OutputService2ProtocolTest) OutputService2TestCaseOperation1(input *OutputService2TestShapeOutputService2TestCaseOperation1Input) (*OutputService2TestShapeOutputShape, error) {
req, out := c.OutputService2TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type OutputService2TestShapeOutputService2TestCaseOperation1Input struct {
metadataOutputService2TestShapeOutputService2TestCaseOperation1Input `json:"-" xml:"-"`
}
type metadataOutputService2TestShapeOutputService2TestCaseOperation1Input struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService2TestShapeOutputShape struct {
Blob []byte `type:"blob"`
metadataOutputService2TestShapeOutputShape `json:"-" xml:"-"`
}
type metadataOutputService2TestShapeOutputShape struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService3ProtocolTest struct {
*aws.Service
}
// New returns a new OutputService3ProtocolTest client.
func NewOutputService3ProtocolTest(config *aws.Config) *OutputService3ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "outputservice3protocoltest",
APIVersion: "",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &OutputService3ProtocolTest{service}
}
// newRequest creates a new request for a OutputService3ProtocolTest operation and runs any
// custom request initialization.
func (c *OutputService3ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opOutputService3TestCaseOperation1 = "OperationName"
// OutputService3TestCaseOperation1Request generates a request for the OutputService3TestCaseOperation1 operation.
func (c *OutputService3ProtocolTest) OutputService3TestCaseOperation1Request(input *OutputService3TestShapeOutputService3TestCaseOperation1Input) (req *aws.Request, output *OutputService3TestShapeOutputShape) {
op := &aws.Operation{
Name: opOutputService3TestCaseOperation1,
}
if input == nil {
input = &OutputService3TestShapeOutputService3TestCaseOperation1Input{}
}
req = c.newRequest(op, input, output)
output = &OutputService3TestShapeOutputShape{}
req.Data = output
return
}
func (c *OutputService3ProtocolTest) OutputService3TestCaseOperation1(input *OutputService3TestShapeOutputService3TestCaseOperation1Input) (*OutputService3TestShapeOutputShape, error) {
req, out := c.OutputService3TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type OutputService3TestShapeOutputService3TestCaseOperation1Input struct {
metadataOutputService3TestShapeOutputService3TestCaseOperation1Input `json:"-" xml:"-"`
}
type metadataOutputService3TestShapeOutputService3TestCaseOperation1Input struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService3TestShapeOutputShape struct {
ListMember []*string `type:"list"`
metadataOutputService3TestShapeOutputShape `json:"-" xml:"-"`
}
type metadataOutputService3TestShapeOutputShape struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService4ProtocolTest struct {
*aws.Service
}
// New returns a new OutputService4ProtocolTest client.
func NewOutputService4ProtocolTest(config *aws.Config) *OutputService4ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "outputservice4protocoltest",
APIVersion: "",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &OutputService4ProtocolTest{service}
}
// newRequest creates a new request for a OutputService4ProtocolTest operation and runs any
// custom request initialization.
func (c *OutputService4ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opOutputService4TestCaseOperation1 = "OperationName"
// OutputService4TestCaseOperation1Request generates a request for the OutputService4TestCaseOperation1 operation.
func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1Request(input *OutputService4TestShapeOutputService4TestCaseOperation1Input) (req *aws.Request, output *OutputService4TestShapeOutputShape) {
op := &aws.Operation{
Name: opOutputService4TestCaseOperation1,
}
if input == nil {
input = &OutputService4TestShapeOutputService4TestCaseOperation1Input{}
}
req = c.newRequest(op, input, output)
output = &OutputService4TestShapeOutputShape{}
req.Data = output
return
}
func (c *OutputService4ProtocolTest) OutputService4TestCaseOperation1(input *OutputService4TestShapeOutputService4TestCaseOperation1Input) (*OutputService4TestShapeOutputShape, error) {
req, out := c.OutputService4TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type OutputService4TestShapeOutputService4TestCaseOperation1Input struct {
metadataOutputService4TestShapeOutputService4TestCaseOperation1Input `json:"-" xml:"-"`
}
type metadataOutputService4TestShapeOutputService4TestCaseOperation1Input struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService4TestShapeOutputShape struct {
ListMember []*string `locationNameList:"item" type:"list"`
metadataOutputService4TestShapeOutputShape `json:"-" xml:"-"`
}
type metadataOutputService4TestShapeOutputShape struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService5ProtocolTest struct {
*aws.Service
}
// New returns a new OutputService5ProtocolTest client.
func NewOutputService5ProtocolTest(config *aws.Config) *OutputService5ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "outputservice5protocoltest",
APIVersion: "",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &OutputService5ProtocolTest{service}
}
// newRequest creates a new request for a OutputService5ProtocolTest operation and runs any
// custom request initialization.
func (c *OutputService5ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opOutputService5TestCaseOperation1 = "OperationName"
// OutputService5TestCaseOperation1Request generates a request for the OutputService5TestCaseOperation1 operation.
func (c *OutputService5ProtocolTest) OutputService5TestCaseOperation1Request(input *OutputService5TestShapeOutputService5TestCaseOperation1Input) (req *aws.Request, output *OutputService5TestShapeOutputShape) {
op := &aws.Operation{
Name: opOutputService5TestCaseOperation1,
}
if input == nil {
input = &OutputService5TestShapeOutputService5TestCaseOperation1Input{}
}
req = c.newRequest(op, input, output)
output = &OutputService5TestShapeOutputShape{}
req.Data = output
return
}
func (c *OutputService5ProtocolTest) OutputService5TestCaseOperation1(input *OutputService5TestShapeOutputService5TestCaseOperation1Input) (*OutputService5TestShapeOutputShape, error) {
req, out := c.OutputService5TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type OutputService5TestShapeOutputService5TestCaseOperation1Input struct {
metadataOutputService5TestShapeOutputService5TestCaseOperation1Input `json:"-" xml:"-"`
}
type metadataOutputService5TestShapeOutputService5TestCaseOperation1Input struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService5TestShapeOutputShape struct {
ListMember []*string `type:"list" flattened:"true"`
metadataOutputService5TestShapeOutputShape `json:"-" xml:"-"`
}
type metadataOutputService5TestShapeOutputShape struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService6ProtocolTest struct {
*aws.Service
}
// New returns a new OutputService6ProtocolTest client.
func NewOutputService6ProtocolTest(config *aws.Config) *OutputService6ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "outputservice6protocoltest",
APIVersion: "",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &OutputService6ProtocolTest{service}
}
// newRequest creates a new request for a OutputService6ProtocolTest operation and runs any
// custom request initialization.
func (c *OutputService6ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opOutputService6TestCaseOperation1 = "OperationName"
// OutputService6TestCaseOperation1Request generates a request for the OutputService6TestCaseOperation1 operation.
func (c *OutputService6ProtocolTest) OutputService6TestCaseOperation1Request(input *OutputService6TestShapeOutputService6TestCaseOperation1Input) (req *aws.Request, output *OutputService6TestShapeOutputShape) {
op := &aws.Operation{
Name: opOutputService6TestCaseOperation1,
}
if input == nil {
input = &OutputService6TestShapeOutputService6TestCaseOperation1Input{}
}
req = c.newRequest(op, input, output)
output = &OutputService6TestShapeOutputShape{}
req.Data = output
return
}
func (c *OutputService6ProtocolTest) OutputService6TestCaseOperation1(input *OutputService6TestShapeOutputService6TestCaseOperation1Input) (*OutputService6TestShapeOutputShape, error) {
req, out := c.OutputService6TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type OutputService6TestShapeOutputService6TestCaseOperation1Input struct {
metadataOutputService6TestShapeOutputService6TestCaseOperation1Input `json:"-" xml:"-"`
}
type metadataOutputService6TestShapeOutputService6TestCaseOperation1Input struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService6TestShapeOutputShape struct {
Map map[string]*OutputService6TestShapeStructureType `type:"map"`
metadataOutputService6TestShapeOutputShape `json:"-" xml:"-"`
}
type metadataOutputService6TestShapeOutputShape struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService6TestShapeStructureType struct {
Foo *string `locationName:"foo" type:"string"`
metadataOutputService6TestShapeStructureType `json:"-" xml:"-"`
}
type metadataOutputService6TestShapeStructureType struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService7ProtocolTest struct {
*aws.Service
}
// New returns a new OutputService7ProtocolTest client.
func NewOutputService7ProtocolTest(config *aws.Config) *OutputService7ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "outputservice7protocoltest",
APIVersion: "",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &OutputService7ProtocolTest{service}
}
// newRequest creates a new request for a OutputService7ProtocolTest operation and runs any
// custom request initialization.
func (c *OutputService7ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opOutputService7TestCaseOperation1 = "OperationName"
// OutputService7TestCaseOperation1Request generates a request for the OutputService7TestCaseOperation1 operation.
func (c *OutputService7ProtocolTest) OutputService7TestCaseOperation1Request(input *OutputService7TestShapeOutputService7TestCaseOperation1Input) (req *aws.Request, output *OutputService7TestShapeOutputShape) {
op := &aws.Operation{
Name: opOutputService7TestCaseOperation1,
}
if input == nil {
input = &OutputService7TestShapeOutputService7TestCaseOperation1Input{}
}
req = c.newRequest(op, input, output)
output = &OutputService7TestShapeOutputShape{}
req.Data = output
return
}
func (c *OutputService7ProtocolTest) OutputService7TestCaseOperation1(input *OutputService7TestShapeOutputService7TestCaseOperation1Input) (*OutputService7TestShapeOutputShape, error) {
req, out := c.OutputService7TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type OutputService7TestShapeOutputService7TestCaseOperation1Input struct {
metadataOutputService7TestShapeOutputService7TestCaseOperation1Input `json:"-" xml:"-"`
}
type metadataOutputService7TestShapeOutputService7TestCaseOperation1Input struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService7TestShapeOutputShape struct {
Map map[string]*string `type:"map" flattened:"true"`
metadataOutputService7TestShapeOutputShape `json:"-" xml:"-"`
}
type metadataOutputService7TestShapeOutputShape struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService8ProtocolTest struct {
*aws.Service
}
// New returns a new OutputService8ProtocolTest client.
func NewOutputService8ProtocolTest(config *aws.Config) *OutputService8ProtocolTest {
service := &aws.Service{
Config: aws.DefaultConfig.Merge(config),
ServiceName: "outputservice8protocoltest",
APIVersion: "",
}
service.Initialize()
// Handlers
service.Handlers.Sign.PushBack(v4.Sign)
service.Handlers.Build.PushBack(ec2query.Build)
service.Handlers.Unmarshal.PushBack(ec2query.Unmarshal)
service.Handlers.UnmarshalMeta.PushBack(ec2query.UnmarshalMeta)
service.Handlers.UnmarshalError.PushBack(ec2query.UnmarshalError)
return &OutputService8ProtocolTest{service}
}
// newRequest creates a new request for a OutputService8ProtocolTest operation and runs any
// custom request initialization.
func (c *OutputService8ProtocolTest) newRequest(op *aws.Operation, params, data interface{}) *aws.Request {
req := aws.NewRequest(c.Service, op, params, data)
return req
}
const opOutputService8TestCaseOperation1 = "OperationName"
// OutputService8TestCaseOperation1Request generates a request for the OutputService8TestCaseOperation1 operation.
func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation1Request(input *OutputService8TestShapeOutputService8TestCaseOperation1Input) (req *aws.Request, output *OutputService8TestShapeOutputShape) {
op := &aws.Operation{
Name: opOutputService8TestCaseOperation1,
}
if input == nil {
input = &OutputService8TestShapeOutputService8TestCaseOperation1Input{}
}
req = c.newRequest(op, input, output)
output = &OutputService8TestShapeOutputShape{}
req.Data = output
return
}
func (c *OutputService8ProtocolTest) OutputService8TestCaseOperation1(input *OutputService8TestShapeOutputService8TestCaseOperation1Input) (*OutputService8TestShapeOutputShape, error) {
req, out := c.OutputService8TestCaseOperation1Request(input)
err := req.Send()
return out, err
}
type OutputService8TestShapeOutputService8TestCaseOperation1Input struct {
metadataOutputService8TestShapeOutputService8TestCaseOperation1Input `json:"-" xml:"-"`
}
type metadataOutputService8TestShapeOutputService8TestCaseOperation1Input struct {
SDKShapeTraits bool `type:"structure"`
}
type OutputService8TestShapeOutputShape struct {
Map map[string]*string `locationNameKey:"foo" locationNameValue:"bar" type:"map" flattened:"true"`
metadataOutputService8TestShapeOutputShape `json:"-" xml:"-"`
}
type metadataOutputService8TestShapeOutputShape struct {
SDKShapeTraits bool `type:"structure"`
}
//
// Tests begin here
//
func TestOutputService1ProtocolTestScalarMembersCase1(t *testing.T) {
svc := NewOutputService1ProtocolTest(nil)
buf := bytes.NewReader([]byte("<OperationNameResponse><Str>myname</Str><FooNum>123</FooNum><FalseBool>false</FalseBool><TrueBool>true</TrueBool><Float>1.2</Float><Double>1.3</Double><Long>200</Long><Char>a</Char><RequestId>request-id</RequestId></OperationNameResponse>"))
req, out := svc.OutputService1TestCaseOperation1Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
assert.NoError(t, req.Error)
// assert response
assert.NotNil(t, out) // ensure out variable is used
assert.Equal(t, "a", *out.Char)
assert.Equal(t, 1.3, *out.Double)
assert.Equal(t, false, *out.FalseBool)
assert.Equal(t, 1.2, *out.Float)
assert.Equal(t, int64(200), *out.Long)
assert.Equal(t, int64(123), *out.Num)
assert.Equal(t, "myname", *out.Str)
assert.Equal(t, true, *out.TrueBool)
}
func TestOutputService2ProtocolTestBlobCase1(t *testing.T) {
svc := NewOutputService2ProtocolTest(nil)
buf := bytes.NewReader([]byte("<OperationNameResponse><Blob>dmFsdWU=</Blob><RequestId>requestid</RequestId></OperationNameResponse>"))
req, out := svc.OutputService2TestCaseOperation1Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
assert.NoError(t, req.Error)
// assert response
assert.NotNil(t, out) // ensure out variable is used
assert.Equal(t, "value", string(out.Blob))
}
func TestOutputService3ProtocolTestListsCase1(t *testing.T) {
svc := NewOutputService3ProtocolTest(nil)
buf := bytes.NewReader([]byte("<OperationNameResponse><ListMember><member>abc</member><member>123</member></ListMember><RequestId>requestid</RequestId></OperationNameResponse>"))
req, out := svc.OutputService3TestCaseOperation1Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
assert.NoError(t, req.Error)
// assert response
assert.NotNil(t, out) // ensure out variable is used
assert.Equal(t, "abc", *out.ListMember[0])
assert.Equal(t, "123", *out.ListMember[1])
}
func TestOutputService4ProtocolTestListWithCustomMemberNameCase1(t *testing.T) {
svc := NewOutputService4ProtocolTest(nil)
buf := bytes.NewReader([]byte("<OperationNameResponse><ListMember><item>abc</item><item>123</item></ListMember><RequestId>requestid</RequestId></OperationNameResponse>"))
req, out := svc.OutputService4TestCaseOperation1Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
assert.NoError(t, req.Error)
// assert response
assert.NotNil(t, out) // ensure out variable is used
assert.Equal(t, "abc", *out.ListMember[0])
assert.Equal(t, "123", *out.ListMember[1])
}
func TestOutputService5ProtocolTestFlattenedListCase1(t *testing.T) {
svc := NewOutputService5ProtocolTest(nil)
buf := bytes.NewReader([]byte("<OperationNameResponse><ListMember>abc</ListMember><ListMember>123</ListMember><RequestId>requestid</RequestId></OperationNameResponse>"))
req, out := svc.OutputService5TestCaseOperation1Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
assert.NoError(t, req.Error)
// assert response
assert.NotNil(t, out) // ensure out variable is used
assert.Equal(t, "abc", *out.ListMember[0])
assert.Equal(t, "123", *out.ListMember[1])
}
func TestOutputService6ProtocolTestNormalMapCase1(t *testing.T) {
svc := NewOutputService6ProtocolTest(nil)
buf := bytes.NewReader([]byte("<OperationNameResponse><Map><entry><key>qux</key><value><foo>bar</foo></value></entry><entry><key>baz</key><value><foo>bam</foo></value></entry></Map><RequestId>requestid</RequestId></OperationNameResponse>"))
req, out := svc.OutputService6TestCaseOperation1Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
assert.NoError(t, req.Error)
// assert response
assert.NotNil(t, out) // ensure out variable is used
assert.Equal(t, "bam", *out.Map["baz"].Foo)
assert.Equal(t, "bar", *out.Map["qux"].Foo)
}
func TestOutputService7ProtocolTestFlattenedMapCase1(t *testing.T) {
svc := NewOutputService7ProtocolTest(nil)
buf := bytes.NewReader([]byte("<OperationNameResponse><Map><key>qux</key><value>bar</value></Map><Map><key>baz</key><value>bam</value></Map><RequestId>requestid</RequestId></OperationNameResponse>"))
req, out := svc.OutputService7TestCaseOperation1Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
assert.NoError(t, req.Error)
// assert response
assert.NotNil(t, out) // ensure out variable is used
assert.Equal(t, "bam", *out.Map["baz"])
assert.Equal(t, "bar", *out.Map["qux"])
}
func TestOutputService8ProtocolTestNamedMapCase1(t *testing.T) {
svc := NewOutputService8ProtocolTest(nil)
buf := bytes.NewReader([]byte("<OperationNameResponse><Map><foo>qux</foo><bar>bar</bar></Map><Map><foo>baz</foo><bar>bam</bar></Map><RequestId>requestid</RequestId></OperationNameResponse>"))
req, out := svc.OutputService8TestCaseOperation1Request(nil)
req.HTTPResponse = &http.Response{StatusCode: 200, Body: ioutil.NopCloser(buf), Header: http.Header{}}
// set headers
// unmarshal response
ec2query.UnmarshalMeta(req)
ec2query.Unmarshal(req)
assert.NoError(t, req.Error)
// assert response
assert.NotNil(t, out) // ensure out variable is used
assert.Equal(t, "bam", *out.Map["baz"])
assert.Equal(t, "bar", *out.Map["qux"])
}

View File

@@ -0,0 +1,33 @@
// Package query provides serialisation of AWS query requests, and responses.
package query
//go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/input/query.json build_test.go
import (
"net/url"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/internal/protocol/query/queryutil"
)
// Build builds a request for an AWS Query service.
func Build(r *aws.Request) {
body := url.Values{
"Action": {r.Operation.Name},
"Version": {r.Service.APIVersion},
}
if err := queryutil.Parse(body, r.Params, false); err != nil {
r.Error = awserr.New("SerializationError", "failed encoding Query request", err)
return
}
if r.ExpireTime == 0 {
r.HTTPRequest.Method = "POST"
r.HTTPRequest.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=utf-8")
r.SetBufferBody([]byte(body.Encode()))
} else { // This is a pre-signed request
r.HTTPRequest.Method = "GET"
r.HTTPRequest.URL.RawQuery = body.Encode()
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,223 @@
package queryutil
import (
"encoding/base64"
"fmt"
"net/url"
"reflect"
"sort"
"strconv"
"strings"
"time"
)
// Parse parses an object i and fills a url.Values object. The isEC2 flag
// indicates if this is the EC2 Query sub-protocol.
func Parse(body url.Values, i interface{}, isEC2 bool) error {
q := queryParser{isEC2: isEC2}
return q.parseValue(body, reflect.ValueOf(i), "", "")
}
func elemOf(value reflect.Value) reflect.Value {
for value.Kind() == reflect.Ptr {
value = value.Elem()
}
return value
}
type queryParser struct {
isEC2 bool
}
func (q *queryParser) parseValue(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error {
value = elemOf(value)
// no need to handle zero values
if !value.IsValid() {
return nil
}
t := tag.Get("type")
if t == "" {
switch value.Kind() {
case reflect.Struct:
t = "structure"
case reflect.Slice:
t = "list"
case reflect.Map:
t = "map"
}
}
switch t {
case "structure":
return q.parseStruct(v, value, prefix)
case "list":
return q.parseList(v, value, prefix, tag)
case "map":
return q.parseMap(v, value, prefix, tag)
default:
return q.parseScalar(v, value, prefix, tag)
}
}
func (q *queryParser) parseStruct(v url.Values, value reflect.Value, prefix string) error {
if !value.IsValid() {
return nil
}
t := value.Type()
for i := 0; i < value.NumField(); i++ {
if c := t.Field(i).Name[0:1]; strings.ToLower(c) == c {
continue // ignore unexported fields
}
value := elemOf(value.Field(i))
field := t.Field(i)
var name string
if q.isEC2 {
name = field.Tag.Get("queryName")
}
if name == "" {
if field.Tag.Get("flattened") != "" && field.Tag.Get("locationNameList") != "" {
name = field.Tag.Get("locationNameList")
} else if locName := field.Tag.Get("locationName"); locName != "" {
name = locName
}
if name != "" && q.isEC2 {
name = strings.ToUpper(name[0:1]) + name[1:]
}
}
if name == "" {
name = field.Name
}
if prefix != "" {
name = prefix + "." + name
}
if err := q.parseValue(v, value, name, field.Tag); err != nil {
return err
}
}
return nil
}
func (q *queryParser) parseList(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error {
// If it's empty, generate an empty value
if !value.IsNil() && value.Len() == 0 {
v.Set(prefix, "")
return nil
}
// check for unflattened list member
if !q.isEC2 && tag.Get("flattened") == "" {
prefix += ".member"
}
for i := 0; i < value.Len(); i++ {
slicePrefix := prefix
if slicePrefix == "" {
slicePrefix = strconv.Itoa(i + 1)
} else {
slicePrefix = slicePrefix + "." + strconv.Itoa(i+1)
}
if err := q.parseValue(v, value.Index(i), slicePrefix, ""); err != nil {
return err
}
}
return nil
}
func (q *queryParser) parseMap(v url.Values, value reflect.Value, prefix string, tag reflect.StructTag) error {
// If it's empty, generate an empty value
if !value.IsNil() && value.Len() == 0 {
v.Set(prefix, "")
return nil
}
// check for unflattened list member
if !q.isEC2 && tag.Get("flattened") == "" {
prefix += ".entry"
}
// sort keys for improved serialization consistency.
// this is not strictly necessary for protocol support.
mapKeyValues := value.MapKeys()
mapKeys := map[string]reflect.Value{}
mapKeyNames := make([]string, len(mapKeyValues))
for i, mapKey := range mapKeyValues {
name := mapKey.String()
mapKeys[name] = mapKey
mapKeyNames[i] = name
}
sort.Strings(mapKeyNames)
for i, mapKeyName := range mapKeyNames {
mapKey := mapKeys[mapKeyName]
mapValue := value.MapIndex(mapKey)
kname := tag.Get("locationNameKey")
if kname == "" {
kname = "key"
}
vname := tag.Get("locationNameValue")
if vname == "" {
vname = "value"
}
// serialize key
var keyName string
if prefix == "" {
keyName = strconv.Itoa(i+1) + "." + kname
} else {
keyName = prefix + "." + strconv.Itoa(i+1) + "." + kname
}
if err := q.parseValue(v, mapKey, keyName, ""); err != nil {
return err
}
// serialize value
var valueName string
if prefix == "" {
valueName = strconv.Itoa(i+1) + "." + vname
} else {
valueName = prefix + "." + strconv.Itoa(i+1) + "." + vname
}
if err := q.parseValue(v, mapValue, valueName, ""); err != nil {
return err
}
}
return nil
}
func (q *queryParser) parseScalar(v url.Values, r reflect.Value, name string, tag reflect.StructTag) error {
switch value := r.Interface().(type) {
case string:
v.Set(name, value)
case []byte:
if !r.IsNil() {
v.Set(name, base64.StdEncoding.EncodeToString(value))
}
case bool:
v.Set(name, strconv.FormatBool(value))
case int64:
v.Set(name, strconv.FormatInt(value, 10))
case int:
v.Set(name, strconv.Itoa(value))
case float64:
v.Set(name, strconv.FormatFloat(value, 'f', -1, 64))
case float32:
v.Set(name, strconv.FormatFloat(float64(value), 'f', -1, 32))
case time.Time:
const ISO8601UTC = "2006-01-02T15:04:05Z"
v.Set(name, value.UTC().Format(ISO8601UTC))
default:
return fmt.Errorf("unsupported value for param %s: %v (%s)", name, r.Interface(), r.Type().Name())
}
return nil
}

View File

@@ -0,0 +1,29 @@
package query
//go:generate go run ../../fixtures/protocol/generate.go ../../fixtures/protocol/output/query.json unmarshal_test.go
import (
"encoding/xml"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/internal/protocol/xml/xmlutil"
)
// Unmarshal unmarshals a response for an AWS Query service.
func Unmarshal(r *aws.Request) {
defer r.HTTPResponse.Body.Close()
if r.DataFilled() {
decoder := xml.NewDecoder(r.HTTPResponse.Body)
err := xmlutil.UnmarshalXML(r.Data, decoder, r.Operation.Name+"Result")
if err != nil {
r.Error = awserr.New("SerializationError", "failed decoding Query response", err)
return
}
}
}
// UnmarshalMeta unmarshals header response values for an AWS Query service.
func UnmarshalMeta(r *aws.Request) {
// TODO implement unmarshaling of request IDs
}

View File

@@ -0,0 +1,33 @@
package query
import (
"encoding/xml"
"io"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
)
type xmlErrorResponse struct {
XMLName xml.Name `xml:"ErrorResponse"`
Code string `xml:"Error>Code"`
Message string `xml:"Error>Message"`
RequestID string `xml:"RequestId"`
}
// UnmarshalError unmarshals an error response for an AWS Query service.
func UnmarshalError(r *aws.Request) {
defer r.HTTPResponse.Body.Close()
resp := &xmlErrorResponse{}
err := xml.NewDecoder(r.HTTPResponse.Body).Decode(resp)
if err != nil && err != io.EOF {
r.Error = awserr.New("SerializationError", "failed to decode query XML error response", err)
} else {
r.Error = awserr.NewRequestFailure(
awserr.New(resp.Code, resp.Message, nil),
r.HTTPResponse.StatusCode,
resp.RequestID,
)
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,217 @@
// Package rest provides RESTful serialisation of AWS requests and responses.
package rest
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"net/url"
"path"
"reflect"
"strconv"
"strings"
"time"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
)
// RFC822 returns an RFC822 formatted timestamp for AWS protocols
const RFC822 = "Mon, 2 Jan 2006 15:04:05 GMT"
// Whether the byte value can be sent without escaping in AWS URLs
var noEscape [256]bool
func init() {
for i := 0; i < len(noEscape); i++ {
// AWS expects every character except these to be escaped
noEscape[i] = (i >= 'A' && i <= 'Z') ||
(i >= 'a' && i <= 'z') ||
(i >= '0' && i <= '9') ||
i == '-' ||
i == '.' ||
i == '_' ||
i == '~'
}
}
// Build builds the REST component of a service request.
func Build(r *aws.Request) {
if r.ParamsFilled() {
v := reflect.ValueOf(r.Params).Elem()
buildLocationElements(r, v)
buildBody(r, v)
}
}
func buildLocationElements(r *aws.Request, v reflect.Value) {
query := r.HTTPRequest.URL.Query()
for i := 0; i < v.NumField(); i++ {
m := v.Field(i)
if n := v.Type().Field(i).Name; n[0:1] == strings.ToLower(n[0:1]) {
continue
}
if m.IsValid() {
field := v.Type().Field(i)
name := field.Tag.Get("locationName")
if name == "" {
name = field.Name
}
if m.Kind() == reflect.Ptr {
m = m.Elem()
}
if !m.IsValid() {
continue
}
switch field.Tag.Get("location") {
case "headers": // header maps
buildHeaderMap(r, m, field.Tag.Get("locationName"))
case "header":
buildHeader(r, m, name)
case "uri":
buildURI(r, m, name)
case "querystring":
buildQueryString(r, m, name, query)
}
}
if r.Error != nil {
return
}
}
r.HTTPRequest.URL.RawQuery = query.Encode()
updatePath(r.HTTPRequest.URL, r.HTTPRequest.URL.Path)
}
func buildBody(r *aws.Request, v reflect.Value) {
if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
if payloadName := field.Tag.Get("payload"); payloadName != "" {
pfield, _ := v.Type().FieldByName(payloadName)
if ptag := pfield.Tag.Get("type"); ptag != "" && ptag != "structure" {
payload := reflect.Indirect(v.FieldByName(payloadName))
if payload.IsValid() && payload.Interface() != nil {
switch reader := payload.Interface().(type) {
case io.ReadSeeker:
r.SetReaderBody(reader)
case []byte:
r.SetBufferBody(reader)
case string:
r.SetStringBody(reader)
default:
r.Error = awserr.New("SerializationError",
"failed to encode REST request",
fmt.Errorf("unknown payload type %s", payload.Type()))
}
}
}
}
}
}
func buildHeader(r *aws.Request, v reflect.Value, name string) {
str, err := convertType(v)
if err != nil {
r.Error = awserr.New("SerializationError", "failed to encode REST request", err)
} else if str != nil {
r.HTTPRequest.Header.Add(name, *str)
}
}
func buildHeaderMap(r *aws.Request, v reflect.Value, prefix string) {
for _, key := range v.MapKeys() {
str, err := convertType(v.MapIndex(key))
if err != nil {
r.Error = awserr.New("SerializationError", "failed to encode REST request", err)
} else if str != nil {
r.HTTPRequest.Header.Add(prefix+key.String(), *str)
}
}
}
func buildURI(r *aws.Request, v reflect.Value, name string) {
value, err := convertType(v)
if err != nil {
r.Error = awserr.New("SerializationError", "failed to encode REST request", err)
} else if value != nil {
uri := r.HTTPRequest.URL.Path
uri = strings.Replace(uri, "{"+name+"}", EscapePath(*value, true), -1)
uri = strings.Replace(uri, "{"+name+"+}", EscapePath(*value, false), -1)
r.HTTPRequest.URL.Path = uri
}
}
func buildQueryString(r *aws.Request, v reflect.Value, name string, query url.Values) {
str, err := convertType(v)
if err != nil {
r.Error = awserr.New("SerializationError", "failed to encode REST request", err)
} else if str != nil {
query.Set(name, *str)
}
}
func updatePath(url *url.URL, urlPath string) {
scheme, query := url.Scheme, url.RawQuery
hasSlash := strings.HasSuffix(urlPath, "/")
// clean up path
urlPath = path.Clean(urlPath)
if hasSlash && !strings.HasSuffix(urlPath, "/") {
urlPath += "/"
}
// get formatted URL minus scheme so we can build this into Opaque
url.Scheme, url.Path, url.RawQuery = "", "", ""
s := url.String()
url.Scheme = scheme
url.RawQuery = query
// build opaque URI
url.Opaque = s + urlPath
}
// EscapePath escapes part of a URL path in Amazon style
func EscapePath(path string, encodeSep bool) string {
var buf bytes.Buffer
for i := 0; i < len(path); i++ {
c := path[i]
if noEscape[c] || (c == '/' && !encodeSep) {
buf.WriteByte(c)
} else {
buf.WriteByte('%')
buf.WriteString(strings.ToUpper(strconv.FormatUint(uint64(c), 16)))
}
}
return buf.String()
}
func convertType(v reflect.Value) (*string, error) {
v = reflect.Indirect(v)
if !v.IsValid() {
return nil, nil
}
var str string
switch value := v.Interface().(type) {
case string:
str = value
case []byte:
str = base64.StdEncoding.EncodeToString(value)
case bool:
str = strconv.FormatBool(value)
case int64:
str = strconv.FormatInt(value, 10)
case float64:
str = strconv.FormatFloat(value, 'f', -1, 64)
case time.Time:
str = value.UTC().Format(RFC822)
default:
err := fmt.Errorf("Unsupported value for param %v (%s)", v.Interface(), v.Type())
return nil, err
}
return &str, nil
}

View File

@@ -0,0 +1,45 @@
package rest
import "reflect"
// PayloadMember returns the payload field member of i if there is one, or nil.
func PayloadMember(i interface{}) interface{} {
if i == nil {
return nil
}
v := reflect.ValueOf(i).Elem()
if !v.IsValid() {
return nil
}
if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
if payloadName := field.Tag.Get("payload"); payloadName != "" {
field, _ := v.Type().FieldByName(payloadName)
if field.Tag.Get("type") != "structure" {
return nil
}
payload := v.FieldByName(payloadName)
if payload.IsValid() || (payload.Kind() == reflect.Ptr && !payload.IsNil()) {
return payload.Interface()
}
}
}
return nil
}
// PayloadType returns the type of a payload field member of i if there is one, or "".
func PayloadType(i interface{}) string {
v := reflect.Indirect(reflect.ValueOf(i))
if !v.IsValid() {
return ""
}
if field, ok := v.Type().FieldByName("SDKShapeTraits"); ok {
if payloadName := field.Tag.Get("payload"); payloadName != "" {
if member, ok := v.Type().FieldByName(payloadName); ok {
return member.Tag.Get("type")
}
}
}
return ""
}

Some files were not shown because too many files have changed in this diff Show More