Merge branch 'master' of github.com:grafana/grafana

Conflicts:
	examples/nginx-app/package.json
	examples/nginx-app/plugin.json
This commit is contained in:
Torkel Ödegaard
2016-03-11 12:39:10 +01:00
52 changed files with 155 additions and 291 deletions

View File

@ -64,9 +64,19 @@ Name | Description
`metrics(namespace)` | Returns a list of metrics in the namespace.
`dimension_keys(namespace)` | Returns a list of dimension keys in the namespace.
`dimension_values(region, namespace, metric, dimension_key)` | Returns a list of dimension values matching the specified `region`, `namespace`, `metric` and `dimension_key`.
`ebs_volume_ids(region, instance_id)` | Returns a list of volume id matching the specified `region`, `instance_id`.
`ec2_instance_attribute(region, attribute_name, filters)` | Returns a list of attribute matching the specified `region`, `attribute_name`, `filters`.
For details about the metrics CloudWatch provides, please refer to the [CloudWatch documentation](https://docs.aws.amazon.com/AmazonCloudWatch/latest/DeveloperGuide/CW_Support_For_AWS.html).
The `ec2_instance_attribute` query take `filters` in JSON format.
You can specify [pre-defined filters of ec2:DescribeInstances](http://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstances.html).
Specify like `{ filter_name1: [ filter_value1 ], filter_name2: [ filter_value2 ] }`
Example `ec2_instance_attribute()` query
ec2_instance_attribute(us-east-1, InstanceId, { "tag:Environment": [ "production" ] })
![](/img/v2/cloudwatch_templating.png)
## Cost

View File

@ -74,7 +74,7 @@ page_keywords: grafana, admin, http, api, documentation, datasource
"jsonData":null
}
## Get a single data sources by Name
## Get a single data source by Name
`GET /api/datasources/name/:name`
@ -107,6 +107,26 @@ page_keywords: grafana, admin, http, api, documentation, datasource
"jsonData":null
}
## Get data source Id by Name
`GET /api/datasources/id/:name`
**Example Request**:
GET /api/datasources/id/test_datasource HTTP/1.1
Accept: application/json
Content-Type: application/json
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
**Example Response**:
HTTP/1.1 200
Content-Type: application/json
{
"id":1
}
## Create data source
`POST /api/datasources`

View File

@ -373,7 +373,7 @@ Set to `true` to enable auto sign up of users who do not exist in Grafana DB. De
### provider
Valid values are `memory`, `file`, `mysql`, `postgres`, `memcache`. Default is `file`.
Valid values are `memory`, `file`, `mysql`, `postgres`, `memcache` or `redis`. Default is `file`.
### provider_config
@ -384,6 +384,7 @@ session provider you have configured.
- **mysql:** go-sql-driver/mysql dsn config string, e.g. `user:password@tcp(127.0.0.1:3306)/database_name`
- **postgres:** ex: user=a password=b host=localhost port=5432 dbname=c sslmode=disable
- **memcache:** ex: 127.0.0.1:11211
- **redis:** ex: `addr=127.0.0.1:6379,pool_size=100,db=grafana`
If you use MySQL or Postgres as the session store you need to create the
session table manually.

View File

@ -6,7 +6,7 @@ page_keywords: grafana, ldap, configuration, documentation, integration
# LDAP Integration
Grafana 2.1 ships with a strong LDAP integration feature. The LDAP integration in Grafana allows your
Grafana (2.1 and newer) ships with a strong LDAP integration feature. The LDAP integration in Grafana allows your
Grafana users to login with their LDAP credentials. You can also specify mappings between LDAP
group memberships and Grafana Organization user roles.

View File

@ -1,3 +1,4 @@
## Example plugin implementations
[datasource-plugin-genericdatsource](https://github.com/grafana/datasource-plugin-genericdatasource/tree/3.0)
datasource:[simple-json-datasource](https://github.com/grafana/simple-json-datasource)
app: [example-app](https://github.com/grafana/example-app)

View File

@ -1,7 +0,0 @@
.DS_Store
node_modules
tmp/*
npm-debug.log
dist/*

View File

@ -1,13 +0,0 @@
{
"disallowImplicitTypeConversion": ["string"],
"disallowKeywords": ["with"],
"disallowMultipleLineBreaks": true,
"disallowMixedSpacesAndTabs": true,
"disallowTrailingWhitespace": true,
"requireSpacesInFunctionExpression": {
"beforeOpeningCurlyBrace": true
},
"disallowSpacesInsideArrayBrackets": true,
"disallowSpacesInsideParentheses": true,
"validateIndentation": 2
}

View File

@ -1,36 +0,0 @@
{
"browser": true,
"esnext": true,
"bitwise":false,
"curly": true,
"eqnull": true,
"devel": true,
"eqeqeq": true,
"forin": false,
"immed": true,
"supernew": true,
"expr": true,
"indent": 2,
"latedef": true,
"newcap": true,
"noarg": true,
"noempty": true,
"undef": true,
"boss": true,
"trailing": true,
"laxbreak": true,
"laxcomma": true,
"sub": true,
"unused": true,
"maxdepth": 6,
"maxlen": 140,
"globals": {
"System": true,
"define": true,
"require": true,
"Chromath": false,
"setImmediate": true
}
}

View File

@ -1,54 +0,0 @@
module.exports = function(grunt) {
require('load-grunt-tasks')(grunt);
grunt.loadNpmTasks('grunt-execute');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.initConfig({
clean: ["dist"],
copy: {
src_to_dist: {
cwd: 'src',
expand: true,
src: ['**/*', '!**/*.js', '!**/*.scss'],
dest: 'dist'
},
pluginDef: {
expand: true,
src: ['plugin.json', 'readme.md'],
dest: 'dist',
}
},
watch: {
rebuild_all: {
files: ['src/**/*', 'plugin.json', 'readme.md'],
tasks: ['default'],
options: {spawn: false}
},
},
babel: {
options: {
sourceMap: true,
presets: ["es2015"],
plugins: ['transform-es2015-modules-systemjs', "transform-es2015-for-of"],
},
dist: {
files: [{
cwd: 'src',
expand: true,
src: ['**/*.js'],
dest: 'dist',
ext:'.js'
}]
},
},
});
grunt.registerTask('default', ['clean', 'copy:src_to_dist', 'copy:pluginDef', 'babel']);
};

View File

@ -1,37 +0,0 @@
{
"name": "kentik-app",
"private": true,
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/raintank/kentik-app-poc.git"
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/raintank/kentik-app-poc/issues"
},
"devDependencies": {
"grunt": "~0.4.5",
"babel": "~6.5.1",
"grunt-babel": "~6.0.0",
"grunt-contrib-copy": "~0.8.2",
"grunt-contrib-watch": "^0.6.1",
"grunt-contrib-uglify": "~0.11.0",
"grunt-systemjs-builder": "^0.2.5",
"load-grunt-tasks": "~3.2.0",
"grunt-execute": "~0.2.2",
"grunt-contrib-clean": "~0.6.0"
},
"dependencies": {
"babel-plugin-transform-es2015-modules-systemjs": "^6.5.0",
"babel-preset-es2015": "^6.5.0",
"lodash": "~4.0.0"
},
"homepage": "https://github.com/raintank/kentik-app-poc#readme"
}

View File

@ -1,7 +0,0 @@
## Overview
This application is an example app.
### Awesome
Even though it does not have any features it is still pretty awesome.

View File

@ -1,3 +0,0 @@
<h3>
Nginx config!
</h3>

View File

@ -1,6 +0,0 @@
export class NginxAppConfigCtrl {
}
NginxAppConfigCtrl.templateUrl = 'components/config.html';

View File

@ -1,3 +0,0 @@
<h3>
Logs page!
</h3>

View File

@ -1,6 +0,0 @@
export class LogsPageCtrl {
}
LogsPageCtrl.templateUrl = 'components/logs.html';

View File

@ -1,3 +0,0 @@
<h3>
Stream page!
</h3>

View File

@ -1,6 +0,0 @@
export class StreamPageCtrl {
}
StreamPageCtrl.templateUrl = 'components/stream.html';

View File

@ -1,12 +0,0 @@
export default class NginxDatasource {
constructor() {}
query(options) {
return [];
}
testDatasource() {
return false;
}
}

View File

@ -1,5 +0,0 @@
import {Datasource} from './datasource';
export {
Datasource
};

View File

@ -1,5 +0,0 @@
{
"type": "datasource",
"name": "Nginx Datasource",
"id": "nginx-datasource"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

View File

@ -1,9 +0,0 @@
import {LogsPageCtrl} from './components/logs';
import {StreamPageCtrl} from './components/stream';
import {NginxAppConfigCtrl} from './components/config';
export {
NginxAppConfigCtrl as ConfigCtrl,
StreamPageCtrl,
LogsPageCtrl
};

View File

@ -1,15 +0,0 @@
import {PanelCtrl} from 'app/plugins/sdk';
class NginxPanelCtrl extends PanelCtrl {
constructor($scope, $injector) {
super($scope, $injector);
}
}
NginxPanelCtrl.template = '<h2>nginx!</h2>';
export {
NginxPanelCtrl as PanelCtrl
};

View File

@ -1,5 +0,0 @@
{
"type": "panel",
"name": "Nginx Panel",
"id": "nginx-panel"
}

View File

@ -167,11 +167,10 @@ func Register(r *macaron.Macaron) {
r.Put("/:id", bind(m.UpdateDataSourceCommand{}), UpdateDataSource)
r.Delete("/:id", DeleteDataSource)
r.Get("/:id", wrap(GetDataSourceById))
r.Get("/name/:name", wrap(GetDataSourceByName))
}, reqOrgAdmin)
r.Group("/datasources/name/:name", func() {
r.Get("/", wrap(GetDataSourceByName))
}, reqOrgAdmin)
r.Get("/datasources/id/:name", wrap(GetDataSourceIdByName), reqSignedIn)
r.Group("/plugins", func() {
r.Get("/", wrap(GetPluginList))

View File

@ -55,8 +55,10 @@ func init() {
"S3BytesWritten", "S3BytesRead", "HDFSUtilization", "HDFSBytesRead", "HDFSBytesWritten", "MissingBlocks", "CorruptBlocks", "TotalLoad", "MemoryTotalMB", "MemoryReservedMB", "MemoryAvailableMB", "MemoryAllocatedMB", "PendingDeletionBlocks", "UnderReplicatedBlocks", "DfsPendingReplicationBlocks", "CapacityRemainingGB",
"HbaseBackupFailed", "MostRecentBackupDuration", "TimeSinceLastSuccessfulBackup"},
"AWS/ES": {"ClusterStatus.green", "ClusterStatus.yellow", "ClusterStatus.red", "Nodes", "SearchableDocuments", "DeletedDocuments", "CPUUtilization", "FreeStorageSpace", "JVMMemoryPressure", "AutomatedSnapshotFailure", "MasterCPUUtilization", "MasterFreeStorageSpace", "MasterJVMMemoryPressure", "ReadLatency", "WriteLatency", "ReadThroughput", "WriteThroughput", "DiskQueueLength", "ReadIOPS", "WriteIOPS"},
"AWS/Events": {"Invocations", "FailedInvocations", "TriggeredRules", "MatchedEvents", "ThrottledRules"},
"AWS/Kinesis": {"PutRecord.Bytes", "PutRecord.Latency", "PutRecord.Success", "PutRecords.Bytes", "PutRecords.Latency", "PutRecords.Records", "PutRecords.Success", "IncomingBytes", "IncomingRecords", "GetRecords.Bytes", "GetRecords.IteratorAgeMilliseconds", "GetRecords.Latency", "GetRecords.Success"},
"AWS/Lambda": {"Invocations", "Errors", "Duration", "Throttles"},
"AWS/Logs": {"IncomingBytes", "IncomingLogEvents", "ForwardedBytes", "ForwardedLogEvents", "DeliveryErrors", "DeliveryThrottling"},
"AWS/ML": {"PredictCount", "PredictFailureCount"},
"AWS/OpsWorks": {"cpu_idle", "cpu_nice", "cpu_system", "cpu_user", "cpu_waitio", "load_1", "load_5", "load_15", "memory_buffers", "memory_cached", "memory_free", "memory_swap", "memory_total", "memory_used", "procs"},
"AWS/Redshift": {"CPUUtilization", "DatabaseConnections", "HealthStatus", "MaintenanceMode", "NetworkReceiveThroughput", "NetworkTransmitThroughput", "PercentageDiskSpaceUsed", "ReadIOPS", "ReadLatency", "ReadThroughput", "WriteIOPS", "WriteLatency", "WriteThroughput"},
@ -85,8 +87,10 @@ func init() {
"AWS/ELB": {"LoadBalancerName", "AvailabilityZone"},
"AWS/ElasticMapReduce": {"ClusterId", "JobFlowId", "JobId"},
"AWS/ES": {},
"AWS/Events": {"RuleName"},
"AWS/Kinesis": {"StreamName"},
"AWS/Lambda": {"FunctionName"},
"AWS/Logs": {"LogGroupName", "DestinationType", "FilterName"},
"AWS/ML": {"MLModelId", "RequestMode"},
"AWS/OpsWorks": {"StackId", "LayerId", "InstanceId"},
"AWS/Redshift": {"NodeID", "ClusterIdentifier"},

View File

@ -116,6 +116,25 @@ func GetDataSourceByName(c *middleware.Context) Response {
return Json(200, &dtos)
}
// Get /api/datasources/id/:name
func GetDataSourceIdByName(c *middleware.Context) Response {
query := m.GetDataSourceByNameQuery{Name: c.Params(":name"), OrgId: c.OrgId}
if err := bus.Dispatch(&query); err != nil {
if err == m.ErrDataSourceNotFound {
return ApiError(404, "Data source not found", nil)
}
return ApiError(500, "Failed to query datasources", err)
}
ds := query.Result
dtos := dtos.AnyId{
Id: ds.Id,
}
return Json(200, &dtos)
}
func convertModelToDtos(ds m.DataSource) dtos.DataSource {
return dtos.DataSource{
Id: ds.Id,

View File

@ -10,6 +10,10 @@ import (
"github.com/grafana/grafana/pkg/setting"
)
type AnyId struct {
Id int64 `json:"id"`
}
type LoginCommand struct {
User string `json:"user" binding:"Required"`
Password string `json:"password" binding:"Required"`

View File

@ -48,18 +48,23 @@ func setIndexViewData(c *middleware.Context) (*dtos.IndexViewData, error) {
data.User.LightTheme = true
}
dashboardChildNavs := []*dtos.NavLink{
{Text: "Home", Url: setting.AppSubUrl + "/"},
{Text: "Playlists", Url: setting.AppSubUrl + "/playlists"},
{Text: "Snapshots", Url: setting.AppSubUrl + "/dashboard/snapshots"},
}
if c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR {
dashboardChildNavs = append(dashboardChildNavs, &dtos.NavLink{Divider: true})
dashboardChildNavs = append(dashboardChildNavs, &dtos.NavLink{Text: "New", Url: setting.AppSubUrl + "/dashboard/new"})
dashboardChildNavs = append(dashboardChildNavs, &dtos.NavLink{Text: "Import", Url: setting.AppSubUrl + "/import/dashboard"})
}
data.MainNavLinks = append(data.MainNavLinks, &dtos.NavLink{
Text: "Dashboards",
Icon: "icon-gf icon-gf-dashboard",
Url: setting.AppSubUrl + "/",
Children: []*dtos.NavLink{
{Text: "Home", Url: setting.AppSubUrl + "/"},
{Text: "Playlists", Url: setting.AppSubUrl + "/playlists"},
{Text: "Snapshots", Url: setting.AppSubUrl + "/dashboard/snapshots"},
{Divider: true},
{Text: "New", Url: setting.AppSubUrl + "/dashboard/new"},
{Text: "Import", Url: setting.AppSubUrl + "/import/dashboard"},
},
Children: dashboardChildNavs,
})
if c.OrgRole == m.ROLE_ADMIN {

View File

@ -31,6 +31,7 @@ func RenderToPng(c *middleware.Context) {
Width: queryReader.Get("width", "800"),
Height: queryReader.Get("height", "400"),
SessionId: c.Session.ID(),
Timeout: queryReader.Get("timeout", "15"),
}
renderOpts.Url = setting.ToAbsUrl(renderOpts.Url)

View File

@ -4,6 +4,7 @@ import (
"archive/zip"
"bytes"
"errors"
"fmt"
"github.com/grafana/grafana/pkg/cmd/grafana-cli/log"
m "github.com/grafana/grafana/pkg/cmd/grafana-cli/models"
s "github.com/grafana/grafana/pkg/cmd/grafana-cli/services"
@ -64,32 +65,33 @@ func InstallPlugin(pluginName, version string, c CommandLine) error {
return err
}
url := v.Url
commit := v.Commit
if version == "" {
version = v.Version
}
downloadURL := url + "/archive/" + commit + ".zip"
downloadURL := fmt.Sprintf("%s/%s/versions/%s/download",
c.GlobalString("repo"),
pluginName,
version)
log.Infof("installing %v @ %v\n", plugin.Id, version)
log.Infof("from url: %v\n", downloadURL)
log.Infof("on commit: %v\n", commit)
log.Infof("into: %v\n", pluginFolder)
err = downloadFile(plugin.Id, pluginFolder, downloadURL)
if err == nil {
log.Infof("Installed %v successfully ✔\n", plugin.Id)
if err != nil {
return err
}
res, _ := s.ReadPlugin(pluginFolder, pluginName)
log.Infof("Installed %v successfully ✔\n", plugin.Id)
/* Enable once we need support for downloading depedencies
res, _ := s.ReadPlugin(pluginFolder, pluginName)
for _, v := range res.Dependency.Plugins {
InstallPlugin(v.Id, version, c)
log.Infof("Installed Dependency: %v ✔\n", v.Id)
log.Infof("Installed dependency: %v ✔\n", v.Id)
}
*/
return err
}

View File

@ -10,7 +10,7 @@ import (
var ls_getPlugins func(path string) []m.InstalledPlugin = s.GetLocalPlugins
var validateLsCommmand = func(pluginDir string) error {
var validateLsCommand = func(pluginDir string) error {
if pluginDir == "" {
return errors.New("missing path flag")
}
@ -31,7 +31,7 @@ var validateLsCommmand = func(pluginDir string) error {
func lsCommand(c CommandLine) error {
pluginDir := c.GlobalString("path")
if err := validateLsCommmand(pluginDir); err != nil {
if err := validateLsCommand(pluginDir); err != nil {
return err
}

View File

@ -9,10 +9,10 @@ import (
)
func TestMissingPath(t *testing.T) {
var org = validateLsCommmand
var org = validateLsCommand
Convey("ls command", t, func() {
validateLsCommmand = org
validateLsCommand = org
Convey("Missing path", func() {
commandLine := &commandstest.FakeCommandLine{
@ -61,7 +61,7 @@ func TestMissingPath(t *testing.T) {
},
}
validateLsCommmand = func(pluginDir string) error {
validateLsCommand = func(pluginDir string) error {
return errors.New("dummie error")
}

View File

@ -41,7 +41,7 @@ func main() {
cli.StringFlag{
Name: "repo",
Usage: "url to the plugin repository",
Value: "https://raw.githubusercontent.com/grafana/grafana-plugin-repository/master/repo.json",
Value: "",
},
cli.BoolFlag{
Name: "debug, d",

View File

@ -12,7 +12,8 @@ import (
var IoHelper m.IoUtil = IoUtilImp{}
func ListAllPlugins(repoUrl string) (m.PluginRepo, error) {
res, _ := goreq.Request{Uri: repoUrl}.Do()
res, _ := goreq.Request{Uri: repoUrl + "/repo", MaxRedirects: 3}.Do()
var resp m.PluginRepo
err := res.Body.FromJsonTo(&resp)

View File

@ -11,6 +11,7 @@ import (
"github.com/grafana/grafana/pkg/log"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util"
"strconv"
)
type RenderOpts struct {
@ -18,6 +19,7 @@ type RenderOpts struct {
Width string
Height string
SessionId string
Timeout string
}
func RenderToPng(params *RenderOpts) (string, error) {
@ -60,8 +62,13 @@ func RenderToPng(params *RenderOpts) (string, error) {
close(done)
}()
timeout, err := strconv.Atoi(params.Timeout)
if err != nil {
timeout = 15
}
select {
case <-time.After(15 * time.Second):
case <-time.After(time.Duration(timeout) * time.Second):
if err := cmd.Process.Kill(); err != nil {
log.Error(4, "failed to kill: %v", err)
}

View File

@ -14,8 +14,8 @@ func TestPluginDashboards(t *testing.T) {
Convey("When asking plugin dashboard info", t, func() {
setting.Cfg = ini.Empty()
sec, _ := setting.Cfg.NewSection("plugin.nginx-app")
sec.NewKey("path", "../../examples/nginx-app")
sec, _ := setting.Cfg.NewSection("plugin.test-app")
sec.NewKey("path", "../../tests/test-app")
err := Init()
So(err, ShouldBeNil)
@ -31,7 +31,7 @@ func TestPluginDashboards(t *testing.T) {
return m.ErrDashboardNotFound
})
dashboards, err := GetPluginDashboards(1, "nginx-app")
dashboards, err := GetPluginDashboards(1, "test-app")
So(err, ShouldBeNil)
@ -43,7 +43,7 @@ func TestPluginDashboards(t *testing.T) {
So(dashboards[0].Title, ShouldEqual, "Nginx Connections")
So(dashboards[0].Revision, ShouldEqual, "1.5")
So(dashboards[0].InstalledRevision, ShouldEqual, "1.1")
So(dashboards[0].InstalledURI, ShouldEqual, "db/nginx-connections")
So(dashboards[0].InstalledUri, ShouldEqual, "db/nginx-connections")
So(dashboards[1].Revision, ShouldEqual, "2.0")
So(dashboards[1].InstalledRevision, ShouldEqual, "")

View File

@ -28,14 +28,14 @@ func TestPluginScans(t *testing.T) {
Convey("When reading app plugin definition", t, func() {
setting.Cfg = ini.Empty()
sec, _ := setting.Cfg.NewSection("plugin.nginx-app")
sec.NewKey("path", "../../examples/nginx-app")
sec.NewKey("path", "../../tests/test-app")
err := Init()
So(err, ShouldBeNil)
So(len(Apps), ShouldBeGreaterThan, 0)
So(Apps["nginx-app"].Info.Logos.Large, ShouldEqual, "public/plugins/nginx-app/img/logo_large.png")
So(Apps["nginx-app"].Info.Screenshots[1].Path, ShouldEqual, "public/plugins/nginx-app/img/screenshot2.png")
So(Apps["test-app"].Info.Logos.Large, ShouldEqual, "public/plugins/test-app/img/logo_large.png")
So(Apps["test-app"].Info.Screenshots[1].Path, ShouldEqual, "public/plugins/test-app/img/screenshot2.png")
})
}

View File

@ -74,7 +74,7 @@ function (angular, _, kbn) {
if (urlValue !== void 0) {
return self.setVariableFromUrl(variable, urlValue).then(lock.resolve);
}
else if (variable.refresh === 'On Dashboard Load' || variable.refresh === 'On Time Change and Dashboard Load') {
else if (variable.refresh === 1 || variable.refresh === 2) {
return self.updateOptions(variable).then(function() {
if (_.isEmpty(variable.current) && variable.options.length) {
console.log("setting current for %s", variable.name);

View File

@ -143,7 +143,7 @@ function (angular, _, moment, dateMath, CloudWatchAnnotationQuery) {
return this.awsRequest({
region: region,
action: 'DescribeInstances',
parameters: { filter: filters, instanceIds: instanceIds }
parameters: { filters: filters, instanceIds: instanceIds }
});
};
@ -205,6 +205,28 @@ function (angular, _, moment, dateMath, CloudWatchAnnotationQuery) {
});
}
var ec2InstanceAttributeQuery = query.match(/^ec2_instance_attribute\(([^,]+?),\s?([^,]+?),\s?(.+?)\)/);
if (ec2InstanceAttributeQuery) {
region = templateSrv.replace(ec2InstanceAttributeQuery[1]);
var filterJson = JSON.parse(templateSrv.replace(ec2InstanceAttributeQuery[3]));
var filters = _.map(filterJson, function(values, name) {
return {
Name: name,
Values: values
};
});
var targetAttributeName = templateSrv.replace(ec2InstanceAttributeQuery[2]);
return this.performEC2DescribeInstances(region, filters, null).then(function(result) {
var attributes = _.chain(result.Reservations)
.map(function(reservations) {
return _.pluck(reservations.Instances, targetAttributeName);
})
.flatten().value();
return transformSuggestData(attributes);
});
}
return $q.when([]);
};

View File

@ -104,7 +104,7 @@ export function InfluxDatasource(instanceSettings, $q, backendSrv, templateSrv)
this.metricFindQuery = function (query) {
var interpolated;
try {
interpolated = templateSrv.replace(query);
interpolated = templateSrv.replace(query, null, 'regex');
} catch (err) {
return $q.reject(err);
}

View File

@ -258,6 +258,6 @@
"annotations": {
"enable": false
},
"refresh": "Never",
"refresh": 0,
"version": 6
}

View File

@ -1,7 +1,7 @@
{
"type": "app",
"name": "Nginx",
"id": "nginx-app",
"name": "Test App",
"id": "test-app",
"staticRoot": ".",
@ -16,12 +16,12 @@
},
"info": {
"description": "Official Grafana Nginx App & Dashboard bundle",
"description": "Official Grafana Test App & Dashboard bundle",
"author": {
"name": "Nginx Inc.",
"url": "http://nginx.com"
"name": "Test Inc.",
"url": "http://test.com"
},
"keywords": ["nginx"],
"keywords": ["test"],
"logos": {
"small": "img/logo_small.png",
"large": "img/logo_large.png"