├── .github └── workflows │ └── node.js.yml ├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTION.md ├── LICENSE ├── README.md ├── example.js ├── grafana.png ├── grafana ├── alert │ ├── alert.js │ ├── condition.js │ └── index.js ├── annotations │ ├── graphite.js │ └── index.js ├── config.js ├── dashboard.js ├── errors.js ├── external-link.js ├── id.js ├── panels │ ├── dashboard_list.js │ ├── graph.js │ ├── index.js │ ├── singlestat.js │ ├── table.js │ └── text.js ├── publish.js ├── row.js ├── target.js └── templates │ ├── custom.js │ ├── index.js │ └── query.js ├── index.js ├── package-lock.json ├── package.json └── test ├── alert ├── alert.js ├── condition.js └── index.js ├── annotations ├── graphite.js └── index.js ├── config.js ├── dashboard.js ├── external-link.js ├── fixtures ├── alert │ ├── alert.mock.js │ ├── alert_with_condition.js │ ├── simple_alert.js │ └── simple_condition.js ├── annotations │ ├── override_graphite.js │ └── simple_graphite.js ├── external_link.js ├── override_dashboard.js ├── override_row.js ├── panels │ ├── graph_with_alert.js │ ├── override_dashboard_list.js │ ├── override_graph.js │ ├── override_singlestat.js │ ├── override_table.js │ ├── override_text.js │ ├── simple_dashboard_list.js │ ├── simple_graph.js │ ├── simple_singlestat.js │ ├── simple_table.js │ └── simple_text.js ├── simple_dashboard.js ├── simple_row.js └── templates │ ├── override_custom.js │ ├── override_custom_text_value.js │ ├── override_query.js │ ├── simple_custom.js │ └── simple_query.js ├── index.js ├── panels ├── dashboard_list.js ├── graph.js ├── index.js ├── singlestat.js ├── table.js └── text.js ├── publish.js ├── row.js ├── target.js └── templates ├── custom.js ├── index.js └── query.js /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [10.x, 12.x, 14.x, 16.x, 18.x] 20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 21 | 22 | steps: 23 | - uses: actions/checkout@v2 24 | - name: Use Node.js ${{ matrix.node-version }} 25 | uses: actions/setup-node@v2 26 | with: 27 | node-version: ${{ matrix.node-version }} 28 | cache: 'npm' 29 | - run: npm ci 30 | - run: npm run build --if-present 31 | - run: npm test 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | coverage 4 | .nyc_output 5 | npm-debug.log 6 | .idea 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | CHANGELOG 2 | ========= 3 | 4 | v4.0.1 (2023-08-22) 5 | ------------------- 6 | 7 | - Fix `current` type bug in custom templates against newer versions of grafana 8 | - Slim down published NPM package 9 | 10 | 11 | v4.0.0 (2023-08-20) 12 | ------------------- 13 | 14 | - **Breaking change:** `publish` now returns a promise with either a `node-fetch` `Response` or an `SError` from the `error` package 15 | - **Breaking change:** thrown errors are from the upgraded `error@10` `SError` type instead of the `error@7` `TypedError` package 16 | - Dependency updates 17 | -------------------------------------------------------------------------------- /CONTRIBUTION.md: -------------------------------------------------------------------------------- 1 | # Want to contribute? 2 | 3 | Great! That's why this is an open source project. We use this project in our infrastructure at Uber, and we hope that it's useful to others as well. 4 | 5 | Before you get started, here are some suggestions: 6 | 7 | - Check open issues for what you want. 8 | - If there is an open issue, comment on it. Otherwise open an issue describing your bug or feature with use cases. 9 | - Before undertaking a major change, please discuss this on the issue. We'd hate to see you spend a lot of time working on something that conflicts with other goals or requirements that might not be obvious. 10 | - Write code to fix the problem, then open a pull request with tests and documentation. 11 | - The pull requests gets reviewed and then merged assuming there are no problems. 12 | - A new release version gets cut. 13 | 14 | ## Licencing 15 | 16 | - Every file must have a licence block at the top. This is enforced using `uber-licence` 17 | - If you contribute to a file in this project and are not an Uber employee, then you should add your name to the copyright section of the licence file. 18 | - Work that you contribute must be your own. 19 | 20 | ## Releases 21 | 22 | Declaring formal releases requires peer review. 23 | 24 | - A reviewer of a pull request should recommend a new version number (patch, minor or major). 25 | - Once your change is merged feel free to bump the version as recommended by the reviewer. 26 | - A new version number should not be cut without peer review unless done by the project maintainer. 27 | 28 | ### Cutting a new version 29 | 30 | - Get your branch merged on master 31 | - Run `npm version major` or `npm version minor` or `npm version patch` 32 | - `git push origin master --tags` 33 | - If you are a project owner, then `npm publish` 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Uber 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Grafana Dash Gen 2 | 3 | [![Node.js CI](https://github.com/uber/grafana-dash-gen/actions/workflows/node.js.yml/badge.svg)](https://github.com/uber/grafana-dash-gen/actions/workflows/node.js.yml) 4 | 5 | A collection of utility classes to construct and publish grafana graphs. The library is built ground up to incorporate grafana terminologies. 6 | 7 | - **Dashboard**: Represents the final dashboard that is displayed. 8 | - **Row**: A row in grafana. Dashboard consists or many rows. 9 | - **Panel**: A visual display item. A panel could be a graph, single stat or others. A row consists of many panels. 10 | - **Target**: A dot separated graphite string. E.g, a.b.count. A Panel consists of many targets. 11 | - **Annotations**: Lined markers that will annotate a graph (panel). A Dashboard can have annotations added to it. 12 | - **Templates**: Variables that can be included in the state. E.g, a.$dc.b.count (to switch between datacenters). A Dashboard can have templates added to it. 13 | 14 | ![Alt text](/grafana.png?raw=true "Optional Title") 15 | 16 | ## Code to generate the dashboard 17 | 18 | You will be able to generate and publish a grafana graph using the following steps. 19 | 20 | #### Step 1: Configure grafana 21 | if you would like grafana to publish your dashboard you need this step. If you do not need grafana to publish your dashboard, you can skip this step. 22 | ```js 23 | const grafana = require('grafana-dash-gen'); 24 | const Row = grafana.Row; 25 | const Dashboard = grafana.Dashboard; 26 | const Panels = grafana.Panels; 27 | const Target = grafana.Target; 28 | const Templates = grafana.Templates; 29 | const Alert = grafana.Alert; 30 | const Condition = grafana.Condition; 31 | 32 | grafana.configure({ 33 | url: 'https://your.grafana.com/elasticsearch/grafana-dash/dashboard/', 34 | cookie: 'auth-openid=someidhere' 35 | }); 36 | ``` 37 | #### Step 2: Create a dashboard 38 | ```js 39 | const dashboard = new Dashboard({ 40 | title: 'Api dashboard' 41 | }); 42 | ``` 43 | (or) Below is an example of a dashboard with a custom slug, templates `dc` and `smoothing` and annotations. 44 | ```js 45 | const dashboard = new Dashboard({ 46 | title: 'Api dashboard', 47 | slug: 'api', 48 | templating: [{ 49 | name: 'dc', 50 | options: ['dc1', 'dc2'] 51 | }, { 52 | name: 'smoothing', 53 | options: ['30min', '10min', '5min', '2min', '1min'] 54 | }], 55 | annotations: [{ 56 | name: 'Deploy', 57 | target: 'stats.$dc.production.deploy' 58 | }] 59 | }); 60 | ``` 61 | 62 | If you do not wish to have any templates and annotations 63 | 64 | #### Step 3: Create a new row 65 | As said abolve, grafana dashboard contains a number of rows. 66 | ```js 67 | const row = new Row(); 68 | ``` 69 | 70 | #### Step 4: Create graphs to add to the row 71 | There are two ways to add the graph to a row. Pass it while a graph is created as below 72 | ```js 73 | const panel = new Panels.Graph({ 74 | title: 'api req/sec', 75 | span: 5, 76 | targets: [ 77 | new Target('api.statusCode.*'). 78 | transformNull(0).sum().hitcount('1seconds').scale(0.1).alias('rps') 79 | ], 80 | row: row, 81 | dashboard: dashboard 82 | }); 83 | ``` 84 | 85 | (or) add it in a separate step 86 | ```js 87 | const panel = new Panels.Graph({ 88 | title: 'api req/sec', 89 | span: 5, 90 | targets: [ 91 | new Target('api.statusCode.*'). 92 | transformNull(0).sum().hitcount('1seconds').scale(0.1).alias('rps') 93 | ] 94 | }); 95 | row.addPanel(panel); 96 | ``` 97 | 98 | If you would like to create a full width single stat (as in the image) the code is below. Notice how we create a new row on the fly. 99 | ```js 100 | const requestVolume = new Panels.SingleStat({ 101 | title: 'Current Request Volume', 102 | postfix: 'req/sec', 103 | targets: [ 104 | new Target('stats.$dc.counts'). 105 | sum().scale(0.1) 106 | ], 107 | row: new Row(), 108 | dashboard: dashboard 109 | }); 110 | ``` 111 | 112 | #### Step 5: Create an alert and add it to the graph 113 | _Alerts are optional_. An alert is set on a target, each target added to the panel receives a refId of 'A', 'B', ..., 'Z'. 114 | ```js 115 | const conditionOnRequestLowVolume = new Condition() 116 | .onQuery('A') 117 | .withEvaluator(1, 'lt') 118 | .withReducer('max'); 119 | 120 | const alert = new Alert({ name: 'Low volume of requests' }); 121 | alert.addCondition(conditionOnRequestLowVolume); 122 | 123 | // OR 124 | 125 | const alert = new Alert({ name: 'Low volume of requests' }) 126 | .addCondition(conditionOnRequestLowVolume); 127 | 128 | requestVolume.addAlert(alert); 129 | ``` 130 | 131 | It is also possible to add an alert by passing it to the Graph constructor 132 | ```js 133 | const graphWithAnAlert = new Graph({ alert: YOUR_ALERT_OBJECT }); 134 | ``` 135 | 136 | #### Step 6: Publish the graph 137 | ```js 138 | grafana.publish(dashboard); 139 | ``` 140 | 141 | to generate the json and not publish use 142 | 143 | ```js 144 | console.log(JSON.stringify(dashboard.generate())); 145 | ``` 146 | 147 | **A complete example of a dashboard is provided in example.js** 148 | 149 | 150 | ----- 151 | 152 | ## Installation 153 | 154 | `npm install grafana-dash-gen` 155 | 156 | ## Tests 157 | 158 | `npm test` 159 | 160 | ## Contributors 161 | 162 | - Evan Culver 163 | - Madan Thangavelu 164 | 165 | ## MIT Licenced 166 | 167 | 168 | -------------------------------------------------------------------------------- /example.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var grafana = require('./index'); 4 | var Row = grafana.Row; 5 | var Dashboard = grafana.Dashboard; 6 | var Panels = grafana.Panels; 7 | var Target = grafana.Target; 8 | var Alert = grafana.Alert; 9 | var Condition = grafana.Condition; 10 | 11 | // For grafana v1, the URL should look something like: 12 | // 13 | // https://your.grafana.com/elasticsearch/grafana-dash/dashboard/ 14 | // 15 | // Bascially, grafana v1 used elastic search as its backend, but grafana v2 16 | // has its own backend. Because of this, the URL for grafana v2 should look 17 | // something like this: 18 | // 19 | // https://your.grafanahost.com/grafana2/api/dashboards/db/ 20 | 21 | grafana.configure({ 22 | url: 'https://your.grafanahost.com/grafana2/api/dashboards/db/', 23 | cookie: 'auth-openid=REPLACETOKENIFAPPLICABLE', 24 | headers: {'x': 'y'} 25 | }); 26 | 27 | // Dashboard Constants 28 | var TITLE = 'TEST API dashboard'; 29 | var TAGS = ['myapp', 'platform']; 30 | var TEMPLATING = [{ 31 | name: 'dc', 32 | options: ['dc1', 'dc2'] 33 | }, { 34 | name: 'smoothing', 35 | options: ['30min', '10min', '5min', '2min', '1min'] 36 | }]; 37 | var ANNOTATIONS = [{ 38 | name: 'Deploy', 39 | target: 'stats.$dc.production.deploy' 40 | }]; 41 | var REFRESH = '1m'; 42 | 43 | // Target prefixes 44 | var SERVER_PREFIX = 'servers.app*-$dc.myapp.'; 45 | var COUNT_PREFIX = 'stats.$dc.counts.myapp.'; 46 | 47 | function generateDashboard() { 48 | // Rows 49 | var volumeRow = new Row({ 50 | title: 'Request Volume' 51 | }); 52 | var systemRow = new Row({ 53 | title: 'System / OS' 54 | }); 55 | 56 | // Panels: request volume 57 | var rpsGraphPanel = new Panels.Graph({ 58 | title: 'req/sec', 59 | span: 8, 60 | targets: [ 61 | new Target(COUNT_PREFIX + 'statusCode.*'). 62 | transformNull(0). 63 | sum(). 64 | hitcount('1seconds'). 65 | scale(0.1). 66 | alias('rps') 67 | ] 68 | }); 69 | 70 | // set alert on request volume when it's (max) value is lower than 1 req / sec 71 | var condition = new Condition() 72 | .withReducer('max') 73 | .withEvaluator(1, 'lt') 74 | .onQuery('A'); 75 | 76 | var alert = new Alert() 77 | .addCondition(condition); 78 | 79 | rpsGraphPanel.addAlert(alert); 80 | 81 | var rpsStatPanel = new Panels.SingleStat({ 82 | title: 'Current Request Volume', 83 | postfix: 'req/sec', 84 | span: 4, 85 | targets: [ 86 | new Target(COUNT_PREFIX + 'statusCode.*'). 87 | sum(). 88 | scale(0.1) 89 | ] 90 | }); 91 | 92 | var favDashboardList = new Panels.DashboardList({ 93 | title: 'My Favorite Dashboard', 94 | span: 4, 95 | mode: 'search', 96 | query: 'dashboard list' 97 | }); 98 | 99 | // Panels: system health 100 | var cpuGraph = new Panels.Graph({ 101 | title: 'CPU', 102 | span: 4, 103 | targets: [ 104 | new Target(SERVER_PREFIX + 'cpu.user'). 105 | nonNegativeDerivative(). 106 | scale(1 / 60). 107 | scale(100). 108 | averageSeries(). 109 | alias('avg'), 110 | new Target(SERVER_PREFIX + 'cpu.user'). 111 | nonNegativeDerivative(). 112 | scale(1 / 60). 113 | scale(100). 114 | percentileOfSeries(95, false). 115 | alias('p95') 116 | ] 117 | }); 118 | var rssGraph = new Panels.Graph({ 119 | title: 'Memory', 120 | span: 4, 121 | targets: [ 122 | new Target(SERVER_PREFIX + 'memory.rss'). 123 | averageSeries(). 124 | alias('rss') 125 | ] 126 | }); 127 | var fdsGraph = new Panels.Graph({ 128 | title: 'FDs', 129 | span: 4, 130 | targets: [ 131 | new Target(SERVER_PREFIX + 'fds'). 132 | averageSeries(). 133 | movingAverage('10min'). 134 | alias('moving avg') 135 | ] 136 | }); 137 | 138 | // Dashboard 139 | var dashboard = new Dashboard({ 140 | title: TITLE, 141 | tags: TAGS, 142 | templating: TEMPLATING, 143 | annotations: ANNOTATIONS, 144 | refresh: REFRESH 145 | }); 146 | 147 | // Layout: panels 148 | volumeRow.addPanel(rpsGraphPanel); 149 | volumeRow.addPanel(rpsStatPanel); 150 | volumeRow.addPanel(favDashboardList); 151 | systemRow.addPanel(cpuGraph); 152 | systemRow.addPanel(rssGraph); 153 | systemRow.addPanel(fdsGraph); 154 | 155 | // Layout: rows 156 | dashboard.addRow(volumeRow); 157 | dashboard.addRow(systemRow); 158 | 159 | // Finish 160 | grafana.publish(dashboard); 161 | } 162 | 163 | module.exports = { 164 | generate: generateDashboard 165 | }; 166 | 167 | if (require.main === module) { 168 | generateDashboard(); 169 | } 170 | -------------------------------------------------------------------------------- /grafana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/uber/grafana-dash-gen/3e265ce8849dc584d85feb26387bb2c4e4d32757/grafana.png -------------------------------------------------------------------------------- /grafana/alert/alert.js: -------------------------------------------------------------------------------- 1 | function Alert(opts) { 2 | opts = opts || {}; 3 | this.conditions = []; 4 | 5 | this.state = { 6 | name: 'Panel Title alert', 7 | for: '15m', 8 | frequency: '5m', 9 | conditions: [], 10 | message: '', 11 | notifications: [], 12 | executionErrorState: 'keep_state', 13 | noDataState: 'keep_state', 14 | alertRuleTags: {}, 15 | handler: 1, 16 | }; 17 | 18 | this._init(opts); 19 | this._initConditions(opts); 20 | } 21 | 22 | Alert.prototype._init = function _init(opts) { 23 | const self = this; 24 | 25 | Object.keys(opts).forEach(function eachOpt(opt) { 26 | self.state[opt] = opts[opt]; 27 | }); 28 | } 29 | 30 | Alert.prototype._initConditions = function _initConditions(opts) { 31 | var self = this; 32 | this.state.conditions = this.state.conditions || []; 33 | 34 | if (opts.conditions) { 35 | self.conditions = self.conditions.concat(opts.conditions); 36 | } 37 | }; 38 | 39 | Alert.prototype.addCondition = function addCondition(condition) { 40 | this.conditions.push(condition); 41 | return this; 42 | }; 43 | 44 | Alert.prototype.generate = function generate() { 45 | this.state.conditions = this.conditions.map(condition => condition.generate()); 46 | return this.state; 47 | }; 48 | 49 | module.exports = Alert; 50 | -------------------------------------------------------------------------------- /grafana/alert/condition.js: -------------------------------------------------------------------------------- 1 | function Condition(opts) { 2 | opts = opts || {}; 3 | 4 | const that = this; 5 | that.state = {}; 6 | 7 | this._evaluator = { 8 | params: [], 9 | type: 'gt', 10 | }; 11 | 12 | this._operator = { 13 | type: 'and', 14 | }; 15 | 16 | this._query = { 17 | params: ['A', '5m', 'now'], 18 | }; 19 | 20 | this._reducer = { 21 | params: [], 22 | type: 'avg' 23 | }; 24 | 25 | Object.keys(opts).forEach(function eachOpt(opt) { 26 | that.state[opt] = opts[opt]; 27 | }); 28 | 29 | function withEvaluator(value, type) { 30 | const types = ['gt', 'lt', 'within_range']; 31 | 32 | if (!types.includes(type)) { 33 | throw Error(`Evaluator type must be one of [${types.toString()}]`); 34 | } 35 | 36 | that._evaluator.type = type; 37 | 38 | if (['gt', 'lt'].includes(type)) { 39 | that._evaluator.params = [value]; 40 | } else if (Array.isArray(value)) { 41 | that._evaluator.params = value; 42 | } 43 | 44 | return this; 45 | } 46 | 47 | function withOperator(operator) { 48 | const types = ['and', 'or']; 49 | 50 | if (!types.includes(operator)) { 51 | throw Error(`Operator must be one of [${types.toString}]`); 52 | } 53 | 54 | that._operator.type = operator; 55 | return this; 56 | } 57 | 58 | function orCondition() { 59 | that._operator.type = 'or'; 60 | return this; 61 | } 62 | 63 | function andCondition() { 64 | that._operator.type = 'and'; 65 | return this; 66 | } 67 | 68 | function onQuery(query, duration, from) { 69 | if (typeof query !== 'string') { 70 | throw Error('Query identifier must be a string. eg. "A" or "B", etc...'); 71 | } 72 | that._query.params[0] = query; 73 | that._query.params[1] = duration; 74 | that._query.params[2] = from; 75 | 76 | return this; 77 | } 78 | 79 | function withReducer(type) { 80 | const types = ['min', 'max', 'sum', 'avg', 'count', 'last', 'median', 'diff']; 81 | 82 | if (!types.includes(type)) { 83 | throw Error(`Reducer has to be one of [${types.toString()}]`); 84 | } 85 | 86 | that._reducer.type = type; 87 | return this; 88 | } 89 | 90 | function generate() { 91 | return Object.assign({}, { 92 | evaluator: that._evaluator, 93 | operator: that._operator, 94 | query: that._query, 95 | reducer: that._reducer, 96 | type: 'query', 97 | }, 98 | that.state); 99 | } 100 | 101 | return { 102 | withEvaluator, 103 | withOperator, 104 | withReducer, 105 | orCondition, 106 | andCondition, 107 | onQuery, 108 | generate, 109 | } 110 | } 111 | 112 | module.exports = Condition; 113 | -------------------------------------------------------------------------------- /grafana/alert/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Alert = require('./alert'); 4 | var Condition = require('./condition'); 5 | 6 | module.exports = { 7 | Alert: Alert, 8 | Condition: Condition, 9 | }; 10 | -------------------------------------------------------------------------------- /grafana/annotations/graphite.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var errors = require('../errors'); 24 | 25 | function Graphite(opts) { 26 | opts = opts || {}; 27 | var self = this; 28 | 29 | if (!opts.name) { 30 | throw errors.UnfulfilledRequirement( 31 | "{component} missing requirement: {unfulfilledArg}", 32 | { 33 | component: 'grafana.annotations.Graphite', 34 | unfulfilledArg: 'name' 35 | } 36 | ); 37 | } 38 | 39 | if (!opts.target) { 40 | throw errors.UnfulfilledRequirement( 41 | "{component} missing requirement: {unfulfilledArg}", 42 | { 43 | component: 'grafana.annotations.Graphite', 44 | unfulfilledArg: 'target' 45 | } 46 | ); 47 | } 48 | 49 | var defaults = { 50 | name: 'no name', 51 | datasource: 'graphite', 52 | showLine: true, 53 | iconColor: 'rgb(255, 234, 0)', 54 | lineColor: 'rgba(165, 161, 70, 0.59)', 55 | iconSize: 10, 56 | enable: true, 57 | target: '' 58 | }; 59 | self.state = defaults; 60 | 61 | // Overwrite defaults with custom values 62 | Object.keys(opts).forEach(function eachOpt(opt) { 63 | self.state[opt] = opts[opt]; 64 | }); 65 | } 66 | 67 | Graphite.prototype.generate = function generate() { 68 | return this.state; 69 | }; 70 | 71 | module.exports = Graphite; 72 | -------------------------------------------------------------------------------- /grafana/annotations/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var Graphite = require('./graphite'); 24 | 25 | module.exports = { 26 | Graphite: Graphite 27 | }; 28 | -------------------------------------------------------------------------------- /grafana/config.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | var xtend = require('xtend'); 23 | 24 | /** 25 | * `user` - Auth user, defaults to "guest" 26 | * `group` - Auth group, defaults to "guest" 27 | * `url` - Full URL to grafana's elasticsearch endpoint 28 | * `cookie` - Key/value pair for auth, defaults to"auth-openid=" 29 | * `headers` - Map of header keys/values, defaults to no headers 30 | */ 31 | var configurations = { 32 | user: 'guest', 33 | group: 'guest', 34 | url: 'https://your.graphite.url.com/elasticsearch/grafana-dash/dashboard/', 35 | cookie: 'auth-openid=', 36 | headers: {} 37 | }; 38 | 39 | function configure(opts) { 40 | configurations = xtend(configurations, opts); 41 | } 42 | 43 | function getConfig() { 44 | return configurations; 45 | } 46 | 47 | module.exports = { 48 | configure: configure, 49 | getConfig: getConfig 50 | }; 51 | -------------------------------------------------------------------------------- /grafana/dashboard.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var Templates = require('./templates'); 24 | var Annotations = require('./annotations'); 25 | var ExternalLink = require('./external-link') 26 | 27 | function Dashboard(opts) { 28 | opts = opts || {}; 29 | this.state = {}; 30 | this._init(opts); 31 | this._initRows(opts); 32 | this._initLinks(opts); 33 | this._initTemplating(opts); 34 | this._initAnnotations(opts); 35 | } 36 | 37 | Dashboard.prototype._init = function _init(opts) { 38 | this.state = this.state; 39 | this.state.id = opts.id || null; 40 | this.state.title = opts.title || 'Generated Grafana Dashboard'; 41 | this.state.originalTitle = opts.originalTitle || 'Generated Dashboard'; 42 | this.state.tags = opts.tags || []; 43 | this.state.style = opts.style || 'dark'; 44 | this.state.timezone = opts.timezone || 'browser'; 45 | this.state.editable = true; 46 | this.state.hideControls = !!opts.hideControls; 47 | this.state.sharedCrosshair = !!opts.sharedCrosshair; 48 | this.state.refresh = opts.refresh || false; 49 | this.state.schemaVersion = opts.schemaVersion || 6; 50 | this.state.hideAllLegends = !!opts.hideAllLegends; 51 | this.state.time = opts.time || null; 52 | if("editable" in opts) { 53 | this.state.editable = opts.editable; 54 | } 55 | }; 56 | 57 | Dashboard.prototype._initRows = function _initRows(opts) { 58 | var self = this; 59 | 60 | this.rows = []; 61 | this.state.rows = []; 62 | 63 | if (opts.rows) { 64 | opts.rows.forEach(function r(row) { 65 | self.addRow(row); 66 | }); 67 | } 68 | }; 69 | 70 | Dashboard.prototype._initLinks = function _initLinks(opts) { 71 | this.links = opts.links || []; 72 | this.state.links = []; 73 | }; 74 | 75 | Dashboard.prototype._initTemplating = function _initRows(opts) { 76 | var self = this; 77 | 78 | this.state.templating = { 79 | list: [], 80 | enable: true 81 | }; 82 | 83 | if (opts.templating) { 84 | opts.templating.forEach(function temp(template) { 85 | template = new Templates.Custom(template); 86 | self.addTemplate(template); 87 | }); 88 | } 89 | }; 90 | 91 | Dashboard.prototype._initAnnotations = function _initAnnotations(opts) { 92 | var self = this; 93 | 94 | this.state.annotations = { 95 | list: [], 96 | enable: true 97 | }; 98 | 99 | if (opts.annotations) { 100 | opts.annotations.forEach(function temp(annotation) { 101 | annotation = new Annotations.Graphite(annotation); 102 | self.addAnnotation(annotation); 103 | }); 104 | } 105 | }; 106 | 107 | Dashboard.prototype.addRow = function addRow(row) { 108 | this.rows.push(row); 109 | }; 110 | 111 | Dashboard.prototype.addTemplate = function addTemplate(template) { 112 | this.state.templating.list.push(template.generate()); 113 | }; 114 | 115 | Dashboard.prototype.addAnnotation = function addAnnotation(annotation) { 116 | this.state.annotations.list.push(annotation.generate()); 117 | }; 118 | 119 | Dashboard.prototype.generate = function generate() { 120 | // Generate jsons. 121 | this.state.rows = this.rows.map(row => row.generate()); 122 | this.state.links = this.links.map(link => { 123 | if (link instanceof ExternalLink) { 124 | return link.generate() 125 | } 126 | return link 127 | }); 128 | 129 | return this.state; 130 | }; 131 | 132 | module.exports = Dashboard; 133 | -------------------------------------------------------------------------------- /grafana/errors.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | var SError = require('error').SError; 23 | 24 | class UnfulfilledRequirement extends SError {}; 25 | class InvalidState extends SError {}; 26 | class Misconfigured extends SError {}; 27 | class ResponseError extends SError {}; 28 | 29 | module.exports = { 30 | UnfulfilledRequirement: UnfulfilledRequirement, 31 | InvalidState: InvalidState, 32 | Misconfigured: Misconfigured, 33 | ResponseError: ResponseError 34 | }; 35 | -------------------------------------------------------------------------------- /grafana/external-link.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | function ExternalLink(opts) { 24 | opts = opts || {}; 25 | 26 | const defaults = { 27 | title: "", 28 | tooltip: "", 29 | url: "", 30 | ...opts, 31 | tags: [], 32 | icon: "external link", 33 | targetBlank: true, 34 | type: "link", 35 | includeVars: false, 36 | keepTime: false, 37 | }; 38 | this.state = defaults; 39 | } 40 | 41 | ExternalLink.prototype.generate = function generate() { 42 | if (this.state.title === "") { 43 | throw new SyntaxError("a title for the link must be provided") 44 | } 45 | if (this.state.url === "") { 46 | throw new SyntaxError("a url for the link must be provided") 47 | } 48 | return this.state; 49 | }; 50 | 51 | ExternalLink.prototype.includeVariableValues = function includeVariableValues() { 52 | this.state.includeVars = true; 53 | return this 54 | }; 55 | 56 | ExternalLink.prototype.includeTimeFilter = function includeTimeFilter() { 57 | this.state.keepTime = true; 58 | return this 59 | }; 60 | 61 | ExternalLink.prototype.withIcon = function withIcon(iconName) { 62 | this.state.icon = iconName; 63 | return this 64 | }; 65 | 66 | module.exports = ExternalLink; 67 | -------------------------------------------------------------------------------- /grafana/id.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | // Used to provide unique if for 24 | // generated graphs 25 | 26 | var graphId = 0; 27 | function generateGraphId() { 28 | graphId = graphId + 1; 29 | return graphId; 30 | } 31 | 32 | module.exports = generateGraphId; 33 | -------------------------------------------------------------------------------- /grafana/panels/dashboard_list.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var generateGraphId = require('../id'); 24 | 25 | function DashboardList(opts) { 26 | opts = opts || {}; 27 | var self = this; 28 | 29 | this.state = { 30 | title: 'dashboard list', 31 | error: false, 32 | span: 3, 33 | editable: true, 34 | type: 'dashlist', 35 | isNew: true, 36 | id: generateGraphId(), 37 | mode: 'search', 38 | query: 'dashboard list', 39 | limit: 10, 40 | tags: [], 41 | links: [] 42 | }; 43 | 44 | // Overwrite defaults with custom values 45 | Object.keys(opts).forEach(function eachOpt(opt) { 46 | self.state[opt] = opts[opt]; 47 | }); 48 | 49 | // finally add to row/dashboard if given 50 | if (opts.row && opts.dashboard) { 51 | opts.row.addPanel(this); 52 | opts.dashboard.addRow(opts.row); 53 | } 54 | } 55 | 56 | DashboardList.prototype.setTitle = function setTitle(title) { 57 | this.state.title = title; 58 | }; 59 | 60 | DashboardList.prototype.generate = function generate() { 61 | return this.state; 62 | }; 63 | 64 | module.exports = DashboardList; 65 | -------------------------------------------------------------------------------- /grafana/panels/graph.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | const generateGraphId = require('../id'); 24 | 25 | function Graph(opts) { 26 | opts = opts || {}; 27 | const self = this; 28 | this._currentRefIndex = 0; 29 | 30 | const defaults = { 31 | 'type': 'graph', 32 | 'id': generateGraphId(), 33 | 'renderer': 'flot', 34 | 'title': 'no title (click here)', 35 | 'error': false, 36 | 'editable': true, 37 | 'x-axis': true, 38 | 'y-axis': true, 39 | 'y_formats': [ 40 | 'short', 41 | 'short' 42 | ], 43 | 'grid': { 44 | 'leftMax': null, 45 | 'rightMax': null, 46 | 'leftMin': null, 47 | 'rightMin': null, 48 | 'threshold1': null, 49 | 'threshold2': null, 50 | 'threshold1Color': 'rgba(216, 200, 27, 0.27)', 51 | 'threshold2Color': 'rgba(234, 112, 112, 0.22)' 52 | }, 53 | 'lines': true, 54 | 'span': 12, 55 | 'fill': 0, 56 | 'linewidth': 1, 57 | 'points': false, 58 | 'pointradius': 5, 59 | 'bars': false, 60 | 'stack': false, 61 | 'percentage': false, 62 | 'targets': [], 63 | 'legend': { 64 | 'show': true, 65 | 'values': true, 66 | 'min': false, 67 | 'max': true, 68 | 'current': false, 69 | 'total': false, 70 | 'avg': true 71 | }, 72 | 'nullPointMode': 'null as zero', 73 | 'steppedLine': false, 74 | 'tooltip': { 75 | 'value_type': 'cumulative', 76 | 'shared': false 77 | }, 78 | 'aliasColors': {}, 79 | 'seriesOverrides': [ 80 | {} 81 | ], 82 | 'links': [], 83 | 'datasource': 'graphite' 84 | }; 85 | this.state = defaults; 86 | 87 | // Overwrite defaults with custom values 88 | Object.keys(opts).forEach(function eachOpt(opt) { 89 | self.state[opt] = opts[opt]; 90 | }); 91 | 92 | if (opts.targets) { 93 | this.state.targets = []; 94 | opts.targets.forEach(function addT(target) { 95 | self.addTarget(target); 96 | }); 97 | } 98 | 99 | // finally add to row/dashboard if given 100 | if (opts.row && opts.dashboard) { 101 | opts.row.addPanel(this); 102 | opts.dashboard.addRow(opts.row); 103 | } 104 | } 105 | 106 | Graph.prototype.generate = function generate() { 107 | return this.state; 108 | }; 109 | 110 | Graph.prototype.addAlert = function addAlert(alert) { 111 | this.state.alert = alert.generate(); 112 | }; 113 | 114 | Graph.prototype.addTarget = function addTarget(target) { 115 | const refs = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 116 | const builtTarget = target.toString(); 117 | 118 | const targetWithRefs = { 119 | target: builtTarget, 120 | hide: target.hide, 121 | refId: refs[this._currentRefIndex++], 122 | }; 123 | 124 | const targetFull = handleRefTargets(builtTarget, this.state.targets); 125 | const targetToAdd = Object.assign({}, targetWithRefs, targetFull); 126 | this.state.targets.push(targetToAdd); 127 | }; 128 | 129 | function getRefsFromTarget(target) { 130 | const refMatchRegex = /.*?#(\w)[,)]/g; 131 | const refs = []; 132 | let matches; 133 | 134 | while (matches = refMatchRegex.exec(target)) { 135 | refs.push(matches[1]); 136 | } 137 | return refs; 138 | } 139 | 140 | function handleRefTargets(target, targets) { 141 | if (target.includes('#')) { 142 | const refs = getRefsFromTarget(target); 143 | const findTargetByRefId = (targets, refId) => targets.find(target => target.refId === refId).target; 144 | 145 | return { 146 | targetFull: refs.reduce((res, ref) => 147 | res.replace(`#${ref}`, findTargetByRefId(targets, ref)), 148 | target) 149 | }; 150 | } 151 | 152 | return {} 153 | } 154 | 155 | module.exports = Graph; 156 | -------------------------------------------------------------------------------- /grafana/panels/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | var Graph = require('./graph'); 23 | var SingleStat = require('./singlestat'); 24 | var Text = require('./text'); 25 | var Table = require('./table'); 26 | var DashboardList = require('./dashboard_list'); 27 | 28 | module.exports = { 29 | Graph: Graph, 30 | SingleStat: SingleStat, 31 | Text: Text, 32 | Table: Table, 33 | DashboardList: DashboardList 34 | }; 35 | -------------------------------------------------------------------------------- /grafana/panels/singlestat.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var generateGraphId = require('../id'); 24 | 25 | function SingleStat(opts) { 26 | opts = opts || {}; 27 | var self = this; 28 | 29 | var defaults = { 30 | id: generateGraphId(), 31 | title: 'single stat', 32 | targets: [], 33 | error: false, 34 | span: 12, 35 | editable: true, 36 | type: 'singlestat', 37 | links: [], 38 | maxDataPoints: 100, 39 | interval: null, 40 | cacheTimeout: null, 41 | format: 'none', 42 | prefix: '', 43 | postfix: '', 44 | nullText: null, 45 | valueMaps: [{ 46 | value: 'null', 47 | op: '=', 48 | text: 'N/A' 49 | }], 50 | nullPointMode: 'connected', 51 | valueName: 'current', 52 | prefixFontSize: '50%', 53 | valueFontSize: '80%', 54 | postfixFontSize: '50%', 55 | thresholds: '', 56 | colorBackground: false, 57 | colorValue: false, 58 | colors: [ 59 | 'rgba(71, 212, 59, 0.4)', 60 | 'rgba(245, 150, 40, 0.73)', 61 | 'rgba(225, 40, 40, 0.59)' 62 | ], 63 | sparkline: { 64 | show: true, 65 | full: true, 66 | lineColor: 'rgb(31, 193, 58)', 67 | fillColor: 'rgba(134, 178, 214, 0.41)' 68 | }, 69 | datasource: 'graphite' 70 | }; 71 | this.state = defaults; 72 | 73 | // Overwrite defaults with custom values 74 | Object.keys(opts).forEach(function eachOpt(opt) { 75 | self.state[opt] = opts[opt]; 76 | }); 77 | 78 | if (opts.targets) { 79 | this.state.targets = []; 80 | opts.targets.forEach(function addT(target) { 81 | self.addTarget(target); 82 | }); 83 | } 84 | 85 | // finally add to row/dashboard if given 86 | if (opts.row && opts.dashboard) { 87 | opts.row.addPanel(this); 88 | opts.dashboard.addRow(opts.row); 89 | } 90 | } 91 | 92 | SingleStat.prototype.generate = function generate() { 93 | return this.state; 94 | }; 95 | 96 | SingleStat.prototype.setTitle = function setTitle(title) { 97 | this.state.title = title; 98 | }; 99 | 100 | SingleStat.prototype.addTarget = function addTarget(target) { 101 | this.state.targets.push({ 102 | target: target.toString() 103 | }); 104 | }; 105 | 106 | module.exports = SingleStat; 107 | -------------------------------------------------------------------------------- /grafana/panels/table.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var generateGraphId = require('../id'); 24 | 25 | function Table(opts) { 26 | opts = opts || {}; 27 | var self = this; 28 | 29 | var defaults = { 30 | "title": "Panel Title", 31 | "error": false, 32 | "span": 12, 33 | "editable": true, 34 | "type": "table", 35 | "isNew": true, 36 | "id": generateGraphId(), 37 | "styles": [ 38 | { 39 | "type": "date", 40 | "pattern": "Time", 41 | "dateFormat": "YYYY-MM-DD HH:mm:ss" 42 | },{ 43 | "unit": "short", 44 | "type": "number", 45 | "decimals": 0, 46 | "colors": [ 47 | "rgba(245, 54, 54, 0.9)", 48 | "rgba(237, 129, 40, 0.89)", 49 | "rgba(50, 172, 45, 0.97)" 50 | ], 51 | "colorMode": null, 52 | "pattern": "/.*/", 53 | "thresholds": [] 54 | } 55 | ], 56 | "targets": [], 57 | "transform": "timeseries_aggregations", 58 | "pageSize": null, 59 | "showHeader": true, 60 | "columns": [{ 61 | "text": "Avg", 62 | "value": "avg" 63 | }], 64 | "scroll": true, 65 | "fontSize": "100%", 66 | "sort": { 67 | "col": 0, 68 | "desc": true 69 | }, 70 | "links": [] 71 | }; 72 | this.state = defaults; 73 | 74 | // Overwrite defaults with custom values 75 | Object.keys(opts).forEach(function eachOpt(opt) { 76 | self.state[opt] = opts[opt]; 77 | }); 78 | 79 | if (opts.targets) { 80 | this.state.targets = []; 81 | opts.targets.forEach(function addT(target) { 82 | self.addTarget(target); 83 | }); 84 | } 85 | 86 | // finally add to row/dashboard if given 87 | if (opts.row && opts.dashboard) { 88 | opts.row.addPanel(this); 89 | opts.dashboard.addRow(opts.row); 90 | } 91 | } 92 | 93 | Table.prototype.generate = function generate() { 94 | return this.state; 95 | }; 96 | 97 | Table.prototype.setTitle = function setTitle(title) { 98 | this.state.title = title; 99 | }; 100 | 101 | Table.prototype.addTarget = function addTarget(target) { 102 | this.state.targets.push({ 103 | target: target.toString(), 104 | hide: target.hide 105 | }); 106 | }; 107 | module.exports = Table; 108 | -------------------------------------------------------------------------------- /grafana/panels/text.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var generateGraphId = require('../id'); 24 | 25 | function Text(opts) { 26 | opts = opts || {}; 27 | var self = this; 28 | 29 | var defaults = { 30 | title: '', 31 | id: generateGraphId(), 32 | error: false, 33 | span: 12, 34 | editable: true, 35 | type: 'text', 36 | mode: 'markdown', 37 | content: '', 38 | style: {}, 39 | links: [] 40 | }; 41 | this.state = defaults; 42 | 43 | // Overwrite defaults with custom values 44 | Object.keys(opts).forEach(function eachOpt(opt) { 45 | self.state[opt] = opts[opt]; 46 | }); 47 | 48 | // finally add to row/dashboard if given 49 | if (opts.row && opts.dashboard) { 50 | opts.row.addPanel(this); 51 | opts.dashboard.addRow(opts.row); 52 | } 53 | } 54 | 55 | Text.prototype.generate = function generate() { 56 | return this.state; 57 | }; 58 | 59 | Text.prototype.setTitle = function setTitle(title) { 60 | this.state.title = title; 61 | }; 62 | 63 | module.exports = Text; 64 | -------------------------------------------------------------------------------- /grafana/publish.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | "use strict"; 22 | const fetch = require("node-fetch"); 23 | const config = require("./config"); 24 | const errors = require("./errors"); 25 | 26 | /* eslint-disable max-statements, max-len, no-console, no-undef */ 27 | function publish(dashboard, opts) { 28 | opts = opts || {}; 29 | 30 | if (!dashboard) { 31 | throw errors.UnfulfilledRequirement( 32 | "{component} missing requirement: {unfulfilledArg}", 33 | { 34 | component: "grafana.publish", 35 | unfulfilledArg: "dashboard" 36 | } 37 | ); 38 | } 39 | 40 | const state = dashboard.state; 41 | const cfg = config.getConfig(); 42 | 43 | if (!state || !state.title) { 44 | throw errors.InvalidState( 45 | "{component} state is invalid: state.{invalidArg} {reason}", 46 | { 47 | component: "grafana.Dashboard", 48 | invalidArg: "title", 49 | reason: "undefined" 50 | } 51 | ); 52 | } 53 | 54 | if (!cfg.url) { 55 | throw errors.Misconfigured( 56 | "Incorrect configuration: config.{invalidArg} {reason} - {resolution}", 57 | { 58 | invalidArg: "url", 59 | reason: "undefined", 60 | resolution: "Must call grafana.configure before publishing" 61 | } 62 | ); 63 | } 64 | 65 | if (!cfg.cookie) { 66 | throw errors.Misconfigured( 67 | "Incorrect configuration: config.{invalidArg} {reason} - {resolution}", 68 | { 69 | invalidArg: "cookie", 70 | reason: "undefined" 71 | } 72 | ); 73 | } 74 | 75 | const headers = new fetch.Headers(cfg.headers || {}); 76 | headers.set("Cookie", cfg.cookie); 77 | headers.set("Content-Type", "application/json"); 78 | 79 | const createData = { 80 | dashboard: dashboard.generate(), 81 | overwrite: true 82 | }; 83 | 84 | return fetch(cfg.url, { 85 | method: "POST", 86 | headers: headers, 87 | body: JSON.stringify(createData), 88 | timeout: opts.timeout || 1000 89 | }) 90 | .then(resp => { 91 | if (resp.ok) { 92 | console.log("Published the dashboard", state.title); 93 | return resp.text(); 94 | } else { 95 | throw new errors.ResponseError( 96 | "request failed: {name}", 97 | { 98 | name: resp.statusText, 99 | response: resp 100 | } 101 | ); 102 | } 103 | }) 104 | .catch(e => { 105 | console.log( 106 | "grafana-dash-gen: publish: caught error: ", 107 | e.name, 108 | e.message 109 | ); 110 | console.log("Unable to publish dashboard ", state.title); 111 | if (e.response) { 112 | console.log("response headers: ", e.response && e.response.headers.raw()); 113 | console.log("response body: ", e.response && e.response.text()); 114 | console.log("response statusCode:", e.response && e.response.status); 115 | } 116 | throw e; // rethrow for downstream consumers 117 | }); 118 | } 119 | /* eslint-enable */ 120 | 121 | module.exports = publish; 122 | -------------------------------------------------------------------------------- /grafana/row.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var xtend = require('xtend'); 24 | 25 | function Row(opts) { 26 | opts = opts || {}; 27 | var self = this; 28 | 29 | var state = { 30 | title: 'New row', 31 | height: '250px', 32 | editable: true, 33 | collapse: false, 34 | panels: [], 35 | showTitle: true 36 | }; 37 | 38 | this.state = xtend(state, opts); 39 | this.panels = []; 40 | 41 | if (opts.panels) { 42 | opts.panels.forEach(function addP(panel) { 43 | self.addPanel(panel); 44 | }) 45 | } 46 | } 47 | 48 | Row.prototype.generate = function generate() { 49 | var generatedJson = []; 50 | this.panels.forEach(function generatePanelJson(panel) { 51 | generatedJson.push(panel.generate()); 52 | }); 53 | 54 | this.state.panels = generatedJson; 55 | return this.state; 56 | }; 57 | 58 | Row.prototype.addPanel = function addPanel(panel) { 59 | this.panels.push(panel); 60 | }; 61 | 62 | module.exports = Row; 63 | -------------------------------------------------------------------------------- /grafana/target.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var _ = require('underscore'); 24 | var util = require('util'); 25 | 26 | function Target() { 27 | if (arguments.length === 0) { 28 | throw new Error('Incorrect invocation of Target. ' + 29 | 'Must provide at least one argument'); 30 | } 31 | if (typeof arguments[0] === 'string') { 32 | // Format string 33 | this.source = util.format.apply(null, arguments); 34 | } else { 35 | // Another target 36 | this.source = arguments[0]; 37 | this.func = arguments[1]; 38 | } 39 | } 40 | 41 | Target.prototype.toString = function toString() { 42 | if (this.func) { 43 | var args = _.reduce(this.func.slice(1), function reduce(memo, arg) { 44 | if (typeof arg === 'string') { 45 | arg = JSON.stringify(arg); 46 | } else { 47 | arg = arg.toString(); 48 | } 49 | return memo + ', ' + arg; 50 | }, ''); 51 | return this.func[0] + '(' + this.source.toString() + args + ')'; 52 | } else { 53 | return this.source; 54 | } 55 | }; 56 | 57 | // Primitive methods 58 | // Method Name: arity ignoring first target input 59 | Target.PRIMITIVES = { 60 | absolute: 0, 61 | aggregateLine: 0, 62 | alias: 1, 63 | aliasByMetric: 0, 64 | aliasByNode: 1, 65 | aliasSub: 2, 66 | alpha: 1, 67 | areaBetween: 0, 68 | asPercent: 0, 69 | averageAbove: 1, 70 | averageBelow: 1, 71 | averageOutsidePercentile: 1, 72 | averageSeries: 0, 73 | averageSeriesWithWildcards: 1, 74 | cactiStyle: 0, 75 | color: 1, 76 | consolidateBy: 1, 77 | countSeries: 0, 78 | cumulative: 0, 79 | currentAbove: 1, 80 | currentBelow: 1, 81 | dashed: 0, 82 | derivative: 0, 83 | diffSeries: 1, 84 | divideSeries: 1, 85 | drawAsInfinite: 0, 86 | exclude: 1, 87 | grep: 1, 88 | group: 0, 89 | groupByNode: 2, 90 | highestAverage: 1, 91 | highestCurrent: 1, 92 | highestMax: 1, 93 | hitcount: 1, 94 | holtWintersAbberation: 0, 95 | holtWintersConfidenceArea: 0, 96 | holtWintersConfidenceBands: 0, 97 | holtWintersForecast: 0, 98 | integral: 0, 99 | invert: 0, 100 | isNonNull: 0, 101 | keepLastValue: 0, 102 | legendValue: 1, 103 | limit: 1, 104 | lineWidth: 1, 105 | logarithm: 0, 106 | lowestAverage: 1, 107 | lowestCurrent: 1, 108 | mapSeries: 1, 109 | maxSeries: 0, 110 | maximumAbove: 1, 111 | maximumBelow: 1, 112 | minSeries: 0, 113 | minimumAbove: 1, 114 | mostDeviant: 1, 115 | movingAverage: 1, 116 | movingMedian: 1, 117 | multiplySeries: 0, 118 | nPercentile: 1, 119 | nonNegativeDerivative: 0, 120 | offset: 1, 121 | offsetToZero: 0, 122 | perSecond: 0, 123 | percentileOfSeries: 1, 124 | rangeOfSeries: 0, 125 | reduceSeries: 3, 126 | removeAbovePercentile: 1, 127 | removeAboveValue: 1, 128 | removeBelowPercentile: 1, 129 | removeBelowValue: 1, 130 | removeBetweenPercentile: 1, 131 | scale: 1, 132 | scaleToSeconds: 1, 133 | secondYAxis: 0, 134 | smartSummarize: 1, 135 | sortByMaxima: 0, 136 | sortByMinima: 0, 137 | sortByName: 0, 138 | sortByTotal: 0, 139 | stacked: 0, 140 | stddevSeries: 0, 141 | stdev: 1, 142 | sum: 0, 143 | sumSeries: 0, 144 | sumSeriesWithWildcards: 1, 145 | summarize: 1, 146 | timeShift: 1, 147 | timeStack: 3, 148 | transformNull: 0, 149 | useSeriesAbove: 3, 150 | weightedAverage: 2 151 | }; 152 | 153 | _.each(Target.PRIMITIVES, function each(n, method) { 154 | Target.prototype[method] = function t() { 155 | if (arguments.length < n) { 156 | /*eslint-disable*/ 157 | console.warn("Incorrect number of arguments passed to %s", method); 158 | console.trace(); 159 | /*eslint-enable*/ 160 | } 161 | return new Target(this, 162 | [method].concat(Array.prototype.slice.call(arguments, 0))); 163 | }; 164 | }); 165 | 166 | Target.COLORS = [ 167 | 'orange', 168 | 'blue', 169 | 'green', 170 | 'red', 171 | 'white', 172 | 'yellow', 173 | 'brown', 174 | 'purple', 175 | 'pink', 176 | 'aqua' 177 | ]; 178 | 179 | _.each(Target.COLORS, function each(color) { 180 | Target.prototype[color] = function t() { 181 | return this.color(color); 182 | }; 183 | }); 184 | 185 | // Target Helpers 186 | 187 | Target.prototype.cpu = function cpu() { 188 | return this.derivative().scale(0.016666666667).removeBelowValue(0); 189 | }; 190 | 191 | Target.prototype.reallyFaded = function reallyFaded() { 192 | return this.lineWidth(5).alpha(0.5); 193 | }; 194 | 195 | Target.prototype.faded = function faded() { 196 | return this.alpha(0.5).lineWidth(5); 197 | }; 198 | 199 | Target.prototype.lastWeek = function lastWeek() { 200 | return this.timeShift('7d'); 201 | }; 202 | 203 | Target.prototype.summarize15min = function summarize15min() { 204 | return this.summarize('15min'); 205 | }; 206 | 207 | Target.prototype.hide = function hide() { 208 | this.hide = true; 209 | return this; 210 | }; 211 | 212 | module.exports = Target; 213 | -------------------------------------------------------------------------------- /grafana/templates/custom.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | const DEFAULT_VARIABLE_ALL = '$__all'; 24 | 25 | function Custom(opts) { 26 | opts = opts || {}; 27 | this.state = { 28 | allFormat: 'glob', 29 | current: {}, 30 | datasource: null, 31 | includeAll: false, 32 | allValue: '', 33 | name: 'template', 34 | options: [], 35 | query: null, 36 | refresh: 1, 37 | 'refresh_on_load': false, 38 | type: 'custom' 39 | }; 40 | this.defaultValue = ''; 41 | 42 | // Overwrite defaults with custom values 43 | Object.keys(opts).forEach(key => { 44 | switch (key) { 45 | case 'defaultValue': 46 | this.defaultValue = opts[key]; 47 | break; 48 | default: 49 | this.state[key] = opts[key]; 50 | } 51 | }); 52 | this._processOptions(); 53 | } 54 | 55 | /* 56 | * Ensures options are objects, and updates the state's query and current 57 | * values. 58 | */ 59 | Custom.prototype._processOptions = function _processOptions() { 60 | if (!this.state.options.length) { 61 | if (this.defaultValue !== '') { 62 | throw new SyntaxError("cannot define default value without any options") 63 | } 64 | return; 65 | } 66 | 67 | let newOptions = []; 68 | let newQuery = []; 69 | 70 | let hasAll = false; 71 | for (let i = 0; i < this.state.options.length; i++) { 72 | const option = this.state.options[i]; 73 | const isObject = typeof option === 'object' && option.constructor === Object; 74 | const opt = isObject ? option : { 75 | text: option, 76 | value: option 77 | }; 78 | if (opt.value === DEFAULT_VARIABLE_ALL) { 79 | if (hasAll) { 80 | continue; 81 | } 82 | hasAll = true; 83 | } 84 | 85 | newOptions.push(opt); 86 | newQuery.push(opt.value); 87 | } 88 | 89 | if (this.defaultValue !== '') { 90 | const defaultOption = newOptions.find(option => option.value === this.defaultValue); 91 | if (!defaultOption) { 92 | throw new SyntaxError("default value not found in options list") 93 | } 94 | this.state.current = defaultOption 95 | } else if ((!this.state.current || Object.keys(this.state.current).length === 0) && !this.state.includeAll) { 96 | this.state.current = newOptions[0]; 97 | } 98 | 99 | this.state.options = newOptions; 100 | this.state.query = newQuery.join(','); 101 | }; 102 | 103 | Custom.prototype.generate = function generate() { 104 | return this.state; 105 | }; 106 | 107 | module.exports = Custom; 108 | -------------------------------------------------------------------------------- /grafana/templates/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var Custom = require('./custom'); 24 | var Query = require('./query'); 25 | 26 | module.exports = { 27 | Custom: Custom, 28 | Query: Query 29 | }; 30 | -------------------------------------------------------------------------------- /grafana/templates/query.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | /** 24 | * Provide a query to populate template variable. 25 | * 26 | * @param {string} query - The stat which will be queried. 27 | * @param {object} opts - Any state overrides, complete state of a query. 28 | * 29 | * @example 30 | * new Query('servers.*.docker.std-service-*', { 31 | * name: 'servers', 32 | * datasource: 'graphite', 33 | * includeAll: true, 34 | * allFormat: 'wildcard', 35 | * multi: true, 36 | * multiFormat: 'glob', 37 | * regex: '/(.*)\\-us\\d+/' 38 | * }); 39 | * 40 | * @see http://docs.grafana.org/reference/templating/ 41 | */ 42 | function Query(query, opts) { 43 | opts = opts || {}; 44 | var self = this; 45 | 46 | this.state = { 47 | query: query, 48 | name: opts.name, 49 | datasource: opts.datasource, 50 | type: 'query', 51 | includeAll: true, 52 | allFormat: 'wildcard', 53 | allValue: null, 54 | refresh: false, 55 | multi: false, 56 | options: [], 57 | current: {}, 58 | }; 59 | 60 | this._required = [ 61 | 'name', 62 | 'datasource' 63 | ]; 64 | 65 | this._overridable = [ 66 | 'includeAll', 67 | 'allFormat', 68 | 'allValue', 69 | 'multi', 70 | 'multiFormat', 71 | 'refresh', 72 | 'regex', 73 | 'tag' 74 | ]; 75 | 76 | // Override overridable values 77 | Object.keys(opts).forEach(function eachOpt(opt) { 78 | if (self._overridable.indexOf(opt) !== -1) { 79 | self.state[opt] = opts[opt]; 80 | } 81 | }); 82 | 83 | // assert required state has been populated 84 | this._required.forEach(function eachRequired(reqOpt) { 85 | if (!self.state[reqOpt]) { 86 | throw new Error('Missing Requirement: ' + reqOpt); 87 | } 88 | }); 89 | 90 | // make state immutable after this point 91 | Object.freeze(this.state); 92 | } 93 | 94 | Query.prototype.generate = function generate() { 95 | return this.state; 96 | }; 97 | 98 | module.exports = Query; 99 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var Dashboard = require('./grafana/dashboard'); 24 | var Row = require('./grafana/row'); 25 | var ExternalLink = require('./grafana/external-link') 26 | var Target = require('./grafana/target'); 27 | var Panels = require('./grafana/panels'); 28 | var Alert = require('./grafana/alert/alert'); 29 | var Condition = require('./grafana/alert/condition'); 30 | var Templates = require('./grafana/templates'); 31 | var publish = require('./grafana/publish'); 32 | var generateGraphId = require('./grafana/id'); 33 | var config = require('./grafana/config'); 34 | var Annotations = require('./grafana/annotations'); 35 | 36 | module.exports = { 37 | Dashboard: Dashboard, 38 | Row: Row, 39 | ExternalLink: ExternalLink, 40 | Panels: Panels, 41 | Templates: Templates, 42 | Alert, 43 | Condition, 44 | Annotations: Annotations, 45 | Target: Target, 46 | publish: publish, 47 | generateGraphId: generateGraphId, 48 | configure: config.configure 49 | }; 50 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "grafana-dash-gen", 3 | "version": "4.0.1", 4 | "description": "A grafana dashboard generator", 5 | "main": "index.js", 6 | "scripts": { 7 | "fast-test": "node ./test/index.js | tap-arc", 8 | "test-cover": "nyc --reporter html --reporter cobertura --reporter text tape ./test/index.js", 9 | "view-cover": "rm -rf ./coverage && npm run test-cover && open ./coverage/index.html", 10 | "test": "npm run fast-test && npm run test-cover" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/uber/grafana-dash-gen.git" 15 | }, 16 | "keywords": [ 17 | "grafana", 18 | "dashboard", 19 | "generator" 20 | ], 21 | "author": "Madan Thangavelu", 22 | "license": "MIT", 23 | "dependencies": { 24 | "error": "^10.4.0", 25 | "node-fetch": "^2.6.12", 26 | "underscore": "^1.10.2", 27 | "xtend": "^4.0.2" 28 | }, 29 | "devDependencies": { 30 | "eslint": "^8.47.0", 31 | "nock": "^13.3.2", 32 | "nyc": "^15.1.0", 33 | "pre-commit": "^1.0.6", 34 | "tap-arc": "^0.3.5", 35 | "tape": "^5.6.6" 36 | }, 37 | "files": [ 38 | "CHANGELOG.md", 39 | "CONTRIBUTION.md", 40 | "LICENSE", 41 | "README.md", 42 | "example.js", 43 | "grafana", 44 | "index.js", 45 | "package.json" 46 | ], 47 | "engines": { 48 | "node": ">=10" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/alert/alert.js: -------------------------------------------------------------------------------- 1 | const test = require('tape'); 2 | const Alert = require('../../grafana/alert/alert'); 3 | const Condition = require('../../grafana/alert/condition'); 4 | const simpleAlert = require('../fixtures/alert/simple_alert'); 5 | const alertWithCondition = require('../fixtures/alert/alert_with_condition'); 6 | 7 | test('simple alert', function t(assert) { 8 | const alert = new Alert(); 9 | 10 | assert.deepEqual(alert.generate(), simpleAlert); 11 | assert.end(); 12 | }); 13 | 14 | test('alert should be able to add condition', assert => { 15 | const alert = new Alert(); 16 | const condition = new Condition() 17 | .onQuery('B', '5m','now') 18 | .withReducer('min') 19 | .withEvaluator(1.1, 'gt'); 20 | 21 | alert.addCondition(condition); 22 | 23 | assert.deepEqual(alert.generate(), alertWithCondition); 24 | assert.end(); 25 | }); 26 | 27 | test('alert should be able to override defaults from the constructor', assert => { 28 | const overrideOptions = { 29 | name: 'override name', 30 | for: '30min', 31 | }; 32 | 33 | const alert = new Alert(overrideOptions); 34 | const actualAlert = alert.generate(); 35 | 36 | assert.deepEqual(actualAlert.name, overrideOptions.name); 37 | assert.deepEqual(actualAlert.for, overrideOptions.for); 38 | assert.end(); 39 | }); 40 | 41 | test('alert should be able to receive conditions in the constructor', assert => { 42 | const condition = new Condition({ 43 | type: 'query', 44 | query: { 45 | params: [ 46 | 'B', 47 | '5m', 48 | 'now' 49 | ] 50 | }, 51 | reducer: { 52 | type: 'min', 53 | params: [] 54 | }, 55 | evaluator: { 56 | type: 'gt', 57 | params: [1.1] 58 | }, 59 | operator: { 60 | type: 'and' 61 | } 62 | }); 63 | 64 | const overrideConditions = { conditions: [condition] }; 65 | const alert = new Alert(overrideConditions); 66 | 67 | assert.deepEqual(alert.generate(), alertWithCondition); 68 | assert.end(); 69 | }); 70 | -------------------------------------------------------------------------------- /test/alert/condition.js: -------------------------------------------------------------------------------- 1 | const test = require('tape'); 2 | const Condition = require('../../grafana/alert/condition'); 3 | 4 | test('condition .withEvaluator', assert => { 5 | const condition = new Condition() 6 | .withEvaluator(2, 'gt') 7 | .generate(); 8 | 9 | assert.deepEqual(condition.evaluator, { 10 | params: [2], 11 | type: 'gt' 12 | }); 13 | assert.end(); 14 | }); 15 | 16 | test('condition .withEvaluator should accept array of values', assert => { 17 | const condition = new Condition() 18 | .withEvaluator([2, 4], 'within_range') 19 | .generate(); 20 | 21 | assert.deepEqual(condition.evaluator, { 22 | params: [2, 4], 23 | type: 'within_range', 24 | }); 25 | assert.end(); 26 | }); 27 | 28 | test('condition .witEvaluator should throw when passing a weird value', assert => { 29 | const condition = new Condition(); 30 | assert.throws(() => condition.withEvaluator(2, 'bla')); 31 | assert.end(); 32 | }); 33 | 34 | test('condition .withOperator', assert => { 35 | const condition = new Condition() 36 | .withOperator('or') 37 | .generate(); 38 | 39 | assert.deepEqual(condition.operator, {type: 'or'}); 40 | assert.end(); 41 | }); 42 | 43 | test('condition .withOperator should throw when passing invalid value', assert => { 44 | const condition = new Condition(); 45 | assert.throws(() => condition.withOperator('bla')); 46 | assert.end(); 47 | }); 48 | 49 | test('condition .orCondition', assert => { 50 | const condition = new Condition() 51 | .orCondition() 52 | .generate(); 53 | 54 | assert.deepEqual(condition.operator, {type: 'or'}); 55 | assert.end(); 56 | }); 57 | 58 | test('condition .andCondition', assert => { 59 | const condition = new Condition() 60 | .andCondition() 61 | .generate(); 62 | 63 | assert.deepEqual(condition.operator, {type: 'and'}); 64 | assert.end(); 65 | }); 66 | 67 | test('condition should have default and operator', assert => { 68 | const condition = new Condition().generate(); 69 | 70 | assert.deepEqual(condition.operator, {type: 'and'}); 71 | assert.end(); 72 | }); 73 | 74 | test('condition should allow setting the query metric with .onQuery', assert => { 75 | const condition = new Condition() 76 | .onQuery('D', '60m', 'now') 77 | .generate(); 78 | 79 | assert.deepEqual(condition.query.params[0], 'D'); 80 | assert.deepEqual(condition.query.params[1], '60m'); 81 | assert.deepEqual(condition.query.params[2], 'now'); 82 | assert.end(); 83 | }); 84 | 85 | test('condition should throw when using .onQuery with a weird value', assert => { 86 | const condition = new Condition(); 87 | assert.throws(() => condition.onQuery(2)); 88 | assert.end(); 89 | }); 90 | 91 | test('condition should allow choosing condition reducer type', assert => { 92 | const condition = new Condition() 93 | .withReducer('min') 94 | .generate(); 95 | 96 | assert.deepEqual(condition.reducer, {params: [], type: 'min'}); 97 | assert.end(); 98 | }); 99 | 100 | test('condition should throw when using .withReducer with a weird value', assert => { 101 | const condition = new Condition(); 102 | assert.throws(() => condition.withReducer('bla')); 103 | assert.end(); 104 | }); 105 | 106 | test('override condition values from constructor', assert => { 107 | const overrideReducer = { 108 | reducer: { 109 | params: [], 110 | type: 'max', 111 | } 112 | }; 113 | const condition = new Condition(overrideReducer).generate(); 114 | 115 | assert.deepEqual(condition.reducer, { 116 | params: [], 117 | type: 'max', 118 | }); 119 | assert.end(); 120 | }); 121 | -------------------------------------------------------------------------------- /test/alert/index.js: -------------------------------------------------------------------------------- 1 | require('./alert'); 2 | require('./condition'); 3 | -------------------------------------------------------------------------------- /test/annotations/graphite.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | /* eslint-disable no-new */ 24 | var test = require('tape'); 25 | var Graphite = require('../../grafana/annotations/graphite'); 26 | 27 | var simpleGraphite = require('../fixtures/annotations/simple_graphite'); 28 | var overrideGraphite = require('../fixtures/annotations/override_graphite'); 29 | 30 | test('Graphite annotation has requirements', function t(assert) { 31 | assert.throws(function assertThrows() { 32 | new Graphite(); 33 | }, /UnfulfilledRequirement/); 34 | assert.end(); 35 | }); 36 | 37 | test('Graphite annotation requires name', function t(assert) { 38 | assert.throws(function assertThrows() { 39 | new Graphite({target: 'foo'}); 40 | }, /UnfulfilledRequirement/); 41 | assert.end(); 42 | }); 43 | 44 | test('Graphite annotation requires target', function t(assert) { 45 | assert.throws(function assertThrows() { 46 | new Graphite({name: 'foo'}); 47 | }, /UnfulfilledRequirement/); 48 | assert.end(); 49 | }); 50 | 51 | test('Graphite annotation generates state', function t(assert) { 52 | var annotation = new Graphite({ 53 | name: 'name', 54 | target: 'target' 55 | }); 56 | assert.deepEqual(annotation.generate(), simpleGraphite); 57 | assert.end(); 58 | }); 59 | 60 | test('Graphite annotation state can be overridden', function t(assert) { 61 | var annotation = new Graphite({ 62 | name: 'custom name', 63 | datasource: 'custom datasource', 64 | showLine: false, 65 | iconColor: 'rgb(255, 0, 0)', 66 | lineColor: 'rgb(0, 0, 255)', 67 | iconSize: 5, 68 | enable: false, 69 | target: 'custom.target', 70 | arbitraryProperty: 'foo' 71 | }); 72 | assert.deepEqual(annotation.generate(), overrideGraphite); 73 | assert.end(); 74 | }); 75 | -------------------------------------------------------------------------------- /test/annotations/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | require('./graphite'); 24 | -------------------------------------------------------------------------------- /test/config.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var config = require('../grafana/config'); 25 | 26 | test('config extends default configuration', function t(assert) { 27 | var foo = 'foo'; 28 | var bar = 1; 29 | var user = 'notguest'; 30 | var group = 'guest'; 31 | var url = 'http://myfakeurl.com'; 32 | var cookie = 'auth=value'; 33 | var headers = {'asdf': 'qwer'}; 34 | 35 | var cfg = { 36 | foo: foo, 37 | bar: bar, 38 | user: user, 39 | url: url, 40 | cookie: cookie, 41 | headers: headers 42 | }; 43 | 44 | var expected = { 45 | foo: foo, 46 | bar: bar, 47 | user: user, 48 | group: group, 49 | url: url, 50 | cookie: cookie, 51 | headers: headers 52 | }; 53 | 54 | config.configure(cfg); 55 | var result = config.getConfig(); 56 | 57 | assert.deepEqual(result, expected); 58 | assert.end(); 59 | }); 60 | -------------------------------------------------------------------------------- /test/dashboard.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var Dashboard = require('../grafana/dashboard'); 25 | var ExternalLink = require('../grafana/external-link') 26 | require('../grafana/panels'); // for coverage 27 | 28 | var simpleDashboard = require('./fixtures/simple_dashboard'); 29 | var overrideDashboard = require('./fixtures/override_dashboard'); 30 | 31 | test('Simple Dashboard', function t(assert) { 32 | var dashboard = new Dashboard(); 33 | dashboard.state.id = simpleDashboard.id; 34 | assert.deepEqual(dashboard.state, simpleDashboard); 35 | assert.end(); 36 | }); 37 | 38 | test('Dashboard with overriden information', function t(assert) { 39 | var dashboard = new Dashboard({ 40 | title: 'custom title', 41 | tags: ['foo', 'bar'], 42 | templating: [{ 43 | name: 'myvar', 44 | options: ['a', 'b'] 45 | }, { 46 | name: 'smoothing', 47 | options: ['30min', '10min', '5min', '2min', '1min'] 48 | }], 49 | annotations: [{ 50 | name: 'Deploy Completed', 51 | target: 'path.to.metric.with.annotation' 52 | }], 53 | refresh: '1m', 54 | rows: [{ 55 | title: 'New row', 56 | height: '250px', 57 | editable: true, 58 | collapse: false, 59 | panels: [] 60 | }], 61 | editable: true, 62 | }); 63 | dashboard.state.id = overrideDashboard.id; 64 | assert.deepEqual(dashboard.state, overrideDashboard); 65 | assert.end(); 66 | }); 67 | 68 | test('Dashboard can add rows', function t(assert) { 69 | var dashboard = new Dashboard(); 70 | var row = {foo: 'foo'}; 71 | dashboard.addRow(row); 72 | assert.deepEqual(dashboard.rows, [row]); 73 | assert.end(); 74 | }); 75 | 76 | test('Dashboard can add links', function t(assert) { 77 | const externalLinks = [ 78 | new ExternalLink({ 79 | title: "Uber Homepage", 80 | url: "www.uber.com", 81 | }) 82 | ] 83 | var dashboard = new Dashboard({ 84 | links: externalLinks 85 | }); 86 | assert.deepEqual(dashboard.links, externalLinks); 87 | assert.end(); 88 | }) 89 | 90 | test('Dashboard can set time', function t(assert) { 91 | var d = new Dashboard({ 92 | time: { 93 | from: 'now-1h', 94 | to: 'now' 95 | } 96 | }); 97 | 98 | assert.deepEqual(d.generate().time, { 99 | from: 'now-1h', 100 | to: 'now' 101 | }); 102 | assert.end(); 103 | }); 104 | 105 | test('Dashboard can generate correct body', function t(assert) { 106 | var rowData = {foo: 'foo'}; 107 | var dashboard = new Dashboard({ 108 | links: [ 109 | new ExternalLink({ 110 | title: "Uber Homepage", 111 | url: "www.uber.com", 112 | }), 113 | { 114 | title: "Google Homepage", 115 | tooltip: "", 116 | url: "www.google.com", 117 | icon: "external link", 118 | targetBlank: true, 119 | type: "link", 120 | includeVars: false, 121 | keepTime: false, 122 | } 123 | ] 124 | }); 125 | var row = { 126 | generate: function generate() { 127 | return rowData; 128 | } 129 | }; 130 | dashboard.addRow(row); 131 | simpleDashboard.rows = [rowData]; 132 | var json = dashboard.generate(); 133 | 134 | var expectedJson = { 135 | ...simpleDashboard, 136 | links: [ 137 | { 138 | title: "Uber Homepage", 139 | tooltip: "", 140 | url: "www.uber.com", 141 | tags: [], 142 | icon: "external link", 143 | targetBlank: true, 144 | type: "link", 145 | includeVars: false, 146 | keepTime: false, 147 | }, 148 | { 149 | title: "Google Homepage", 150 | tooltip: "", 151 | url: "www.google.com", 152 | icon: "external link", 153 | targetBlank: true, 154 | type: "link", 155 | includeVars: false, 156 | keepTime: false, 157 | } 158 | ] 159 | } 160 | assert.deepEqual(json, expectedJson); 161 | assert.end(); 162 | }); 163 | -------------------------------------------------------------------------------- /test/external-link.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var ExternalLink = require('../grafana/external-link'); 25 | var defaultExternalLink = require('./fixtures/external_link'); 26 | 27 | test('default external link', function t(assert) { 28 | var externalLink = new ExternalLink({ 29 | title: "Uber Home Page", 30 | url: "www.uber.com", 31 | }); 32 | assert.deepEqual(externalLink.generate(), defaultExternalLink); 33 | assert.end(); 34 | }); 35 | 36 | test('external link with custom settings', function t(assert) { 37 | var externalLink = new ExternalLink({ 38 | title: "Uber Home Page", 39 | tooltip: "click to view", 40 | url: "www.uber.com", 41 | }) 42 | .includeTimeFilter() 43 | .includeVariableValues() 44 | .withIcon("custom icon"); 45 | 46 | assert.deepEqual(externalLink.generate(), { 47 | title: 'Uber Home Page', 48 | tooltip: "click to view", 49 | url: "www.uber.com", 50 | tags: [], 51 | icon: "custom icon", 52 | targetBlank: true, 53 | type: "link", 54 | includeVars: true, 55 | keepTime: true, 56 | }); 57 | assert.end(); 58 | }); 59 | 60 | test('external link validates required fields', function t(assert) { 61 | assert.throws( 62 | () => new ExternalLink().generate(), 63 | new SyntaxError("a title for the link must be provided"), 64 | ); 65 | assert.throws( 66 | () => new ExternalLink({title: "Uber Home Page"}).generate(), 67 | new SyntaxError("a url for the link must be provided"), 68 | ); 69 | assert.end(); 70 | }); 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /test/fixtures/alert/alert.mock.js: -------------------------------------------------------------------------------- 1 | const Condition = require('../../../grafana/alert/condition'); 2 | const Alert = require('../../../grafana/alert/alert'); 3 | 4 | const getAlert = () => { 5 | const condition = new Condition() 6 | .onQuery('B', '5m', 'now') 7 | .withReducer('min') 8 | .withEvaluator(1.1, 'gt'); 9 | 10 | return new Alert().addCondition(condition); 11 | }; 12 | 13 | module.exports.getAlert = getAlert; 14 | -------------------------------------------------------------------------------- /test/fixtures/alert/alert_with_condition.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'Panel Title alert', 3 | conditions: [{ 4 | type: 'query', 5 | query: { 6 | params: [ 7 | 'B', 8 | '5m', 9 | 'now' 10 | ] 11 | }, 12 | reducer: { 13 | type: 'min', 14 | params: [] 15 | }, 16 | evaluator: { 17 | type: 'gt', 18 | params: [1.1] 19 | }, 20 | operator: { 21 | type: 'and' 22 | } 23 | }], 24 | for: '15m', 25 | frequency: '5m', 26 | message: '', 27 | notifications: [], 28 | executionErrorState: 'keep_state', 29 | noDataState: 'keep_state', 30 | alertRuleTags: {}, 31 | handler: 1, 32 | }; 33 | -------------------------------------------------------------------------------- /test/fixtures/alert/simple_alert.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "name": "Panel Title alert", 3 | "for": "15m", 4 | "frequency": "5m", 5 | "conditions": [], 6 | "message": '', 7 | "notifications": [], 8 | "executionErrorState": "keep_state", 9 | "noDataState": "keep_state", 10 | "alertRuleTags": {}, 11 | "handler": 1, 12 | }; 13 | -------------------------------------------------------------------------------- /test/fixtures/alert/simple_condition.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | type: 'query', 3 | query: { 4 | params: [ 5 | 'A', 6 | '5m', 7 | 'now' 8 | ] 9 | }, 10 | reducer: { 11 | type: 'avg', 12 | params: [] 13 | }, 14 | evaluator: { 15 | type: 'gt', 16 | params: [] 17 | }, 18 | operator: { 19 | type: 'and' 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /test/fixtures/annotations/override_graphite.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = { 24 | name: 'custom name', 25 | datasource: 'custom datasource', 26 | showLine: false, 27 | iconColor: 'rgb(255, 0, 0)', 28 | lineColor: 'rgb(0, 0, 255)', 29 | iconSize: 5, 30 | enable: false, 31 | target: 'custom.target', 32 | arbitraryProperty: 'foo' 33 | }; 34 | -------------------------------------------------------------------------------- /test/fixtures/annotations/simple_graphite.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = { 24 | name: 'name', 25 | datasource: 'graphite', 26 | showLine: true, 27 | iconColor: 'rgb(255, 234, 0)', 28 | lineColor: 'rgba(165, 161, 70, 0.59)', 29 | iconSize: 10, 30 | enable: true, 31 | target: 'target' 32 | }; 33 | -------------------------------------------------------------------------------- /test/fixtures/external_link.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | module.exports = { 22 | title: 'Uber Home Page', 23 | tooltip: "", 24 | url: "www.uber.com", 25 | tags: [], 26 | icon: "external link", 27 | targetBlank: true, 28 | type: "link", 29 | includeVars: false, 30 | keepTime: false, 31 | }; 32 | -------------------------------------------------------------------------------- /test/fixtures/override_dashboard.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | module.exports = { 23 | id: null, 24 | title: 'custom title', 25 | originalTitle: 'Generated Dashboard', 26 | tags: ['foo', 'bar'], 27 | style: 'dark', 28 | timezone: 'browser', 29 | editable: true, 30 | hideControls: false, 31 | sharedCrosshair: false, 32 | refresh: '1m', 33 | schemaVersion: 6, 34 | hideAllLegends: false, 35 | rows: [], 36 | templating: { 37 | enable: true, 38 | list: [{ 39 | allFormat: 'glob', 40 | current: { 41 | text: 'a', 42 | value: 'a' 43 | }, 44 | datasource: null, 45 | includeAll: false, 46 | allValue: '', 47 | name: 'myvar', 48 | options: [{ 49 | text: 'a', 50 | value: 'a' 51 | }, { 52 | text: 'b', 53 | value: 'b' 54 | }], 55 | query: 'a,b', 56 | refresh: 1, 57 | 'refresh_on_load': false, 58 | type: 'custom' 59 | }, { 60 | allFormat: 'glob', 61 | current: { 62 | text: '30min', 63 | value: '30min' 64 | }, 65 | datasource: null, 66 | includeAll: false, 67 | allValue: '', 68 | name: 'smoothing', 69 | options: [{ 70 | text: '30min', 71 | value: '30min' 72 | }, { 73 | text: '10min', 74 | value: '10min' 75 | }, { 76 | text: '5min', 77 | value: '5min' 78 | }, { 79 | text: '2min', value: '2min' 80 | }, { 81 | text: '1min', 82 | value: '1min' 83 | }], 84 | query: '30min,10min,5min,2min,1min', 85 | refresh: 1, 86 | 'refresh_on_load': false, 87 | type: 'custom' 88 | }] 89 | }, 90 | annotations: { 91 | enable: true, 92 | list: [{ 93 | name: 'Deploy Completed', 94 | datasource: 'graphite', 95 | showLine: true, 96 | iconColor: 'rgb(255, 234, 0)', 97 | lineColor: 'rgba(165, 161, 70, 0.59)', 98 | iconSize: 10, 99 | enable: true, 100 | target: 'path.to.metric.with.annotation' 101 | }] 102 | }, 103 | time: null, 104 | links: [], 105 | }; 106 | -------------------------------------------------------------------------------- /test/fixtures/override_row.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | module.exports = { 22 | title: 'My Row', 23 | height: '1000px', 24 | editable: false, 25 | showTitle: true, 26 | collapse: true, 27 | panels: [{ 28 | foo: 'foo', 29 | bar: 'bar', 30 | baz: 1 31 | }] 32 | }; 33 | -------------------------------------------------------------------------------- /test/fixtures/panels/graph_with_alert.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | module.exports = { 22 | alert: { 23 | name: 'Panel Title alert', 24 | conditions: [{ 25 | type: 'query', 26 | query: { 27 | params: [ 28 | 'B', 29 | '5m', 30 | 'now' 31 | ] 32 | }, 33 | reducer: { 34 | type: 'min', 35 | params: [] 36 | }, 37 | evaluator: { 38 | type: 'gt', 39 | params: [1.1] 40 | }, 41 | operator: { 42 | type: 'and' 43 | } 44 | }], 45 | for: '15m', 46 | frequency: '5m', 47 | message: '', 48 | notifications: [], 49 | executionErrorState: 'keep_state', 50 | noDataState: 'keep_state', 51 | alertRuleTags: {}, 52 | handler: 1, 53 | }, 54 | aliasColors: {}, 55 | bars: false, 56 | editable: true, 57 | error: false, 58 | fill: 0, 59 | grid: { 60 | leftMax: null, 61 | leftMin: null, 62 | rightMax: null, 63 | rightMin: null, 64 | threshold1: null, 65 | threshold1Color: 'rgba(216, 200, 27, 0.27)', 66 | threshold2: null, 67 | threshold2Color: 'rgba(234, 112, 112, 0.22)' 68 | }, 69 | id: 1, 70 | legend: { 71 | avg: true, 72 | current: false, 73 | max: true, 74 | min: false, 75 | show: true, 76 | total: false, 77 | values: true 78 | }, 79 | lines: true, 80 | linewidth: 1, 81 | links: [], 82 | nullPointMode: 'null as zero', 83 | percentage: false, 84 | pointradius: 5, 85 | points: false, 86 | renderer: 'flot', 87 | seriesOverrides: [{}], 88 | span: 12, 89 | stack: false, 90 | steppedLine: false, 91 | targets: [{ hide: undefined, refId: 'A', target: 'firstTarget' }], 92 | title: 'no title (click here)', 93 | tooltip: { 94 | shared: false, 95 | value_type: 'cumulative' 96 | }, 97 | type: 'graph', 98 | 'x-axis': true, 99 | 'y-axis': true, 100 | y_formats: ['short', 'short'], 101 | datasource: 'graphite' 102 | }; 103 | -------------------------------------------------------------------------------- /test/fixtures/panels/override_dashboard_list.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | module.exports = { 22 | title: 'dashboard list', 23 | error: false, 24 | span: 3, 25 | editable: true, 26 | type: 'dashlist', 27 | isNew: true, 28 | id: 9, 29 | mode: 'search', 30 | query: 'dashboard list', 31 | limit: 10, 32 | tags: [], 33 | links: [] 34 | }; 35 | -------------------------------------------------------------------------------- /test/fixtures/panels/override_graph.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = { 24 | aliasColors: {}, 25 | bars: false, 26 | editable: true, 27 | error: false, 28 | fill: 0, 29 | grid: { 30 | leftMax: null, 31 | leftMin: null, 32 | rightMax: null, 33 | rightMin: null, 34 | threshold1: null, 35 | threshold1Color: 'rgba(216, 200, 27, 0.27)', 36 | threshold2: null, 37 | threshold2Color: 'rgba(234, 112, 112, 0.22)' 38 | }, 39 | id: 2, 40 | legend: { 41 | avg: true, 42 | current: false, 43 | max: true, 44 | min: false, 45 | show: true, 46 | total: false, 47 | values: true 48 | }, 49 | lines: true, 50 | linewidth: 1, 51 | links: [], 52 | nullPointMode: 'null as zero', 53 | percentage: false, 54 | pointradius: 5, 55 | points: false, 56 | renderer: 'flot', 57 | seriesOverrides: [{}], 58 | span: 4, 59 | stack: false, 60 | steppedLine: false, 61 | targets: [{ 62 | target: 'target', 63 | hide: undefined, 64 | refId: 'A', 65 | }], 66 | title: 'custom title', 67 | tooltip: { 68 | shared: false, 69 | 'value_type': 'cumulative' 70 | }, 71 | type: 'graph', 72 | 'x-axis': true, 73 | 'y-axis': true, 74 | 'y_formats': ['short', 'short'], 75 | datasource: 'M3', 76 | arbitraryProperty: 'foo' 77 | }; 78 | -------------------------------------------------------------------------------- /test/fixtures/panels/override_singlestat.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = { 24 | cacheTimeout: null, 25 | colorBackground: false, 26 | colorValue: false, 27 | colors: [ 28 | 'rgba(71, 212, 59, 0.4)', 29 | 'rgba(245, 150, 40, 0.73)', 30 | 'rgba(225, 40, 40, 0.59)' 31 | ], 32 | editable: true, 33 | error: false, 34 | format: 'none', 35 | id: 2, 36 | interval: null, 37 | links: [], 38 | maxDataPoints: 100, 39 | nullPointMode: 'connected', 40 | nullText: null, 41 | postfix: '', 42 | postfixFontSize: '50%', 43 | prefix: '', 44 | prefixFontSize: '50%', 45 | span: 4, 46 | sparkline: { 47 | fillColor: 'rgba(134, 178, 214, 0.41)', 48 | full: true, 49 | lineColor: 'rgb(31, 193, 58)', 50 | show: true 51 | }, 52 | targets: [{ 53 | target: 'target' 54 | }], 55 | thresholds: '', 56 | title: 'custom title', 57 | type: 'singlestat', 58 | valueFontSize: '80%', 59 | valueMaps: [{ 60 | op: '=', 61 | text: 'N/A', 62 | value: 'null' 63 | }], 64 | valueName: 'current', 65 | datasource: 'M3', 66 | arbitraryProperty: 'foo' 67 | }; 68 | -------------------------------------------------------------------------------- /test/fixtures/panels/override_table.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = { 24 | title: "custom title", 25 | error: false, 26 | span: 4, 27 | editable: true, 28 | type: "table", 29 | isNew: true, 30 | id: 1, 31 | datasource: 'M3', 32 | styles: [{ 33 | type: "date", 34 | pattern: "Time", 35 | dateFormat: "YYYY-MM-DD HH:mm:ss" 36 | },{ 37 | unit: "short", 38 | type: "number", 39 | decimals: 0, 40 | colors: [ 41 | "rgba(245, 54, 54, 0.9)", 42 | "rgba(237, 129, 40, 0.89)", 43 | "rgba(50, 172, 45, 0.97)" 44 | ], 45 | colorMode: null, 46 | pattern: "/.*/", 47 | thresholds: [] 48 | }], 49 | targets: [{ 50 | target: 'target', 51 | hide: undefined 52 | }], 53 | transform: "timeseries_aggregations", 54 | pageSize: null, 55 | showHeader: true, 56 | columns: 57 | [{ 58 | text: "Avg", 59 | value: "avg" 60 | }], 61 | scroll: true, 62 | fontSize: "100%", 63 | sort: { 64 | col: 0, 65 | desc: true 66 | }, 67 | links: [], 68 | arbitraryProperty: 'foo' 69 | }; 70 | -------------------------------------------------------------------------------- /test/fixtures/panels/override_text.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | module.exports = { 22 | "title": "", 23 | "error": false, 24 | "span": 4, 25 | "editable": true, 26 | "type": "text", 27 | "id": 2, 28 | "mode": "markdown", 29 | "content": "TEST", 30 | "style": {}, 31 | "links": [], 32 | "height": "100px", 33 | "transparent": true 34 | } 35 | -------------------------------------------------------------------------------- /test/fixtures/panels/simple_dashboard_list.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | module.exports = { 22 | title: 'dashboard list', 23 | error: false, 24 | span: 3, 25 | editable: true, 26 | type: 'dashlist', 27 | isNew: true, 28 | id: 7, 29 | mode: 'search', 30 | query: 'dashboard list', 31 | limit: 10, 32 | tags: [], 33 | links: [] 34 | }; 35 | -------------------------------------------------------------------------------- /test/fixtures/panels/simple_graph.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | module.exports = { 22 | aliasColors: {}, 23 | bars: false, 24 | editable: true, 25 | error: false, 26 | fill: 0, 27 | grid: { 28 | leftMax: null, 29 | leftMin: null, 30 | rightMax: null, 31 | rightMin: null, 32 | threshold1: null, 33 | threshold1Color: 'rgba(216, 200, 27, 0.27)', 34 | threshold2: null, 35 | threshold2Color: 'rgba(234, 112, 112, 0.22)' 36 | }, 37 | id: 1, 38 | legend: { 39 | avg: true, 40 | current: false, 41 | max: true, 42 | min: false, 43 | show: true, 44 | total: false, 45 | values: true 46 | }, 47 | lines: true, 48 | linewidth: 1, 49 | links: [], 50 | nullPointMode: 'null as zero', 51 | percentage: false, 52 | pointradius: 5, 53 | points: false, 54 | renderer: 'flot', 55 | seriesOverrides: [{}], 56 | span: 12, 57 | stack: false, 58 | steppedLine: false, 59 | targets: [], 60 | title: 'no title (click here)', 61 | tooltip: { 62 | shared: false, 63 | value_type: 'cumulative' 64 | }, 65 | type: 'graph', 66 | 'x-axis': true, 67 | 'y-axis': true, 68 | y_formats: ['short', 'short'], 69 | datasource: 'graphite' 70 | }; 71 | -------------------------------------------------------------------------------- /test/fixtures/panels/simple_singlestat.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | module.exports = { 22 | cacheTimeout: null, 23 | colorBackground: false, 24 | colorValue: false, 25 | colors: ['rgba(71, 212, 59, 0.4)', 'rgba(245, 150, 40, 0.73)', 'rgba(225, 40, 40, 0.59)'], 26 | editable: true, 27 | error: false, 28 | format: 'none', 29 | id: 5, 30 | interval: null, 31 | links: [], 32 | maxDataPoints: 100, 33 | nullPointMode: 'connected', 34 | nullText: null, 35 | postfix: '', 36 | postfixFontSize: '50%', 37 | prefix: '', 38 | prefixFontSize: '50%', 39 | span: 12, 40 | sparkline: { 41 | fillColor: 'rgba(134, 178, 214, 0.41)', 42 | full: true, 43 | lineColor: 'rgb(31, 193, 58)', 44 | show: true 45 | }, 46 | targets: [], 47 | thresholds: '', 48 | title: 'single stat', 49 | type: 'singlestat', 50 | valueFontSize: '80%', 51 | valueMaps: [{ 52 | op: '=', 53 | text: 'N/A', 54 | value: 'null' 55 | }], 56 | valueName: 'current', 57 | datasource: 'graphite' 58 | } 59 | -------------------------------------------------------------------------------- /test/fixtures/panels/simple_table.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | module.exports = { 22 | title: "Panel Title", 23 | error: false, 24 | span: 12, 25 | editable: true, 26 | type: "table", 27 | isNew: true, 28 | id: 1, 29 | styles: 30 | [{ 31 | type: "date", 32 | pattern: "Time", 33 | dateFormat: "YYYY-MM-DD HH:mm:ss" 34 | },{ 35 | unit: "short", 36 | type: "number", 37 | decimals: 0, 38 | colors: [ 39 | "rgba(245, 54, 54, 0.9)", 40 | "rgba(237, 129, 40, 0.89)", 41 | "rgba(50, 172, 45, 0.97)" 42 | ], 43 | colorMode: null, 44 | pattern: "/.*/", 45 | thresholds: [] 46 | }], 47 | targets: [], 48 | transform: "timeseries_aggregations", 49 | pageSize: null, 50 | showHeader: true, 51 | columns: 52 | [{ 53 | text: "Avg", 54 | value: "avg" 55 | }], 56 | scroll: true, 57 | fontSize: "100%", 58 | sort: { 59 | col: 0, 60 | desc: true 61 | }, 62 | links: [] 63 | }; 64 | -------------------------------------------------------------------------------- /test/fixtures/panels/simple_text.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | module.exports = { 22 | "title": "", 23 | "error": false, 24 | "span": 12, 25 | "editable": true, 26 | "type": "text", 27 | "id": 2, 28 | "mode": "markdown", 29 | "content": "", 30 | "style": {}, 31 | "links": [] 32 | } 33 | -------------------------------------------------------------------------------- /test/fixtures/simple_dashboard.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | module.exports = { 23 | id: null, 24 | title: 'Generated Grafana Dashboard', 25 | originalTitle: 'Generated Dashboard', 26 | tags: [], 27 | style: 'dark', 28 | timezone: 'browser', 29 | editable: true, 30 | hideControls: false, 31 | sharedCrosshair: false, 32 | refresh: false, 33 | schemaVersion: 6, 34 | hideAllLegends: false, 35 | rows: [], 36 | annotations: {list: [], enable: true}, 37 | templating: {list: [], enable: true}, 38 | time: null, 39 | links: [], 40 | }; 41 | -------------------------------------------------------------------------------- /test/fixtures/simple_row.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | module.exports = { 22 | title: 'New row', 23 | showTitle: true, 24 | height: '250px', 25 | editable: true, 26 | collapse: false, 27 | panels: [] 28 | }; 29 | -------------------------------------------------------------------------------- /test/fixtures/templates/override_custom.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = { 24 | name: 'custom', 25 | type: 'custom', 26 | options: [{ 27 | text: 'a', 28 | value: 'a' 29 | }, { 30 | text: 'b', 31 | value: 'b' 32 | }], 33 | datasource: null, 34 | refresh: 1, 35 | 'refresh_on_load': false, 36 | includeAll: false, 37 | allValue: '', 38 | allFormat: 'glob', 39 | query: 'a,b', 40 | current: { 41 | text: 'a', 42 | value: 'a' 43 | }, 44 | arbitraryProperty: 'foo' 45 | }; 46 | -------------------------------------------------------------------------------- /test/fixtures/templates/override_custom_text_value.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = { 24 | name: 'custom', 25 | type: 'custom', 26 | options: [{ 27 | text: 'myText', 28 | value: 'myValue' 29 | }], 30 | datasource: null, 31 | refresh: 1, 32 | 'refresh_on_load': false, 33 | includeAll: false, 34 | allValue: '', 35 | allFormat: 'glob', 36 | query: 'myValue', 37 | current: { 38 | text: 'myText', 39 | value: 'myValue' 40 | }, 41 | arbitraryProperty: 'foo' 42 | }; 43 | -------------------------------------------------------------------------------- /test/fixtures/templates/override_query.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = { 24 | type: 'query', 25 | query: 'stats.*', 26 | name: 'template', 27 | datasource: 'datasource', 28 | options: [], 29 | current: {}, 30 | includeAll: false, 31 | allFormat: 'glob', 32 | allValue: '*', 33 | refresh: true, 34 | multi: true 35 | }; 36 | -------------------------------------------------------------------------------- /test/fixtures/templates/simple_custom.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | module.exports = { 22 | name: 'template', 23 | type: 'custom', 24 | options: [], 25 | datasource: null, 26 | refresh: 1, 27 | refresh_on_load: false, 28 | includeAll: false, 29 | allValue: '', 30 | allFormat: 'glob', 31 | query: null, 32 | current: {} 33 | } 34 | -------------------------------------------------------------------------------- /test/fixtures/templates/simple_query.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | module.exports = { 24 | type: 'query', 25 | query: 'servers.*', 26 | name: 'foo', 27 | datasource: 'default', 28 | options: [], 29 | current: {}, 30 | includeAll: true, 31 | allFormat: 'wildcard', 32 | allValue: null, 33 | refresh: false, 34 | multi: false 35 | }; 36 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | require('./annotations'); 24 | require('./config'); 25 | require('./dashboard'); 26 | require('./external-link') 27 | require('./panels'); 28 | require('./publish'); 29 | require('./row'); 30 | require('./target'); 31 | require('./templates'); 32 | require('./alert'); 33 | -------------------------------------------------------------------------------- /test/panels/dashboard_list.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2018 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var DashboardList = require('../../grafana/panels/dashboard_list'); 25 | 26 | var dashboardList = require('../fixtures/panels/simple_dashboard_list.js'); 27 | var overrideDashboardList = require('../fixtures/panels/override_dashboard_list.js'); 28 | 29 | test('simple DashboardList panel', function t(assert) { 30 | var graph = new DashboardList(); 31 | graph.state.id = dashboardList.id; 32 | 33 | assert.deepEqual(graph.generate(), dashboardList); 34 | assert.end(); 35 | }); 36 | 37 | test('DashboardList panel with overriden information', function t(assert) { 38 | var graph = new DashboardList({ 39 | span: 3, 40 | title: 'dashboard list', 41 | mode: 'search' 42 | }); 43 | graph.state.id = overrideDashboardList.id; 44 | 45 | assert.deepEqual(graph.generate(), overrideDashboardList); 46 | assert.end(); 47 | }); 48 | 49 | test('DashboardList can set title', function t(assert) { 50 | var title = 'title'; 51 | var graph = new DashboardList(); 52 | graph.setTitle(title); 53 | assert.deepEqual(graph.state.title, title); 54 | assert.end(); 55 | }); 56 | 57 | test('add graph to row and dashboard when passed', function t(assert){ 58 | var calledAddPanel = 0; 59 | var calledAddRow = 0; 60 | 61 | new DashboardList({ 62 | row: { 63 | addPanel: function addPanel() { 64 | calledAddPanel += 1; 65 | } 66 | }, 67 | 68 | dashboard: { 69 | addRow: function addRow() { 70 | calledAddRow += 1; 71 | } 72 | } 73 | }); 74 | 75 | assert.deepEqual(calledAddRow, 1); 76 | assert.deepEqual(calledAddPanel, 1); 77 | assert.end(); 78 | }); 79 | -------------------------------------------------------------------------------- /test/panels/graph.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | /* eslint-disable no-new */ 24 | const test = require('tape'); 25 | const Graph = require('../../grafana/panels/graph'); 26 | 27 | const getAlert = require('../fixtures/alert/alert.mock').getAlert; 28 | const simpleGraph = require('../fixtures/panels/simple_graph.js'); 29 | const overrideGraph = require('../fixtures/panels/override_graph.js'); 30 | const simpleGraphWithAlert = require('../fixtures/panels/graph_with_alert.js'); 31 | const alertWithCondition = require('../fixtures/alert/alert_with_condition.js'); 32 | 33 | test('simple graph', assert => { 34 | const graph = new Graph(); 35 | graph.state.id = simpleGraph.id; 36 | assert.deepEqual(graph.generate(), simpleGraph); 37 | assert.end(); 38 | }); 39 | 40 | test('graph with overriden information', assert => { 41 | const graph = new Graph({ 42 | span: 4, 43 | title: 'custom title', 44 | targets: ['target'], 45 | datasource: 'M3', 46 | fill: 0, 47 | arbitraryProperty: 'foo' 48 | }); 49 | graph.state.id = overrideGraph.id; 50 | 51 | assert.deepEqual(graph.generate(), overrideGraph); 52 | assert.end(); 53 | }); 54 | 55 | test('add graph to row and dashboard when passed', assert => { 56 | let calledAddPanel = 0; 57 | let calledAddRow = 0; 58 | 59 | new Graph({ 60 | row: { 61 | addPanel: function addPanel() { 62 | calledAddPanel += 1; 63 | } 64 | }, 65 | 66 | dashboard: { 67 | addRow: function addRow() { 68 | calledAddRow += 1; 69 | } 70 | } 71 | }); 72 | 73 | assert.deepEqual(calledAddRow, 1); 74 | assert.deepEqual(calledAddPanel, 1); 75 | assert.end(); 76 | }); 77 | 78 | test('graph should assign a refId to each target added', assert => { 79 | const firstTarget = 'target'; 80 | const secondTarget = 'target-2'; 81 | 82 | const expectedTargets = [{ 83 | hide: undefined, 84 | refId: 'A', 85 | target: firstTarget 86 | }, { 87 | hide: undefined, 88 | refId: 'B', 89 | target: secondTarget 90 | }]; 91 | 92 | const graph = new Graph({ 93 | span: 4, 94 | title: 'custom title', 95 | targets: [firstTarget, secondTarget], 96 | datasource: 'M3', 97 | fill: 0, 98 | arbitraryProperty: 'foo' 99 | }); 100 | 101 | assert.deepEqual(graph.generate().targets, expectedTargets); 102 | assert.end(); 103 | }); 104 | 105 | test('graph should be able to add alert', assert => { 106 | const graph = new Graph({ 107 | targets: ['firstTarget'], 108 | }); 109 | 110 | graph.state.id = simpleGraphWithAlert.id; 111 | graph.addAlert(getAlert()); 112 | 113 | assert.deepEqual(graph.generate(), simpleGraphWithAlert); 114 | assert.end(); 115 | }); 116 | 117 | test('graph should receive an alert in the constructor', assert => { 118 | const graph = new Graph({alert: alertWithCondition, targets: ['firstTarget']}); 119 | graph.state.id = simpleGraphWithAlert.id; 120 | 121 | assert.deepEqual(graph.generate(), simpleGraphWithAlert); 122 | assert.end(); 123 | }); 124 | 125 | test('graph should add other targets when a target contains refs', assert => { 126 | const graph = new Graph({ 127 | targets: [ 128 | "alias(scaleToSeconds(summarize(sumSeries(target-1), '60m', 'sum', false), 60), 'alias-1')", 129 | "alias(scaleToSeconds(summarize(sumSeries(target-2), '60m', 'sum', false), 60), 'alias-2')", 130 | "alias(divideSeries(#B, #A), 'success rate')" 131 | ] 132 | }); 133 | 134 | const actualDivideTarget = graph.generate().targets[2]; 135 | const expectedDivideTarget = { 136 | hide: undefined, 137 | refId: 'C', 138 | target: 'alias(divideSeries(#B, #A), \'success rate\')', 139 | targetFull: "alias(divideSeries(alias(scaleToSeconds(summarize(sumSeries(target-2), '60m', 'sum', false), 60), 'alias-2'), alias(scaleToSeconds(summarize(sumSeries(target-1), '60m', 'sum', false), 60), 'alias-1')), 'success rate')", 140 | }; 141 | 142 | assert.deepEqual(actualDivideTarget, expectedDivideTarget); 143 | assert.end(); 144 | }); 145 | -------------------------------------------------------------------------------- /test/panels/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | require('./graph'); 22 | require('./singlestat'); 23 | require('./text'); 24 | require('./table'); 25 | require('./dashboard_list'); 26 | -------------------------------------------------------------------------------- /test/panels/singlestat.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | /* eslint-disable no-new */ 24 | var test = require('tape'); 25 | var SingleStat = require('../../grafana/panels/singlestat'); 26 | 27 | var simpleSingleStat = require('../fixtures/panels/simple_singlestat.js'); 28 | var overrideSingleStat = require('../fixtures/panels/override_singlestat.js'); 29 | 30 | test('simple SingleStat panel', function t(assert) { 31 | var graph = new SingleStat(); 32 | graph.state.id = simpleSingleStat.id; 33 | 34 | assert.deepEqual(graph.generate(), simpleSingleStat); 35 | assert.end(); 36 | }); 37 | 38 | test('SingleStat panel with overriden information', function t(assert) { 39 | var graph = new SingleStat({ 40 | span: 4, 41 | title: 'custom title', 42 | targets: ['target'], 43 | datasource: 'M3', 44 | arbitraryProperty: 'foo' 45 | }); 46 | graph.state.id = overrideSingleStat.id; 47 | 48 | assert.deepEqual(graph.generate(), overrideSingleStat); 49 | assert.end(); 50 | }); 51 | 52 | test('SingleStat can set title', function t(assert) { 53 | var title = 'title'; 54 | var graph = new SingleStat(); 55 | graph.setTitle(title); 56 | assert.deepEqual(graph.state.title, title); 57 | assert.end(); 58 | }); 59 | 60 | test('add graph to row and dashboard when passed', function t(assert) { 61 | var calledAddPanel = 0; 62 | var calledAddRow = 0; 63 | 64 | new SingleStat({ 65 | row: { 66 | addPanel: function addPanel() { 67 | calledAddPanel += 1; 68 | } 69 | }, 70 | 71 | dashboard: { 72 | addRow: function addRow() { 73 | calledAddRow += 1; 74 | } 75 | } 76 | }); 77 | 78 | assert.deepEqual(calledAddRow, 1); 79 | assert.deepEqual(calledAddPanel, 1); 80 | assert.end(); 81 | }); 82 | -------------------------------------------------------------------------------- /test/panels/table.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | /* eslint-disable no-new */ 24 | var test = require('tape'); 25 | var Table = require('../../grafana/panels/table'); 26 | 27 | var simpleTable = require('../fixtures/panels/simple_table.js'); 28 | var overrideTable = require('../fixtures/panels/override_table.js'); 29 | 30 | test('simple table', function t(assert) { 31 | var table = new Table(); 32 | table.state.id = simpleTable.id; 33 | assert.deepEqual(table.generate(), simpleTable); 34 | assert.end(); 35 | }); 36 | 37 | test('table with overriden information', function t(assert) { 38 | var table = new Table({ 39 | span: 4, 40 | title: 'custom title', 41 | targets: ['target'], 42 | datasource: 'M3', 43 | arbitraryProperty: 'foo' 44 | }); 45 | table.state.id = overrideTable.id; 46 | 47 | assert.deepEqual(table.generate(), overrideTable); 48 | assert.end(); 49 | }); 50 | 51 | test('add graph to row and dashboard when passed', function t(assert) { 52 | var calledAddPanel = 0; 53 | var calledAddRow = 0; 54 | 55 | new Table({ 56 | row: { 57 | addPanel: function addPanel() { 58 | calledAddPanel += 1; 59 | } 60 | }, 61 | 62 | dashboard: { 63 | addRow: function addRow() { 64 | calledAddRow += 1; 65 | } 66 | } 67 | }); 68 | 69 | assert.deepEqual(calledAddRow, 1); 70 | assert.deepEqual(calledAddPanel, 1); 71 | assert.end(); 72 | }); 73 | 74 | test('table with overriden info and title', function t(assert) { 75 | var table = new Table({ 76 | span: 4, 77 | targets: ['target'], 78 | datasource: 'M3', 79 | arbitraryProperty: 'foo' 80 | }); 81 | table.state.id = overrideTable.id; 82 | table.setTitle('custom title'); 83 | 84 | assert.deepEqual(table.generate(), overrideTable); 85 | assert.end(); 86 | }); 87 | -------------------------------------------------------------------------------- /test/panels/text.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var Text = require('../../grafana/panels/text'); 25 | 26 | var simpleText = require('../fixtures/panels/simple_text.js'); 27 | var overrideText = require('../fixtures/panels/override_text.js'); 28 | 29 | test('simple Text panel', function t(assert) { 30 | var graph = new Text(); 31 | graph.state.id = overrideText.id; 32 | 33 | assert.deepEqual(graph.generate(), simpleText); 34 | assert.end(); 35 | }); 36 | 37 | test('Text panel with overriden information', function t(assert) { 38 | var graph = new Text({ 39 | span: 4, 40 | content: 'TEST', 41 | height: '100px', 42 | transparent: true 43 | }); 44 | graph.state.id = overrideText.id; 45 | 46 | assert.deepEqual(graph.generate(), overrideText); 47 | assert.end(); 48 | }); 49 | 50 | test('Text can set title', function t(assert) { 51 | var title = 'title'; 52 | var graph = new Text(); 53 | graph.setTitle(title); 54 | assert.deepEqual(graph.state.title, title); 55 | assert.end(); 56 | }); 57 | 58 | test('add graph to row and dashboard when passed', function t(assert){ 59 | var calledAddPanel = 0; 60 | var calledAddRow = 0; 61 | 62 | new Text({ 63 | row: { 64 | addPanel: function addPanel() { 65 | calledAddPanel += 1; 66 | } 67 | }, 68 | dashboard: { 69 | addRow: function addRow() { 70 | calledAddRow += 1; 71 | } 72 | } 73 | }); 74 | 75 | assert.deepEqual(calledAddRow, 1); 76 | assert.deepEqual(calledAddPanel, 1); 77 | assert.end(); 78 | }); 79 | -------------------------------------------------------------------------------- /test/publish.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | "use strict"; 22 | const nock = require("nock"); 23 | const test = require("tape"); 24 | const config = require("../grafana/config"); 25 | const publish = require("../grafana/publish"); 26 | const Dashboard = require("../grafana/dashboard"); 27 | const ExternalLink = require("../grafana/external-link") 28 | 29 | // configuration values, held constant for assertions 30 | const baseUrl = "http://awesome.com"; 31 | const url = [baseUrl, "dashboard"].join("/"); 32 | const cookie = "auth=foo"; 33 | const headers = { asdf: ["qwer"] }; 34 | const title = "Test Dashboard"; 35 | const tags = ["tag1", "tag2"]; 36 | const refresh = "1m"; 37 | const templateconst1 = { 38 | name: "myconst1", 39 | options: ["a", "b"] 40 | }; 41 | const templateconst2 = { 42 | name: "marconst2", 43 | options: [0, 1, 2, 3, 4] 44 | }; 45 | const annotation1 = { 46 | name: "myAnnotation1", 47 | target: "my.annotation.target.1" 48 | }; 49 | 50 | const externalLinks = [ 51 | new ExternalLink({ 52 | title: "Uber Home Page", 53 | url: "www.uber.com", 54 | }) 55 | ] 56 | 57 | const dashboard = new Dashboard({ 58 | title: title, 59 | tags: tags, 60 | refresh: refresh, 61 | templating: [templateconst1, templateconst2], 62 | annotations: [annotation1], 63 | links: externalLinks, 64 | }); 65 | 66 | test("Publish dashboard - requires dashboard", function t(assert) { 67 | assert.throws(function assertThrows() { 68 | config.configure(); 69 | publish(); 70 | }, /UnfulfilledRequirement/); 71 | assert.end(); 72 | }); 73 | 74 | test("Publish dashboard - invalid state", function t(assert) { 75 | assert.throws(function assertThrows() { 76 | config.configure(); 77 | publish({}); 78 | }, /InvalidState/); 79 | assert.end(); 80 | }); 81 | 82 | test("Publish dashboard - invalid title", function t(assert) { 83 | assert.throws(function assertThrows() { 84 | config.configure(); 85 | publish({ 86 | state: {} 87 | }); 88 | }, /InvalidState/); 89 | assert.end(); 90 | }); 91 | 92 | test("Publish dashboard - misconfigured url", function t(assert) { 93 | assert.throws(function assertThrows() { 94 | config.configure({ 95 | cookie: cookie, 96 | url: null 97 | }); 98 | publish({ 99 | state: { 100 | title: title 101 | } 102 | }); 103 | }, /Misconfigured/); 104 | assert.end(); 105 | }); 106 | 107 | test("Publish dashboard - misconfigured cookie", function t(assert) { 108 | assert.throws(function assertThrows() { 109 | config.configure({ 110 | cookie: null, 111 | url: url 112 | }); 113 | publish({ 114 | state: { 115 | title: title 116 | } 117 | }); 118 | }, /Misconfigured/); 119 | assert.end(); 120 | }); 121 | 122 | test("Publish dashboard - default empty headers", function(assert) { 123 | assert.plan(1); 124 | config.configure({ 125 | cookie: cookie, 126 | headers: null, 127 | url: url 128 | }); 129 | nock(baseUrl) 130 | .post("/dashboard") 131 | .reply(200, function createdHandler() { 132 | const headerType = typeof this.req.headers; 133 | assert.equal(headerType, "object"); 134 | }); 135 | publish(dashboard); // 200 136 | }); 137 | 138 | test("Publish dashboard - client error", function(assert) { 139 | assert.plan(1); 140 | config.configure({ 141 | cookie: cookie, 142 | url: url 143 | }); 144 | nock(baseUrl) 145 | .post("/dashboard") 146 | .reply(412, { 147 | status: "version-mismatch", 148 | message: "Version mismatch" 149 | }); 150 | publish(dashboard).catch(e => { 151 | assert.equal(e.info().response.status, 412); 152 | }); 153 | }); 154 | 155 | test("Publish dashboard - client error (invalid)", function(assert) { 156 | assert.plan(1); 157 | config.configure({ 158 | cookie: cookie, 159 | url: url 160 | }); 161 | nock(baseUrl) 162 | .post("/dashboard") 163 | .reply(400, { status: "error" }); 164 | publish(dashboard).catch(e => { 165 | assert.equal(e.info().response.status, 400); 166 | }); 167 | }); 168 | 169 | test("Publish dashboard - client error (n/a)", function t(assert) { 170 | assert.plan(1); 171 | config.configure({ 172 | cookie: cookie, 173 | url: url 174 | }); 175 | nock(baseUrl) 176 | .post("/dashboard") 177 | .reply(412, { status: "error" }); 178 | publish(dashboard).catch(e => { 179 | assert.equal(e.info().response.status, 412); 180 | }); 181 | }); 182 | 183 | test("Publish dashboard - bad response", function(assert) { 184 | assert.plan(1); 185 | config.configure({ 186 | cookie: cookie, 187 | url: url 188 | }); 189 | nock(baseUrl) 190 | .post("/dashboard") 191 | .reply(200, "foo"); 192 | publish(dashboard).then(response => { 193 | assert.equal(response, "foo"); 194 | }); 195 | }); 196 | 197 | test("Publish dashboard - server unavailable", function(assert) { 198 | assert.plan(1); 199 | config.configure({ 200 | cookie: cookie, 201 | url: "http://111.111.111.111" 202 | }); 203 | publish(dashboard).catch(e => { 204 | assert.equal(e.message, "network timeout at: http://111.111.111.111/"); 205 | }); 206 | }); 207 | 208 | test("Publish dashboard - server error", function(assert) { 209 | assert.plan(1); 210 | config.configure({ 211 | cookie: cookie, 212 | url: url 213 | }); 214 | nock(baseUrl) 215 | .post("/dashboard") 216 | .reply(500); 217 | publish(dashboard).catch(e => { 218 | assert.equal(e.info().response.status, 500); 219 | }); 220 | }); 221 | 222 | test("Publish dashboard - success", function(assert) { 223 | assert.plan(2); 224 | config.configure({ 225 | cookie: cookie, 226 | url: url 227 | }); 228 | const expectedBody = { 229 | dashboard: dashboard.generate(), 230 | overwrite: true 231 | }; 232 | // hijack the calls to elastic search, need to test both response codes 233 | // since the initial request will return a 201 and the subsequent will 234 | // return a 200. 235 | nock(baseUrl) 236 | .post("/dashboard") 237 | .reply(201, function createdHandler(uri, requestBody) { 238 | assert.deepEqual(requestBody, expectedBody); 239 | }) 240 | .post("/dashboard") 241 | .reply(200, function okHandler(uri, requestBody) { 242 | assert.deepEqual(requestBody, expectedBody); 243 | }); 244 | publish(dashboard) // 201 245 | .then(() => publish(dashboard)); // 200 246 | }); 247 | 248 | test("Publish dashboard - success w/ custom timeout", function(assert) { 249 | config.configure({ 250 | cookie: cookie, 251 | url: url 252 | }); 253 | const expectedBody = { 254 | dashboard: dashboard.generate(), 255 | overwrite: true 256 | }; 257 | // hijack the calls to elastic search, need to test both response codes 258 | // since the initial request will return a 201 and the subsequent will 259 | // return a 200. 260 | nock(baseUrl) 261 | .post("/dashboard") 262 | .reply(201, function createdHandler(uri, requestBody) { 263 | assert.deepEqual(requestBody, expectedBody); 264 | }) 265 | .post("/dashboard") 266 | .reply(200, function okHandler(uri, requestBody) { 267 | assert.deepEqual(requestBody, expectedBody); 268 | assert.end(); 269 | }); 270 | publish(dashboard, { 271 | timeout: 2000 272 | }) // 201 273 | .then(() => 274 | publish(dashboard, { 275 | timeout: 2000 276 | }) 277 | ); // 200 278 | }); 279 | 280 | test("Publish dashboard - passes headers", function(assert) { 281 | config.configure({ 282 | cookie: cookie, 283 | headers: headers, 284 | url: url 285 | }); 286 | // hijack the calls to elastic search, need to test both response codes 287 | // since the initial request will return a 201 and the subsequent will 288 | // return a 200. 289 | nock(baseUrl) 290 | .post("/dashboard") 291 | .reply(201, function createdHandler() { 292 | const reqHeaders = this.req.headers; 293 | Object.keys(headers).forEach(function(key) { 294 | assert.deepEqual(reqHeaders[key], headers[key]); 295 | }); 296 | }) 297 | .post("/dashboard") 298 | .reply(200, function okHandler() { 299 | const reqHeaders = this.req.headers; 300 | Object.keys(headers).forEach(function(key) { 301 | assert.deepEqual(reqHeaders[key], headers[key]); 302 | }); 303 | assert.end(); 304 | }); 305 | publish(dashboard) // 201 306 | .then(() => publish(dashboard)); // 200 307 | }); 308 | 309 | test("Publish dashboard - follows redirect", assert => { 310 | assert.plan(1); 311 | const redirectBase = "http://willredirect.com"; 312 | config.configure({ 313 | cookie: cookie, 314 | url: redirectBase + "/dashboard" 315 | }); 316 | const expectedBody = { 317 | dashboard: dashboard.generate(), 318 | overwrite: true 319 | }; 320 | // we need to specify 307 in order for a POST redirect to be followed correctly 321 | nock(redirectBase) 322 | .defaultReplyHeaders({ 323 | Location: url 324 | }) 325 | .post("/dashboard") 326 | .reply(307); 327 | 328 | nock(baseUrl) 329 | .post("/dashboard") 330 | .reply(200, function okHandler(uri, requestBody) { 331 | assert.deepEqual(requestBody, expectedBody); 332 | }); 333 | publish(dashboard); 334 | }); 335 | -------------------------------------------------------------------------------- /test/row.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var Row = require('../grafana/row'); 25 | 26 | var simpleRow = require('./fixtures/simple_row.js'); 27 | var overrideRow = require('./fixtures/override_row.js'); 28 | var panelData = { 29 | foo: 'foo', 30 | bar: 'bar', 31 | baz: 1 32 | }; 33 | 34 | test('Simple row', function t(assert) { 35 | var row = new Row(); 36 | assert.deepEqual(row.generate(), simpleRow); 37 | assert.end(); 38 | }); 39 | 40 | test('Row with overriden information', function t(assert) { 41 | var panel1 = { 42 | generate: function generate() { 43 | return panelData; 44 | } 45 | }; 46 | var row = new Row({ 47 | title: 'My Row', 48 | height: '1000px', 49 | editable: false, 50 | collapse: true, 51 | panels: [panel1] 52 | }); 53 | assert.deepEqual(row.generate(), overrideRow); 54 | assert.end(); 55 | }); 56 | 57 | test('Add panels to row when passed', function t(assert) { 58 | var panel1 = { 59 | foo: 'foo', 60 | bar: 'bar', 61 | baz: 1 62 | }; 63 | var panel2 = { 64 | foo: 'foo2', 65 | bar: 'bar2', 66 | baz: 2 67 | }; 68 | var row = new Row({ 69 | panels: [panel1, panel2] 70 | }); 71 | 72 | assert.deepEqual(row.state.panels, [panel1, panel2]); 73 | assert.end(); 74 | }); 75 | 76 | test('Row can add panels', function t(assert) { 77 | var row = new Row({ 78 | title: 'My Row', 79 | height: '1000px', 80 | editable: false, 81 | collapse: true 82 | }); 83 | var panel1 = { 84 | foo: 'foo', 85 | bar: 'bar', 86 | baz: 1 87 | }; 88 | var panel2 = { 89 | foo: 'foo2', 90 | bar: 'bar2', 91 | baz: 2 92 | }; 93 | 94 | row.addPanel(panel1); 95 | row.addPanel(panel2); 96 | assert.deepEqual(row.panels, [panel1, panel2]); 97 | assert.end(); 98 | }); 99 | 100 | test('Row generates state', function t(assert) { 101 | var panel = { 102 | generate: function generate() { 103 | return panelData; 104 | } 105 | }; 106 | var row = new Row({ 107 | title: 'My Row', 108 | height: '1000px', 109 | editable: false, 110 | collapse: true, 111 | panels: [panel] 112 | }); 113 | 114 | assert.deepEqual(row.generate(), overrideRow); 115 | assert.end(); 116 | }); 117 | -------------------------------------------------------------------------------- /test/target.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | /*global console*/ 22 | 23 | 'use strict'; 24 | 25 | var util = require('util'); 26 | var test = require('tape'); 27 | var Target = require('../grafana/target'); 28 | 29 | test('Target throws exception on invalid invocation', function t(assert) { 30 | assert.throws(function shouldThrow() { 31 | new Target(); 32 | }, /Error/); 33 | assert.end(); 34 | }); 35 | 36 | test('Target can initialize as a single string source', function t(assert) { 37 | var arg = 'path.to.metric'; 38 | var target = new Target(arg); 39 | assert.equal(target.source, arg); 40 | assert.end(); 41 | }); 42 | 43 | /*eslint-disable*/ 44 | test('Target can initialize as a single interpolated string source', function t(assert) { 45 | /*eslint-enable*/ 46 | var arg = 'path.to.%s.metric'; 47 | var sub = 'foo'; 48 | var argFinal = 'path.to.foo.metric'; 49 | var target = new Target(arg, sub); 50 | assert.equal(target.source, argFinal); 51 | assert.end(); 52 | }); 53 | 54 | test('Target can initialize as a source and function', function t(assert) { 55 | var arg = 'path.to.metric'; 56 | new Target(arg). 57 | averageSeries(). 58 | movingAverage('$smoothing'). 59 | alias('Total P95'); 60 | assert.end(); 61 | }); 62 | 63 | test('Target can initialize and chain methods', function t(assert) { 64 | var arg = 'path.to.metric'; 65 | var target = new Target(arg). 66 | averageSeries(). 67 | movingAverage('$smoothing'). 68 | alias('Total P95'); 69 | 70 | Object.keys(Target.PRIMITIVES).forEach(function eachPrimitive(primitive) { 71 | assert.ok((typeof target[primitive]) === 'function'); 72 | }); 73 | assert.end(); 74 | }); 75 | 76 | test('Target warns on incorrect primitive invocation', function t(assert) { 77 | assert.plan(2); 78 | /*eslint-disable*/ 79 | console.warn = function warn(str) { 80 | assert.ok(str); 81 | }; 82 | console.trace = function trace(str) { 83 | assert.notOk(str); 84 | }; 85 | new Target('foo').alpha(); 86 | /*eslint-enable*/ 87 | 88 | assert.end(); 89 | }); 90 | 91 | test('Target color methods are generated correctly', function t(assert) { 92 | var arg = 'path.to.metric'; 93 | var target = new Target(arg); 94 | 95 | Target.COLORS.forEach(function eachColor(color) { 96 | assert.ok((typeof target[color]) === 'function'); 97 | var str = target[color]().toString(); 98 | var expected = util.format('color(path.to.metric, "%s")', color); 99 | assert.equal(str, expected); 100 | }); 101 | assert.end(); 102 | }); 103 | 104 | test('Target helper-method - color', function t(assert) { 105 | var arg = 'path.to.metric'; 106 | var expected = 'color(path.to.metric, "COLOR")'; 107 | var target = new Target(arg).color('COLOR').toString(); 108 | assert.equal(target, expected); 109 | assert.end(); 110 | }); 111 | 112 | test('Target helper-method - cpu', function t(assert) { 113 | var arg = 'path.to.metric'; 114 | var expected = ['removeBelowValue(', 115 | 'scale(', 116 | 'derivative(', 117 | 'path.to.metric), ', 118 | '0.016666666667), 0)'].join(''); 119 | var target = new Target(arg).cpu().toString(); 120 | assert.equal(target, expected); 121 | assert.end(); 122 | }); 123 | 124 | test('Target helper-method - reallyFaded', function t(assert) { 125 | var arg = 'path.to.metric'; 126 | var expected = 'alpha(lineWidth(path.to.metric, 5), 0.5)'; 127 | var target = new Target(arg).reallyFaded().toString(); 128 | assert.equal(target, expected); 129 | assert.end(); 130 | }); 131 | 132 | test('Target helper-method - faded', function t(assert) { 133 | var arg = 'path.to.metric'; 134 | var expected = 'lineWidth(alpha(path.to.metric, 0.5), 5)'; 135 | var target = new Target(arg).faded().toString(); 136 | assert.equal(target, expected); 137 | assert.end(); 138 | }); 139 | 140 | test('Target helper-method - lastWeek', function t(assert) { 141 | var arg = 'path.to.metric'; 142 | var expected = 'timeShift(path.to.metric, "7d")'; 143 | var target = new Target(arg).lastWeek().toString(); 144 | assert.equal(target, expected); 145 | assert.end(); 146 | }); 147 | 148 | test('Target helper-method - summarize15min', function t(assert) { 149 | var arg = 'path.to.metric'; 150 | var expected = 'summarize(path.to.metric, "15min")'; 151 | var target = new Target(arg).summarize15min().toString(); 152 | assert.equal(target, expected); 153 | assert.equal(target.hide, undefined); 154 | assert.end(); 155 | }); 156 | 157 | test('Target can call hide()', function t(assert) { 158 | var target = new Target('path.to.metric').hide(); 159 | 160 | assert.equal(target.toString(), 'path.to.metric'); 161 | assert.equal(target.hide, true); 162 | assert.end(); 163 | }); 164 | -------------------------------------------------------------------------------- /test/templates/custom.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var Custom = require('../../grafana/templates/custom'); 25 | 26 | var simpleCustom = require('../fixtures/templates/simple_custom'); 27 | var overrideCustom = require('../fixtures/templates/override_custom'); 28 | var overrideCustomTextValue = 29 | require('../fixtures/templates/override_custom_text_value'); 30 | 31 | test('Custom template has defaults', function t(assert) { 32 | var template = new Custom(); 33 | assert.deepEqual(template.state, simpleCustom); 34 | assert.end(); 35 | }); 36 | 37 | test('Custom template creates state', function t(assert) { 38 | var name = 'custom'; 39 | var options = ['a', 'b']; 40 | var template = new Custom({ 41 | name: name, 42 | options: options, 43 | arbitraryProperty: 'foo' 44 | }); 45 | assert.deepEqual(template.state, overrideCustom); 46 | assert.end(); 47 | }); 48 | 49 | test('Custom template generates state', function t(assert) { 50 | var name = 'custom'; 51 | var options = ['a', 'b']; 52 | var template = new Custom({ 53 | name: name, 54 | options: options, 55 | arbitraryProperty: 'foo' 56 | }); 57 | assert.deepEqual(template.generate(), overrideCustom); 58 | assert.end(); 59 | }); 60 | 61 | test('Custom template can add options', function t(assert) { 62 | var name = 'custom'; 63 | var options = ['a', 'b']; 64 | var template = new Custom({ 65 | name: name, 66 | options: options, 67 | arbitraryProperty: 'foo' 68 | }); 69 | assert.deepEqual(template.state, overrideCustom); 70 | assert.end(); 71 | }); 72 | 73 | test('Custom template can specify text and value', function t(assert) { 74 | var name = 'custom'; 75 | var opt = { 76 | text: 'myText', 77 | value: 'myValue' 78 | }; 79 | var template = new Custom({ 80 | name: name, 81 | options: [opt], 82 | arbitraryProperty: 'foo' 83 | }); 84 | assert.deepEqual(template.generate(), overrideCustomTextValue); 85 | assert.end(); 86 | }); 87 | 88 | test('Custom template overwrites default state', function t(assert) { 89 | var defaultTemplate = new Custom(); 90 | assert.equal(defaultTemplate.state.includeAll, false); 91 | 92 | var customTemplate = new Custom({ 93 | includeAll: true, 94 | arbitraryProperty: 'foo' 95 | }); 96 | assert.equal(customTemplate.state.includeAll, true); 97 | assert.equal(customTemplate.state.allValue, ''); 98 | assert.deepEqual(customTemplate.state.current, {}); 99 | 100 | var customWithAllValue = new Custom({ 101 | includeAll: true, 102 | arbitraryProperty: 'foo', 103 | allValue: 'grafana', 104 | }); 105 | assert.equal(customWithAllValue.state.includeAll, true); 106 | assert.deepEqual(customTemplate.state.current, {}); 107 | assert.equal(customWithAllValue.state.allValue, 'grafana') 108 | 109 | var allIsDefault = new Custom({ 110 | includeAll: true, 111 | arbitraryProperty: 'foo', 112 | options: [{ text: 'grafana', value: 'grafana' }] 113 | }); 114 | assert.equal(allIsDefault.state.includeAll, true); 115 | assert.equal(allIsDefault.state.allValue, '') 116 | assert.deepEqual(customTemplate.state.current, {}); 117 | 118 | var firstIsDefault = new Custom({ 119 | arbitraryProperty: 'foo', 120 | options: [{ text: 'grafana', value: 'grafana' }] 121 | }); 122 | assert.equal(firstIsDefault.state.includeAll, false); 123 | assert.equal(firstIsDefault.state.allValue, '') 124 | assert.equal(firstIsDefault.state.current, firstIsDefault.state.options[0]); 125 | 126 | assert.end(); 127 | }); 128 | 129 | test('Custom template supports custom default', function t(assert) { 130 | const defaultOption = { text: 'dash-gen', value: 'dash-gen' } 131 | var definedDefault = new Custom({ 132 | includeAll: true, 133 | defaultValue: defaultOption.value, 134 | options: [{ text: 'grafana', value: 'grafana' }, defaultOption] 135 | }); 136 | assert.equal(definedDefault.state.includeAll, true); 137 | assert.equal(definedDefault.state.allValue, '') 138 | assert.equal(definedDefault.state.current, defaultOption); 139 | 140 | assert.throws( 141 | () => new Custom({ 142 | includeAll: true, 143 | defaultValue: defaultOption.value, 144 | options: [{ text: 'grafana', value: 'grafana' }] 145 | }), 146 | new SyntaxError("default value not found in options list"), 147 | ); 148 | 149 | assert.throws( 150 | () => new Custom({ 151 | includeAll: true, 152 | defaultValue: defaultOption.value, 153 | }), 154 | new SyntaxError("cannot define default value without any options"), 155 | ); 156 | 157 | assert.throws( 158 | () => new Custom({ 159 | defaultValue: defaultOption.value, 160 | }), 161 | new SyntaxError("cannot define default value without any options"), 162 | ); 163 | 164 | assert.end(); 165 | }); 166 | 167 | -------------------------------------------------------------------------------- /test/templates/index.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | require('./custom'); 24 | require('./query'); 25 | -------------------------------------------------------------------------------- /test/templates/query.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015 Uber Technologies, Inc. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 'use strict'; 22 | 23 | var test = require('tape'); 24 | var Query = require('../../grafana/templates/query'); 25 | 26 | var simpleQuery = require('../fixtures/templates/simple_query'); 27 | var overrideQuery = require('../fixtures/templates/override_query'); 28 | 29 | test('Interval template has defaults', function t(assert) { 30 | var template = new Query('servers.*', { 31 | name: 'foo', 32 | datasource: 'default' 33 | }); 34 | assert.deepEqual(template.generate(), simpleQuery); 35 | assert.end(); 36 | }); 37 | 38 | test('Query template requires query', function t(assert) { 39 | assert.throws(function catchError() { 40 | var template = new Query(null, { 41 | name: 'foo', 42 | datasource: 'default' 43 | }); 44 | template.state.refresh = true; 45 | assert.fail(); 46 | }, Error); 47 | assert.end(); 48 | }); 49 | 50 | test('Query template options default to empty objects', function t(assert) { 51 | assert.throws(function catchError() { 52 | var template = new Query('servers.*'); 53 | template.state.refresh = true; 54 | assert.fail(); 55 | }, Error); 56 | assert.end(); 57 | }); 58 | 59 | test('Query template requires name', function t(assert) { 60 | assert.throws(function catchTypeError() { 61 | var template = new Query('servers.*', { 62 | datasource: 'default' 63 | }); 64 | template.state.refresh = true; 65 | assert.fail(); 66 | }, Error); 67 | assert.end(); 68 | }); 69 | 70 | test('Query template requires datasource', function t(assert) { 71 | assert.throws(function catchTypeError() { 72 | var template = new Query('servers.*', { 73 | name: 'foo' 74 | }); 75 | template.state.refresh = true; 76 | assert.fail(); 77 | }, Error); 78 | assert.end(); 79 | }); 80 | 81 | test('Query template creates state', function t(assert) { 82 | var template = new Query('servers.*', { 83 | name: 'foo', 84 | datasource: 'default' 85 | }); 86 | assert.deepEqual(template.generate(), simpleQuery); 87 | assert.end(); 88 | }); 89 | 90 | test('Query template state cannot be mutated after init', function t(assert) { 91 | var template = new Query('servers.*', { 92 | name: 'foo', 93 | datasource: 'default' 94 | }); 95 | assert.deepEqual(template.generate(), simpleQuery); 96 | 97 | assert.throws(function catchTypeError() { 98 | template.state.refresh = true; 99 | }, TypeError); 100 | 101 | assert.end(); 102 | }); 103 | 104 | test('Query template state overridden on init', function t(assert) { 105 | var template = new Query('stats.*', { 106 | name: 'template', 107 | datasource: 'datasource', 108 | includeAll: false, 109 | allFormat: 'glob', 110 | allValue: '*', 111 | refresh: true, 112 | multi: true 113 | }); 114 | assert.deepEqual(template.generate(), overrideQuery); 115 | assert.end(); 116 | }); 117 | --------------------------------------------------------------------------------