Merge remote-tracking branch 'upstream/master' into postgres-query-builder

This commit is contained in:
Sven Klemm
2018-06-05 23:21:46 +02:00
65 changed files with 1665 additions and 190 deletions
+9
View File
@@ -1,8 +1,11 @@
# 5.2.0 (unreleased)
# 5.2.0-beta1 (2018-06-05)
### New Features
* **Elasticsearch**: Alerting support [#5893](https://github.com/grafana/grafana/issues/5893), thx [@WPH95](https://github.com/WPH95)
* **Login**: Change admin password after first login [#11882](https://github.com/grafana/grafana/issues/11882)
* **Alert list panel**: Updated to support filtering alerts by name, dashboard title, folder, tags [#11500](https://github.com/grafana/grafana/issues/11500), [#8168](https://github.com/grafana/grafana/issues/8168), [#6541](https://github.com/grafana/grafana/issues/6541)
### Minor
@@ -30,6 +33,12 @@
* **Singlestat**: Fix singlestat threshold tooltip [#11971](https://github.com/grafana/grafana/issues/11971)
* **Dashboard**: Hide grid controls in fullscreen/low-activity views [#11771](https://github.com/grafana/grafana/issues/11771)
* **Dashboard**: Validate uid when importing dashboards [#11515](https://github.com/grafana/grafana/issues/11515)
* **Docker**: Support for env variables ending with _FILE [grafana-docker #166](https://github.com/grafana/grafana-docker/pull/166), thx [@efrecon](https://github.com/efrecon)
* **Alert list panel**: Show alerts for user with viewer role [#11167](https://github.com/grafana/grafana/issues/11167)
* **Provisioning**: Verify checksum of dashboards before updating to reduce load on database [#11670](https://github.com/grafana/grafana/issues/11670)
* **Provisioning**: Support symlinked files in dashboard provisioning config files [#11958](https://github.com/grafana/grafana/issues/11958)
* **Dashboard list panel**: Search dashboards by folder [#11525](https://github.com/grafana/grafana/issues/11525)
* **Sidenav**: Always show server admin link in sidenav if grafana admin [#11657](https://github.com/grafana/grafana/issues/11657)
# 5.1.3 (2018-05-16)
Generated
+2 -2
View File
@@ -226,7 +226,7 @@
version = "v1.1.1"
[[projects]]
branch = "renderer"
branch = "master"
name = "github.com/grafana/grafana-plugin-model"
packages = [
"go/datasource",
@@ -670,6 +670,6 @@
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "6c7ae4bcbe7fa4430d3bdbf204df1b7c59cba88151fbcefa167ce15e6351b6d3"
inputs-digest = "08b97771990365d506af4788acb33cdf283ce89856669262ecb84860ad45bfcb"
solver-name = "gps-cdcl"
solver-version = 1
+1 -1
View File
@@ -100,7 +100,7 @@ ignored = [
version = "1.1.1"
[[constraint]]
branch = "renderer"
branch = "master"
name = "github.com/grafana/grafana-plugin-model"
[[constraint]]
@@ -1137,4 +1137,4 @@
"title": "Big Dashboard",
"uid": "000000003",
"version": 16
}
}
+2 -2
View File
@@ -8,7 +8,7 @@ bulkDashboard() {
MAX=400
while [ $COUNTER -lt $MAX ]; do
jsonnet -o "dashboards/bulk-testing/dashboard${COUNTER}.json" -e "local bulkDash = import 'dashboards/bulk-testing/bulkdash.jsonnet'; bulkDash + { uid: 'uid-${COUNTER}', title: 'title-${COUNTER}' }"
let COUNTER=COUNTER+1
let COUNTER=COUNTER+1
done
ln -s -f -r ./dashboards/bulk-testing/bulk-dashboards.yaml ../conf/provisioning/dashboards/custom.yaml
@@ -58,4 +58,4 @@ main() {
fi
}
main "$@"
main "$@"
@@ -197,6 +197,7 @@ providers:
folder: ''
type: file
disableDeletion: false
updateIntervalSeconds: 3 #how often Grafana will scan for changed dashboards
options:
path: /var/lib/grafana/dashboards
```
+70
View File
@@ -0,0 +1,70 @@
+++
title = "What's New in Grafana v5.2"
description = "Feature & improvement highlights for Grafana v5.2"
keywords = ["grafana", "new", "documentation", "5.2"]
type = "docs"
[menu.docs]
name = "Version 5.2"
identifier = "v5.2"
parent = "whatsnew"
weight = -8
+++
# What's New in Grafana v5.2
Grafana v5.2 brings new features, many enhancements and bug fixes. This article will detail the major new features and enhancements.
* [Elasticsearch alerting]({{< relref "#elasticsearch-alerting" >}}) it's finally here!
* [Cross platform build support]({{< relref "#cross-platform-build-support" >}}) enables native builds of Grafana for many more platforms!
* [Improved Docker image]({{< relref "#improved-docker-image" >}}) with support for docker secrets
* [Prometheus]({{< relref "#prometheus" >}}) with alignment enhancements
* [Alerting]({{< relref "#alerting" >}}) with alert notification channel type for Discord
* [Dashboards & Panels]({{< relref "#dashboards-panels" >}})
## Elasticsearch alerting
{{< docs-imagebox img="/img/docs/v52/elasticsearch_alerting.png" max-width="800px" class="docs-image--right" >}}
Grafana v5.2 ships with an updated Elasticsearch datasource with support for alerting. Alerting support for Elasticsearch has been one of
the most requested features by our community and now it's finally here. Please try it out and let us know what you think.
<div class="clearfix"></div>
## Cross platform build support
Grafana v5.2 brings an improved build pipeline with cross platform support. This enables native builds of Grafana for ARMv7 (x32), ARM64 (x64),
MacOS/Darwin (x64) and Windows (x64) in both stable and nightly builds.
We've been longing for native ARM build support for a long time. With the help from our amazing community this is now finally available.
## Improved Docker image
The Grafana docker image now includes support for Docker secrets which enables you to supply Grafana with configuration through files. More
information in the [Installing using Docker documentation](/installation/docker/#reading-secrets-from-files-support-for-docker-secrets).
## Prometheus
The Prometheus datasource now aligns the start/end of the query sent to Prometheus with the step, which ensures PromQL expressions with *rate*
functions get consistent results, and thus avoid graphs jumping around on reload.
## Alerting
By popular demand Grafana now includes support for an alert notification channel type for [Discord](https://discordapp.com/).
## Dashboards & Panels
### Modified time range and variables are no longer saved by default
{{< docs-imagebox img="/img/docs/v52/dashboard_save_modal.png" max-width="800px" class="docs-image--right" >}}
Starting from Grafana v5.2 a modified time range or variable are no longer saved by default. To save a modified
time range or variable you'll need to actively select that when saving a dashboard, see screenshot.
This should hopefully make it easier to have sane defaults of time and variables in dashboards and make it more explicit
when you actually want to overwrite those settings.
<div class="clearfix"></div>
## Changelog
Checkout the [CHANGELOG.md](https://github.com/grafana/grafana/blob/master/CHANGELOG.md) file for a complete list
of new features, changes, and bug fixes.
+21 -13
View File
@@ -419,25 +419,33 @@ allowed_organizations = github google
## [auth.google]
You need to create a Google project. You can do this in the [Google
Developer Console](https://console.developers.google.com/project). When
you create the project you will need to specify a callback URL. Specify
this as callback:
First, you need to create a Google OAuth Client:
```bash
http://<my_grafana_server_name_or_ip>:<grafana_server_port>/login/google
```
1. Go to https://console.developers.google.com/apis/credentials
This callback URL must match the full HTTP address that you use in your
browser to access Grafana, but with the prefix path of `/login/google`.
When the Google project is created you will get a Client ID and a Client
Secret. Specify these in the Grafana configuration file. For example:
2. Click the 'Create Credentials' button, then click 'OAuth Client ID' in the
menu that drops down
3. Enter the following:
- Application Type: Web Application
- Name: Grafana
- Authorized Javascript Origins: https://grafana.mycompany.com
- Authorized Redirect URLs: https://grafana.mycompany.com/login/google
Replace https://grafana.mycompany.com with the URL of your Grafana instance.
4. Click Create
5. Copy the Client ID and Client Secret from the 'OAuth Client' modal
Specify the Client ID and Secret in the Grafana configuration file. For example:
```bash
[auth.google]
enabled = true
client_id = YOUR_GOOGLE_APP_CLIENT_ID
client_secret = YOUR_GOOGLE_APP_CLIENT_SECRET
client_id = CLIENT_ID
client_secret = CLIENT_SECRET
scopes = https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email
auth_url = https://accounts.google.com/o/oauth2/auth
token_url = https://accounts.google.com/o/oauth2/token
+14
View File
@@ -130,6 +130,20 @@ ID=$(id -u) # saves your user id in the ID variable
docker run -d --user $ID --volume "$PWD/data:/var/lib/grafana" -p 3000:3000 grafana/grafana:5.1.0
```
## Reading secrets from files (support for Docker Secrets)
> Available in v5.2.0 and later
It's possible to supply Grafana with configuration through files. This works well with [Docker Secrets](https://docs.docker.com/engine/swarm/secrets/) as the secrets by default gets mapped into `/run/secrets/<name of secret>` of the container.
You can do this with any of the configuration options in conf/grafana.ini by setting `GF_<SectionName>_<KeyName>_FILE` to the path of the file holding the secret.
Let's say you want to set the admin password this way.
- Admin password secret: `/run/secrets/admin_password`
- Environment variable: `GF_SECURITY_ADMIN_PASSWORD_FILE=/run/secrets/admin_password`
## Migration from a previous version of the docker container to 5.1 or later
The docker container for Grafana has seen a major rewrite for 5.1.
+1
View File
@@ -157,6 +157,7 @@
"moment": "^2.18.1",
"mousetrap": "^1.6.0",
"mousetrap-global-bind": "^1.1.0",
"papaparse": "^4.4.0",
"prismjs": "^1.6.0",
"prop-types": "^15.6.0",
"react": "^16.2.0",
+1 -1
View File
@@ -79,7 +79,7 @@ func GetAlerts(c *m.ReqContext) Response {
DashboardIds: dashboardIDs,
Type: string(search.DashHitDB),
FolderIds: folderIDs,
Permission: m.PERMISSION_EDIT,
Permission: m.PERMISSION_VIEW,
}
err := bus.Dispatch(&searchQuery)
+3
View File
@@ -77,6 +77,9 @@ func (hs *HTTPServer) registerRoutes() {
r.Get("/dashboards/", reqSignedIn, Index)
r.Get("/dashboards/*", reqSignedIn, Index)
r.Get("/explore/", reqEditorRole, Index)
r.Get("/explore/*", reqEditorRole, Index)
r.Get("/playlists/", reqSignedIn, Index)
r.Get("/playlists/*", reqSignedIn, Index)
r.Get("/alerting/", reqSignedIn, Index)
+1 -1
View File
@@ -52,7 +52,7 @@ type UserStars struct {
func GetGravatarUrl(text string) string {
if setting.DisableGravatar {
return "/public/img/user_profile.png"
return setting.AppSubUrl + "/public/img/user_profile.png"
}
if text == "" {
+11
View File
@@ -85,6 +85,13 @@ func getFrontendSettingsMap(c *m.ReqContext) (map[string]interface{}, error) {
dsMap["database"] = ds.Database
dsMap["url"] = url
}
if ds.Type == m.DS_INFLUXDB_IFQL {
dsMap["username"] = ds.User
dsMap["password"] = ds.Password
dsMap["database"] = ds.Database
dsMap["url"] = url
}
}
if ds.Type == m.DS_ES {
@@ -95,6 +102,10 @@ func getFrontendSettingsMap(c *m.ReqContext) (map[string]interface{}, error) {
dsMap["database"] = ds.Database
}
if ds.Type == m.DS_INFLUXDB_IFQL {
dsMap["database"] = ds.Database
}
if ds.Type == m.DS_PROMETHEUS {
// add unproxied server URL for link to Prometheus web UI
dsMap["directUrl"] = ds.Url
+17 -3
View File
@@ -128,7 +128,7 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
Children: dashboardChildNavs,
})
if setting.ExploreEnabled {
if setting.ExploreEnabled && (c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR) {
data.NavTree = append(data.NavTree, &dtos.NavLink{
Text: "Explore",
Id: "explore",
@@ -233,7 +233,7 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
}
}
if c.OrgRole == m.ROLE_ADMIN {
if c.IsGrafanaAdmin || c.OrgRole == m.ROLE_ADMIN {
cfgNode := &dtos.NavLink{
Id: "cfg",
Text: "Configuration",
@@ -287,10 +287,24 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
},
}
if c.IsGrafanaAdmin {
if c.OrgRole != m.ROLE_ADMIN {
cfgNode = &dtos.NavLink{
Id: "cfg",
Text: "Configuration",
SubTitle: "Organization: " + c.OrgName,
Icon: "gicon gicon-cog",
Url: setting.AppSubUrl + "/admin/users",
Children: make([]*dtos.NavLink, 0),
}
}
if c.OrgRole == m.ROLE_ADMIN && c.IsGrafanaAdmin {
cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{
Divider: true, HideFromTabs: true, Id: "admin-divider", Text: "Text",
})
}
if c.IsGrafanaAdmin {
cfgNode.Children = append(cfgNode.Children, &dtos.NavLink{
Text: "Server Admin",
HideFromTabs: true,
+1
View File
@@ -254,6 +254,7 @@ type DashboardProvisioning struct {
DashboardId int64
Name string
ExternalId string
CheckSum string
Updated int64
}
+1
View File
@@ -12,6 +12,7 @@ const (
DS_GRAPHITE = "graphite"
DS_INFLUXDB = "influxdb"
DS_INFLUXDB_08 = "influxdb_08"
DS_INFLUXDB_IFQL = "influxdb-ifql"
DS_ES = "elasticsearch"
DS_OPENTSDB = "opentsdb"
DS_CLOUDWATCH = "cloudwatch"
@@ -81,6 +81,10 @@ func (cr *configReader) readConfig() ([]*DashboardsAsConfig, error) {
if dashboards[i].OrgId == 0 {
dashboards[i].OrgId = 1
}
if dashboards[i].UpdateIntervalSeconds == 0 {
dashboards[i].UpdateIntervalSeconds = 3
}
}
return dashboards, nil
@@ -22,7 +22,7 @@ func TestDashboardsAsConfig(t *testing.T) {
cfg, err := cfgProvider.readConfig()
So(err, ShouldBeNil)
validateDashboardAsConfig(cfg)
validateDashboardAsConfig(t, cfg)
})
Convey("Can read config file in version 0 format", func() {
@@ -30,7 +30,7 @@ func TestDashboardsAsConfig(t *testing.T) {
cfg, err := cfgProvider.readConfig()
So(err, ShouldBeNil)
validateDashboardAsConfig(cfg)
validateDashboardAsConfig(t, cfg)
})
Convey("Should skip invalid path", func() {
@@ -56,7 +56,9 @@ func TestDashboardsAsConfig(t *testing.T) {
})
})
}
func validateDashboardAsConfig(cfg []*DashboardsAsConfig) {
func validateDashboardAsConfig(t *testing.T, cfg []*DashboardsAsConfig) {
t.Helper()
So(len(cfg), ShouldEqual, 2)
ds := cfg[0]
@@ -68,6 +70,7 @@ func validateDashboardAsConfig(cfg []*DashboardsAsConfig) {
So(len(ds.Options), ShouldEqual, 1)
So(ds.Options["path"], ShouldEqual, "/var/lib/grafana/dashboards")
So(ds.DisableDeletion, ShouldBeTrue)
So(ds.UpdateIntervalSeconds, ShouldEqual, 10)
ds2 := cfg[1]
So(ds2.Name, ShouldEqual, "default")
@@ -78,4 +81,5 @@ func validateDashboardAsConfig(cfg []*DashboardsAsConfig) {
So(len(ds2.Options), ShouldEqual, 1)
So(ds2.Options["path"], ShouldEqual, "/var/lib/grafana/dashboards")
So(ds2.DisableDeletion, ShouldBeFalse)
So(ds2.UpdateIntervalSeconds, ShouldEqual, 3)
}
@@ -4,12 +4,14 @@ import (
"context"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/bus"
@@ -19,8 +21,6 @@ import (
)
var (
checkDiskForChangesInterval = time.Second * 3
ErrFolderNameMissing = errors.New("Folder name missing")
)
@@ -47,15 +47,25 @@ func NewDashboardFileReader(cfg *DashboardsAsConfig, log log.Logger) (*fileReade
log.Error("Cannot read directory", "error", err)
}
absPath, err := filepath.Abs(path)
copy := path
path, err := filepath.Abs(path)
if err != nil {
log.Error("Could not create absolute path ", "path", path)
absPath = path //if .Abs return an error we fallback to path
}
path, err = filepath.EvalSymlinks(path)
if err != nil {
log.Error("Failed to read content of symlinked path: %s", path)
}
if path == "" {
path = copy
log.Info("falling back to original path due to EvalSymlink/Abs failure")
}
return &fileReader{
Cfg: cfg,
Path: absPath,
Path: path,
log: log,
dashboardService: dashboards.NewProvisioningService(),
}, nil
@@ -66,7 +76,7 @@ func (fr *fileReader) ReadAndListen(ctx context.Context) error {
fr.log.Error("failed to search for dashboards", "error", err)
}
ticker := time.NewTicker(checkDiskForChangesInterval)
ticker := time.NewTicker(time.Duration(int64(time.Second) * fr.Cfg.UpdateIntervalSeconds))
running := false
@@ -159,15 +169,20 @@ func (fr *fileReader) saveDashboard(path string, folderId int64, fileInfo os.Fil
}
provisionedData, alreadyProvisioned := provisionedDashboardRefs[path]
upToDate := alreadyProvisioned && provisionedData.Updated == resolvedFileInfo.ModTime().Unix()
upToDate := alreadyProvisioned && provisionedData.Updated >= resolvedFileInfo.ModTime().Unix()
dash, err := fr.readDashboardFromFile(path, resolvedFileInfo.ModTime(), folderId)
jsonFile, err := fr.readDashboardFromFile(path, resolvedFileInfo.ModTime(), folderId)
if err != nil {
fr.log.Error("failed to load dashboard from ", "file", path, "error", err)
return provisioningMetadata, nil
}
if provisionedData != nil && jsonFile.checkSum == provisionedData.CheckSum {
upToDate = true
}
// keeps track of what uid's and title's we have already provisioned
dash := jsonFile.dashboard
provisioningMetadata.uid = dash.Dashboard.Uid
provisioningMetadata.title = dash.Dashboard.Title
@@ -185,7 +200,13 @@ func (fr *fileReader) saveDashboard(path string, folderId int64, fileInfo os.Fil
}
fr.log.Debug("saving new dashboard", "file", path)
dp := &models.DashboardProvisioning{ExternalId: path, Name: fr.Cfg.Name, Updated: resolvedFileInfo.ModTime().Unix()}
dp := &models.DashboardProvisioning{
ExternalId: path,
Name: fr.Cfg.Name,
Updated: resolvedFileInfo.ModTime().Unix(),
CheckSum: jsonFile.checkSum,
}
_, err = fr.dashboardService.SaveProvisionedDashboard(dash, dp)
return provisioningMetadata, err
}
@@ -283,14 +304,30 @@ func validateWalkablePath(fileInfo os.FileInfo) (bool, error) {
return true, nil
}
func (fr *fileReader) readDashboardFromFile(path string, lastModified time.Time, folderId int64) (*dashboards.SaveDashboardDTO, error) {
type dashboardJsonFile struct {
dashboard *dashboards.SaveDashboardDTO
checkSum string
lastModified time.Time
}
func (fr *fileReader) readDashboardFromFile(path string, lastModified time.Time, folderId int64) (*dashboardJsonFile, error) {
reader, err := os.Open(path)
if err != nil {
return nil, err
}
defer reader.Close()
data, err := simplejson.NewFromReader(reader)
all, err := ioutil.ReadAll(reader)
if err != nil {
return nil, err
}
checkSum, err := util.Md5SumString(string(all))
if err != nil {
return nil, err
}
data, err := simplejson.NewJson(all)
if err != nil {
return nil, err
}
@@ -300,7 +337,11 @@ func (fr *fileReader) readDashboardFromFile(path string, lastModified time.Time,
return nil, err
}
return dash, nil
return &dashboardJsonFile{
dashboard: dash,
checkSum: checkSum,
lastModified: lastModified,
}, nil
}
type provisioningMetadata struct {
@@ -328,7 +369,6 @@ func (checker provisioningSanityChecker) track(pm provisioningMetadata) {
if len(pm.title) > 0 {
checker.titleUsage[pm.title] += 1
}
}
func (checker provisioningSanityChecker) logWarnings(log log.Logger) {
@@ -343,5 +383,4 @@ func (checker provisioningSanityChecker) logWarnings(log log.Logger) {
log.Error("the same 'title' is used more than once", "title", title, "provider", checker.provisioningProvider)
}
}
}
@@ -0,0 +1,39 @@
// +build linux
package dashboards
import (
"path/filepath"
"testing"
"github.com/grafana/grafana/pkg/log"
)
var (
symlinkedFolder = "testdata/test-dashboards/symlink"
)
func TestProvsionedSymlinkedFolder(t *testing.T) {
cfg := &DashboardsAsConfig{
Name: "Default",
Type: "file",
OrgId: 1,
Folder: "",
Options: map[string]interface{}{"path": symlinkedFolder},
}
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"))
if err != nil {
t.Error("expected err to be nil")
}
want, err := filepath.Abs(containingId)
if err != nil {
t.Errorf("expected err to be nill")
}
if reader.Path != want {
t.Errorf("got %s want %s", reader.Path, want)
}
}
@@ -49,13 +49,16 @@ func TestCreatingNewDashboardFileReader(t *testing.T) {
})
Convey("using full path", func() {
cfg.Options["folder"] = "/var/lib/grafana/dashboards"
fullPath := "/var/lib/grafana/dashboards"
if runtime.GOOS == "windows" {
fullPath = `c:\var\lib\grafana`
}
cfg.Options["folder"] = fullPath
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"))
So(err, ShouldBeNil)
if runtime.GOOS != "windows" {
So(reader.Path, ShouldEqual, "/var/lib/grafana/dashboards")
}
So(reader.Path, ShouldEqual, fullPath)
So(filepath.IsAbs(reader.Path), ShouldBeTrue)
})
@@ -6,6 +6,7 @@ providers:
folder: 'developers'
editable: true
disableDeletion: true
updateIntervalSeconds: 10
type: file
options:
path: /var/lib/grafana/dashboards
@@ -3,6 +3,7 @@
folder: 'developers'
editable: true
disableDeletion: true
updateIntervalSeconds: 10
type: file
options:
path: /var/lib/grafana/dashboards
@@ -0,0 +1 @@
containing-id/
+40 -35
View File
@@ -10,23 +10,25 @@ import (
)
type DashboardsAsConfig struct {
Name string
Type string
OrgId int64
Folder string
Editable bool
Options map[string]interface{}
DisableDeletion bool
Name string
Type string
OrgId int64
Folder string
Editable bool
Options map[string]interface{}
DisableDeletion bool
UpdateIntervalSeconds int64
}
type DashboardsAsConfigV0 struct {
Name string `json:"name" yaml:"name"`
Type string `json:"type" yaml:"type"`
OrgId int64 `json:"org_id" yaml:"org_id"`
Folder string `json:"folder" yaml:"folder"`
Editable bool `json:"editable" yaml:"editable"`
Options map[string]interface{} `json:"options" yaml:"options"`
DisableDeletion bool `json:"disableDeletion" yaml:"disableDeletion"`
Name string `json:"name" yaml:"name"`
Type string `json:"type" yaml:"type"`
OrgId int64 `json:"org_id" yaml:"org_id"`
Folder string `json:"folder" yaml:"folder"`
Editable bool `json:"editable" yaml:"editable"`
Options map[string]interface{} `json:"options" yaml:"options"`
DisableDeletion bool `json:"disableDeletion" yaml:"disableDeletion"`
UpdateIntervalSeconds int64 `json:"updateIntervalSeconds" yaml:"updateIntervalSeconds"`
}
type ConfigVersion struct {
@@ -38,13 +40,14 @@ type DashboardAsConfigV1 struct {
}
type DashboardProviderConfigs struct {
Name string `json:"name" yaml:"name"`
Type string `json:"type" yaml:"type"`
OrgId int64 `json:"orgId" yaml:"orgId"`
Folder string `json:"folder" yaml:"folder"`
Editable bool `json:"editable" yaml:"editable"`
Options map[string]interface{} `json:"options" yaml:"options"`
DisableDeletion bool `json:"disableDeletion" yaml:"disableDeletion"`
Name string `json:"name" yaml:"name"`
Type string `json:"type" yaml:"type"`
OrgId int64 `json:"orgId" yaml:"orgId"`
Folder string `json:"folder" yaml:"folder"`
Editable bool `json:"editable" yaml:"editable"`
Options map[string]interface{} `json:"options" yaml:"options"`
DisableDeletion bool `json:"disableDeletion" yaml:"disableDeletion"`
UpdateIntervalSeconds int64 `json:"updateIntervalSeconds" yaml:"updateIntervalSeconds"`
}
func createDashboardJson(data *simplejson.Json, lastModified time.Time, cfg *DashboardsAsConfig, folderId int64) (*dashboards.SaveDashboardDTO, error) {
@@ -68,13 +71,14 @@ func mapV0ToDashboardAsConfig(v0 []*DashboardsAsConfigV0) []*DashboardsAsConfig
for _, v := range v0 {
r = append(r, &DashboardsAsConfig{
Name: v.Name,
Type: v.Type,
OrgId: v.OrgId,
Folder: v.Folder,
Editable: v.Editable,
Options: v.Options,
DisableDeletion: v.DisableDeletion,
Name: v.Name,
Type: v.Type,
OrgId: v.OrgId,
Folder: v.Folder,
Editable: v.Editable,
Options: v.Options,
DisableDeletion: v.DisableDeletion,
UpdateIntervalSeconds: v.UpdateIntervalSeconds,
})
}
@@ -86,13 +90,14 @@ func (dc *DashboardAsConfigV1) mapToDashboardAsConfig() []*DashboardsAsConfig {
for _, v := range dc.Providers {
r = append(r, &DashboardsAsConfig{
Name: v.Name,
Type: v.Type,
OrgId: v.OrgId,
Folder: v.Folder,
Editable: v.Editable,
Options: v.Options,
DisableDeletion: v.DisableDeletion,
Name: v.Name,
Type: v.Type,
OrgId: v.OrgId,
Folder: v.Folder,
Editable: v.Editable,
Options: v.Options,
DisableDeletion: v.DisableDeletion,
UpdateIntervalSeconds: v.UpdateIntervalSeconds,
})
}
+1 -1
View File
@@ -116,7 +116,7 @@ func HandleAlertsQuery(query *m.GetAlertsQuery) error {
}
if query.User.OrgRole != m.ROLE_ADMIN {
builder.writeDashboardPermissionFilter(query.User, m.PERMISSION_EDIT)
builder.writeDashboardPermissionFilter(query.User, m.PERMISSION_VIEW)
}
builder.Write(" ORDER BY name ASC")
+3 -3
View File
@@ -2,7 +2,6 @@ package sqlstore
import (
"testing"
"time"
"github.com/grafana/grafana/pkg/components/simplejson"
@@ -110,11 +109,12 @@ func TestAlertingDataAccess(t *testing.T) {
})
Convey("Viewer cannot read alerts", func() {
alertQuery := m.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, PanelId: 1, OrgId: 1, User: &m.SignedInUser{OrgRole: m.ROLE_VIEWER}}
viewerUser := &m.SignedInUser{OrgRole: m.ROLE_VIEWER, OrgId: 1}
alertQuery := m.GetAlertsQuery{DashboardIDs: []int64{testDash.Id}, PanelId: 1, OrgId: 1, User: viewerUser}
err2 := HandleAlertsQuery(&alertQuery)
So(err2, ShouldBeNil)
So(alertQuery.Result, ShouldHaveLength, 0)
So(alertQuery.Result, ShouldHaveLength, 1)
})
Convey("Alerts with same dashboard id and panel id should update", func() {
@@ -211,4 +211,8 @@ func addDashboardMigration(mg *Migrator) {
"name": "name",
"external_id": "external_id",
})
mg.AddMigration("Add check_sum column", NewAddColumnMigration(dashboardExtrasTableV2, &Column{
Name: "check_sum", Type: DB_NVarchar, Length: 32, Nullable: true,
}))
}
+10 -3
View File
@@ -113,15 +113,22 @@ func (rp *responseParser) processBuckets(aggs map[string]interface{}, target *Qu
}
}
for k, v := range esAgg.Get("buckets").MustMap() {
bucket := simplejson.NewFromAny(v)
buckets := esAgg.Get("buckets").MustMap()
bucketKeys := make([]string, 0)
for k := range buckets {
bucketKeys = append(bucketKeys, k)
}
sort.Strings(bucketKeys)
for _, bucketKey := range bucketKeys {
bucket := simplejson.NewFromAny(buckets[bucketKey])
newProps := make(map[string]string, 0)
for k, v := range props {
newProps[k] = v
}
newProps["filter"] = k
newProps["filter"] = bucketKey
err = rp.processBuckets(bucket.MustMap(), target, series, table, newProps, depth+1)
if err != nil {
+26
View File
@@ -0,0 +1,26 @@
package util
import (
"crypto/md5"
"encoding/hex"
"io"
"strings"
)
// Md5Sum calculates the md5sum of a stream
func Md5Sum(reader io.Reader) (string, error) {
var returnMD5String string
hash := md5.New()
if _, err := io.Copy(hash, reader); err != nil {
return returnMD5String, err
}
hashInBytes := hash.Sum(nil)[:16]
returnMD5String = hex.EncodeToString(hashInBytes)
return returnMD5String, nil
}
// Md5Sum calculates the md5sum of a string
func Md5SumString(input string) (string, error) {
buffer := strings.NewReader(input)
return Md5Sum(buffer)
}
+17
View File
@@ -0,0 +1,17 @@
package util
import "testing"
func TestMd5Sum(t *testing.T) {
input := "dont hash passwords with md5"
have, err := Md5SumString(input)
if err != nil {
t.Fatal("expected err to be nil")
}
want := "2d6a56c82d09d374643b926d3417afba"
if have != want {
t.Fatalf("expected: %s got: %s", want, have)
}
}
+59 -7
View File
@@ -11,10 +11,15 @@ export class LoginCtrl {
password: '',
};
$scope.command = {};
$scope.result = '';
contextSrv.sidemenu = false;
$scope.oauth = config.oauth;
$scope.oauthEnabled = _.keys(config.oauth).length > 0;
$scope.ldapEnabled = config.ldapEnabled;
$scope.authProxyEnabled = config.authProxyEnabled;
$scope.disableLoginForm = config.disableLoginForm;
$scope.disableUserSignUp = config.disableUserSignUp;
@@ -39,6 +44,43 @@ export class LoginCtrl {
}
};
$scope.changeView = function() {
let loginView = document.querySelector('#login-view');
let changePasswordView = document.querySelector('#change-password-view');
loginView.className += ' add';
setTimeout(() => {
loginView.className += ' hidden';
}, 250);
setTimeout(() => {
changePasswordView.classList.remove('hidden');
}, 251);
setTimeout(() => {
changePasswordView.classList.remove('remove');
}, 301);
setTimeout(() => {
document.getElementById('newPassword').focus();
}, 400);
};
$scope.changePassword = function() {
$scope.command.oldPassword = 'admin';
if ($scope.command.newPassword !== $scope.command.confirmNew) {
$scope.appEvent('alert-warning', ['New passwords do not match', '']);
return;
}
backendSrv.put('/api/user/password', $scope.command).then(function() {
$scope.toGrafana();
});
};
$scope.skip = function() {
$scope.toGrafana();
};
$scope.loginModeChanged = function(newValue) {
$scope.submitBtnText = newValue ? 'Log in' : 'Sign up';
};
@@ -65,18 +107,28 @@ export class LoginCtrl {
}
backendSrv.post('/login', $scope.formModel).then(function(result) {
var params = $location.search();
$scope.result = result;
if (params.redirect && params.redirect[0] === '/') {
window.location.href = config.appSubUrl + params.redirect;
} else if (result.redirectUrl) {
window.location.href = result.redirectUrl;
} else {
window.location.href = config.appSubUrl + '/';
if ($scope.formModel.password !== 'admin' || $scope.ldapEnabled || $scope.authProxyEnabled) {
$scope.toGrafana();
return;
}
$scope.changeView();
});
};
$scope.toGrafana = function() {
var params = $location.search();
if (params.redirect && params.redirect[0] === '/') {
window.location.href = config.appSubUrl + params.redirect;
} else if ($scope.result.redirectUrl) {
window.location.href = $scope.result.redirectUrl;
} else {
window.location.href = config.appSubUrl + '/';
}
};
$scope.init();
}
}
+18 -15
View File
@@ -14,7 +14,7 @@ export class KeybindingSrv {
timepickerOpen = false;
/** @ngInject */
constructor(private $rootScope, private $location, private datasourceSrv, private timeSrv) {
constructor(private $rootScope, private $location, private datasourceSrv, private timeSrv, private contextSrv) {
// clear out all shortcuts on route change
$rootScope.$on('$routeChangeSuccess', () => {
Mousetrap.reset();
@@ -177,21 +177,24 @@ export class KeybindingSrv {
}
});
this.bind('x', async () => {
if (dashboard.meta.focusPanelId) {
const panel = dashboard.getPanelById(dashboard.meta.focusPanelId);
const datasource = await this.datasourceSrv.get(panel.datasource);
if (datasource && datasource.supportsExplore) {
const range = this.timeSrv.timeRangeForUrl();
const state = {
...datasource.getExploreState(panel),
range,
};
const exploreState = encodePathComponent(JSON.stringify(state));
this.$location.url(`/explore/${exploreState}`);
// jump to explore if permissions allow
if (this.contextSrv.isEditor) {
this.bind('x', async () => {
if (dashboard.meta.focusPanelId) {
const panel = dashboard.getPanelById(dashboard.meta.focusPanelId);
const datasource = await this.datasourceSrv.get(panel.datasource);
if (datasource && datasource.supportsExplore) {
const range = this.timeSrv.timeRangeForUrl();
const state = {
...datasource.getExploreState(panel),
range,
};
const exploreState = encodePathComponent(JSON.stringify(state));
this.$location.url(`/explore/${exploreState}`);
}
}
}
});
});
}
// delete panel
this.bind('p r', () => {
+4
View File
@@ -44,4 +44,8 @@ export default class TableModel {
this.columnMap[col.text] = col;
}
}
addRow(row) {
this.rows.push(row);
}
}
+12 -6
View File
@@ -16,13 +16,13 @@ const template = `
<form name="ctrl.saveForm" ng-submit="ctrl.save()" class="modal-content" novalidate>
<div class="p-t-1">
<div class="gf-form-group" ng-if="ctrl.timeChange || ctrl.variableChange">
<div class="gf-form-group" ng-if="ctrl.timeChange || ctrl.variableValueChange">
<gf-form-switch class="gf-form"
label="Save current time range" ng-if="ctrl.timeChange" label-class="width-12" switch-class="max-width-6"
checked="ctrl.saveTimerange" on-change="buildUrl()">
</gf-form-switch>
<gf-form-switch class="gf-form"
label="Save current variables" ng-if="ctrl.variableChange" label-class="width-12" switch-class="max-width-6"
label="Save current variables" ng-if="ctrl.variableValueChange" label-class="width-12" switch-class="max-width-6"
checked="ctrl.saveVariables" on-change="buildUrl()">
</gf-form-switch>
</div>
@@ -70,7 +70,7 @@ export class SaveDashboardModalCtrl {
saveForm: any;
dismiss: () => void;
timeChange = false;
variableChange = false;
variableValueChange = false;
/** @ngInject */
constructor(private dashboardSrv) {
@@ -91,18 +91,24 @@ export class SaveDashboardModalCtrl {
}
compareTemplating() {
//checks if variables has been added or removed, if so variables will be saved automatically
if (this.dashboardSrv.dash.originalTemplating.length !== this.dashboardSrv.dash.templating.list.length) {
return (this.variableValueChange = false);
}
//checks if variable value has changed
if (this.dashboardSrv.dash.templating.list.length > 0) {
for (let i = 0; i < this.dashboardSrv.dash.templating.list.length; i++) {
if (
this.dashboardSrv.dash.templating.list[i].current.text !==
this.dashboardSrv.dash.originalTemplating[i].current.text
) {
return (this.variableChange = true);
return (this.variableValueChange = true);
}
}
return (this.variableChange = false);
return (this.variableValueChange = false);
} else {
return (this.variableChange = false);
return (this.variableValueChange = false);
}
}
@@ -43,7 +43,7 @@ describe('SaveDashboardModal', () => {
let modal = new SaveDashboardModalCtrl(fakeDashboardSrv);
expect(modal.timeChange).toBe(true);
expect(modal.variableChange).toBe(true);
expect(modal.variableValueChange).toBe(true);
});
it('should hide checkboxes', () => {
@@ -54,7 +54,6 @@ describe('SaveDashboardModal', () => {
{
current: {
selected: true,
//tags: Array(0),
text: 'server_002',
value: 'server_002',
},
@@ -84,7 +83,46 @@ describe('SaveDashboardModal', () => {
};
let modal = new SaveDashboardModalCtrl(fakeDashboardSrv);
expect(modal.timeChange).toBe(false);
expect(modal.variableChange).toBe(false);
expect(modal.variableValueChange).toBe(false);
});
it('should hide variable checkboxes', () => {
let fakeDashboardSrv = {
dash: {
templating: {
list: [
{
current: {
selected: true,
text: 'server_002',
value: 'server_002',
},
name: 'Server',
},
{
current: {
selected: true,
text: 'web_002',
value: 'web_002',
},
name: 'Web',
},
],
},
originalTemplating: [
{
current: {
selected: true,
text: 'server_002',
value: 'server_002',
},
name: 'Server',
},
],
},
};
let modal = new SaveDashboardModalCtrl(fakeDashboardSrv);
expect(modal.variableValueChange).toBe(false);
});
});
});
@@ -1,9 +1,9 @@
import config from 'app/core/config';
import $ from 'jquery';
import _ from 'lodash';
import config from 'app/core/config';
import kbn from 'app/core/utils/kbn';
import { PanelCtrl } from 'app/features/panel/panel_ctrl';
import * as rangeUtil from 'app/core/utils/rangeutil';
import * as dateMath from 'app/core/utils/datemath';
import { encodePathComponent } from 'app/core/utils/location_util';
@@ -16,6 +16,7 @@ class MetricsPanelCtrl extends PanelCtrl {
datasourceName: any;
$q: any;
$timeout: any;
contextSrv: any;
datasourceSrv: any;
timeSrv: any;
templateSrv: any;
@@ -37,6 +38,7 @@ class MetricsPanelCtrl extends PanelCtrl {
// make metrics tab the default
this.editorTabIndex = 1;
this.$q = $injector.get('$q');
this.contextSrv = $injector.get('contextSrv');
this.datasourceSrv = $injector.get('datasourceSrv');
this.timeSrv = $injector.get('timeSrv');
this.templateSrv = $injector.get('templateSrv');
@@ -312,7 +314,7 @@ class MetricsPanelCtrl extends PanelCtrl {
getAdditionalMenuItems() {
const items = [];
if (this.datasource && this.datasource.supportsExplore) {
if (this.contextSrv.isEditor && this.datasource && this.datasource.supportsExplore) {
items.push({
text: 'Explore',
click: 'ctrl.explore();',
@@ -24,8 +24,9 @@ describe('MetricsPanelCtrl', () => {
});
});
describe('and has datasource set that supports explore', () => {
describe('and has datasource set that supports explore and user has powers', () => {
beforeEach(() => {
ctrl.contextSrv = { isEditor: true };
ctrl.datasource = { supportsExplore: true };
additionalItems = ctrl.getAdditionalMenuItems();
});
@@ -4,6 +4,7 @@ import * as elasticsearchPlugin from 'app/plugins/datasource/elasticsearch/modul
import * as opentsdbPlugin from 'app/plugins/datasource/opentsdb/module';
import * as grafanaPlugin from 'app/plugins/datasource/grafana/module';
import * as influxdbPlugin from 'app/plugins/datasource/influxdb/module';
import * as influxdbIfqlPlugin from 'app/plugins/datasource/influxdb-ifql/module';
import * as mixedPlugin from 'app/plugins/datasource/mixed/module';
import * as mysqlPlugin from 'app/plugins/datasource/mysql/module';
import * as postgresPlugin from 'app/plugins/datasource/postgres/module';
@@ -30,6 +31,7 @@ const builtInPlugins = {
'app/plugins/datasource/opentsdb/module': opentsdbPlugin,
'app/plugins/datasource/grafana/module': grafanaPlugin,
'app/plugins/datasource/influxdb/module': influxdbPlugin,
'app/plugins/datasource/influxdb-ifql/module': influxdbIfqlPlugin,
'app/plugins/datasource/mixed/module': mixedPlugin,
'app/plugins/datasource/mysql/module': mysqlPlugin,
'app/plugins/datasource/postgres/module': postgresPlugin,
@@ -204,10 +204,18 @@ coreModule.directive('datasourceHttpSettings', function() {
scope: {
current: '=',
suggestUrl: '@',
noDirectAccess: '@',
},
templateUrl: 'public/app/features/plugins/partials/ds_http_settings.html',
link: {
pre: function($scope, elem, attrs) {
// do not show access option if direct access is disabled
$scope.showAccessOption = $scope.noDirectAccess !== 'true';
$scope.showAccessHelp = false;
$scope.toggleAccessHelp = function() {
$scope.showAccessHelp = !$scope.showAccessHelp;
};
$scope.getSuggestUrls = function() {
return [$scope.suggestUrl];
};
@@ -22,7 +22,7 @@
</div>
</div>
<div class="gf-form-inline">
<div class="gf-form-inline" ng-if="showAccessOption">
<div class="gf-form max-width-30">
<span class="gf-form-label width-7">Access</span>
<div class="gf-form-select-wrapper max-width-24">
@@ -30,7 +30,7 @@
</div>
</div>
<div class="gf-form">
<label class="gf-form-label query-keyword pointer" ng-click="ctrl.showAccessHelp = !ctrl.showAccessHelp">
<label class="gf-form-label query-keyword pointer" ng-click="toggleAccessHelp()">
Help&nbsp;
<i class="fa fa-caret-down" ng-show="ctrl.showAccessHelp"></i>
<i class="fa fa-caret-right" ng-hide="ctrl.showAccessHelp">&nbsp;</i>
@@ -38,7 +38,7 @@
</div>
</div>
<div class="alert alert-info" ng-show="ctrl.showAccessHelp">
<div class="alert alert-info" ng-show="showAccessHelp">
<div class="alert-body">
<p>
Access mode controls how requests to the data source will be handled.
+83 -52
View File
@@ -4,70 +4,101 @@
<img class="logo-icon" src="public/img/grafana_icon.svg" alt="Grafana" />
<i class="icon-gf icon-gf-grafana_wordmark"></i>
</div>
<div class="login-inner-box">
<form name="loginForm" class="login-form-group gf-form-group" ng-hide="disableLoginForm">
<div class="login-form">
<input type="text" name="username" class="gf-form-input login-form-input" required ng-model='formModel.user' placeholder={{loginHint}}
autofocus>
</div>
<div class="login-form">
<input type="password" name="password" class="gf-form-input login-form-input" required ng-model="formModel.password" id="inputPassword"
placeholder="password">
</div>
<div class="login-button-group">
<button type="submit" class="btn btn-large p-x-2" ng-click="submit();" ng-class="{'btn-inverse': !loginForm.$valid, 'btn-primary': loginForm.$valid}">
Log In
</button>
<div class="login-outer-box">
<div class="login-inner-box" id="login-view">
<form name="loginForm" class="login-form-group gf-form-group" ng-hide="disableLoginForm">
<div class="login-form">
<input type="text" name="username" class="gf-form-input login-form-input" required ng-model='formModel.user' placeholder={{loginHint}}
autofocus>
</div>
<div class="login-form">
<input type="password" name="password" class="gf-form-input login-form-input" required ng-model="formModel.password" id="inputPassword"
placeholder="password">
</div>
<div class="login-button-group">
<button type="submit" class="btn btn-large p-x-2" ng-click="submit();" ng-class="{'btn-inverse': !loginForm.$valid, 'btn-primary': loginForm.$valid}">
Log In
</button>
<div class="small login-button-forgot-password">
<a href="user/password/send-reset-email">
Forgot your password?
</a>
</div>
</div>
</form>
<div class="text-center login-divider" ng-show="oauthEnabled">
<div>
<div class="login-divider-line">
</div>
</div>
<div>
<span class="login-divider-text">
<span ng-hide="disableLoginForm">or</span>
</span>
</div>
<div>
<div class="login-divider-line">
</div>
</div>
</div>
</form>
<div class="text-center login-divider" ng-show="oauthEnabled">
<div>
<div class="login-divider-line">
<div class="clearfix"></div>
<div class="login-oauth text-center" ng-show="oauthEnabled">
<a class="btn btn-medium btn-service btn-service--google login-btn" href="login/google" target="_self" ng-if="oauth.google">
<i class="btn-service-icon fa fa-google"></i>
Sign in with Google
</a>
<a class="btn btn-medium btn-service btn-service--github login-btn" href="login/github" target="_self" ng-if="oauth.github">
<i class="btn-service-icon fa fa-github"></i>
Sign in with GitHub
</a>
<a class="btn btn-medium btn-inverse btn-service btn-service--grafanacom login-btn" href="login/grafana_com" target="_self"
ng-if="oauth.grafana_com">
<i class="btn-service-icon"></i>
Sign in with Grafana.com
</a>
<a class="btn btn-medium btn-inverse btn-service btn-service--oauth login-btn" href="login/generic_oauth" target="_self"
ng-if="oauth.generic_oauth">
<i class="btn-service-icon fa fa-sign-in"></i>
Sign in with {{oauth.generic_oauth.name}}
</a>
</div>
<div class="login-signup-box" ng-show="!disableUserSignUp">
<div class="login-signup-title p-r-1">
New to Grafana?
</div>
<a href="signup" class="btn btn-medium btn-signup btn-p-x-2">
Sign Up
</a>
</div>
<div>
<span class="login-divider-text">
<span ng-hide="disableLoginForm">or</span>
</span>
</div>
<div class="login-inner-box remove hidden" id="change-password-view">
<div class="text-left login-change-password-info">
<h5>Change Password</h5>
Before you can get started with awesome dashboards we need you to make your account more secure by changing your password.
<br />You can change your password again later.
</div>
<div>
<div class="login-divider-line">
<form class="login-form-group gf-form-group">
<div class="login-form">
<input type="password" id="newPassword" name="newPassword" class="gf-form-input login-form-input" required ng-model='command.newPassword'
placeholder="New password">
</div>
</div>
<div class="login-form">
<input type="password" name="confirmNew" class="gf-form-input login-form-input" required ng-model="command.confirmNew" placeholder="Confirm new password">
</div>
<div class="login-button-group login-button-group--right text-right">
<a class="btn btn-link" ng-click="skip();">
Skip
<info-popover mode="no-padding">
If you skip you will be promted to change password next time you login.
</info-popover>
</a>
<button type="submit" class="btn btn-large p-x-2" ng-click="changePassword();" ng-class="{'btn-inverse': !loginForm.$valid, 'btn-success': loginForm.$valid}">
Save
</button>
</div>
</form>
</div>
<div class="clearfix"></div>
<div class="login-oauth text-center" ng-show="oauthEnabled">
<a class="btn btn-medium btn-service btn-service--google login-btn" href="login/google" target="_self" ng-if="oauth.google">
<i class="btn-service-icon fa fa-google"></i>
Sign in with Google
</a>
<a class="btn btn-medium btn-service btn-service--github login-btn" href="login/github" target="_self" ng-if="oauth.github">
<i class="btn-service-icon fa fa-github"></i>
Sign in with GitHub
</a>
<a class="btn btn-medium btn-inverse btn-service btn-service--grafanacom login-btn" href="login/grafana_com" target="_self" ng-if="oauth.grafana_com">
<i class="btn-service-icon"></i>
Sign in with Grafana.com
</a>
<a class="btn btn-medium btn-inverse btn-service btn-service--oauth login-btn" href="login/generic_oauth" target="_self" ng-if="oauth.generic_oauth">
<i class="btn-service-icon fa fa-sign-in"></i>
Sign in with {{oauth.generic_oauth.name}}
</a>
</div>
<div class="login-signup-box" ng-show="!disableUserSignUp">
<div class="login-signup-title p-r-1">
New to Grafana?
</div>
<a href="signup" class="btn btn-medium btn-signup btn-p-x-2">
Sign Up
</a>
</div>
</div>
<div class="clearfix"></div>
</div>
</div>
@@ -0,0 +1,26 @@
# InfluxDB (IFQL) Datasource [BETA] - Native Plugin
Grafana ships with **built in** support for InfluxDB (>= 1.4.1).
Use this datasource if you want to use IFQL to query your InfluxDB.
Feel free to run this datasource side-by-side with the non-IFQL datasource.
If you point both datasources to the same InfluxDB instance, you can switch query mode by switching the datasources.
Read more about IFQL here:
[https://github.com/influxdata/ifql](https://github.com/influxdata/ifql)
Read more about InfluxDB here:
[http://docs.grafana.org/datasources/influxdb/](http://docs.grafana.org/datasources/influxdb/)
## Roadmap
- Sync Grafana time ranges with `range()`
- Template variable expansion
- Syntax highlighting
- Tab completion (functions, values)
- Result helpers (result counts, table previews)
- Annotations support
- Alerting integration
- Explore UI integration
@@ -0,0 +1,233 @@
import _ from 'lodash';
import * as dateMath from 'app/core/utils/datemath';
import { getTableModelFromResult, getTimeSeriesFromResult, parseResults } from './response_parser';
function serializeParams(params) {
if (!params) {
return '';
}
return _.reduce(
params,
(memo, value, key) => {
if (value === null || value === undefined) {
return memo;
}
memo.push(encodeURIComponent(key) + '=' + encodeURIComponent(value));
return memo;
},
[]
).join('&');
}
const MAX_SERIES = 20;
export default class InfluxDatasource {
type: string;
url: string;
username: string;
password: string;
name: string;
orgName: string;
database: any;
basicAuth: any;
withCredentials: any;
interval: any;
supportAnnotations: boolean;
supportMetrics: boolean;
/** @ngInject */
constructor(instanceSettings, private backendSrv, private templateSrv) {
this.type = 'influxdb-ifql';
this.url = instanceSettings.url.trim();
this.username = instanceSettings.username;
this.password = instanceSettings.password;
this.name = instanceSettings.name;
this.orgName = instanceSettings.orgName || 'defaultorgname';
this.database = instanceSettings.database;
this.basicAuth = instanceSettings.basicAuth;
this.withCredentials = instanceSettings.withCredentials;
this.interval = (instanceSettings.jsonData || {}).timeInterval;
this.supportAnnotations = true;
this.supportMetrics = true;
}
prepareQueries(options) {
const targets = _.cloneDeep(options.targets);
const timeFilter = this.getTimeFilter(options);
options.scopedVars.range = { value: timeFilter };
// Filter empty queries and replace grafana variables
const queryTargets = targets.filter(t => t.query).map(t => {
const interpolated = this.templateSrv.replace(t.query, options.scopedVars);
return {
...t,
query: interpolated,
};
});
return queryTargets;
}
query(options) {
const queryTargets = this.prepareQueries(options);
if (queryTargets.length === 0) {
return Promise.resolve({ data: [] });
}
const queries = queryTargets.map(target => {
const { query, resultFormat } = target;
if (resultFormat === 'table') {
return (
this._seriesQuery(query, options)
.then(response => parseResults(response.data))
// Keep only first result from each request
.then(results => results[0])
.then(getTableModelFromResult)
);
} else {
return this._seriesQuery(query, options)
.then(response => parseResults(response.data))
.then(results => results.map(getTimeSeriesFromResult));
}
});
return Promise.all(queries).then((series: any) => {
let seriesList = _.flattenDeep(series).slice(0, MAX_SERIES);
return { data: seriesList };
});
}
annotationQuery(options) {
if (!options.annotation.query) {
return Promise.reject({
message: 'Query missing in annotation definition',
});
}
var timeFilter = this.getTimeFilter({ rangeRaw: options.rangeRaw });
var query = options.annotation.query.replace('$timeFilter', timeFilter);
query = this.templateSrv.replace(query, null, 'regex');
return {};
}
metricFindQuery(query: string, options?: any) {
// TODO not implemented
var interpolated = this.templateSrv.replace(query, null, 'regex');
return this._seriesQuery(interpolated, options).then(_.curry(parseResults)(query));
}
_seriesQuery(query: string, options?: any) {
if (!query) {
return Promise.resolve({ data: '' });
}
return this._influxRequest('POST', '/v1/query', { q: query }, options);
}
testDatasource() {
const query = `from(db:"${this.database}") |> last()`;
return this._influxRequest('POST', '/v1/query', { q: query })
.then(res => {
if (res && res.trim()) {
return { status: 'success', message: 'Data source connected and database found.' };
}
return {
status: 'error',
message:
'Data source connected, but has no data. Verify the "Database" field and make sure the database has data.',
};
})
.catch(err => {
return { status: 'error', message: err.message };
});
}
_influxRequest(method: string, url: string, data: any, options?: any) {
let params: any = {
orgName: this.orgName,
};
if (this.username) {
params.u = this.username;
params.p = this.password;
}
// data sent as GET param
_.extend(params, data);
data = null;
let req: any = {
method: method,
url: this.url + url,
params: params,
data: data,
precision: 'ms',
inspect: { type: this.type },
paramSerializer: serializeParams,
};
req.headers = req.headers || {};
if (this.basicAuth || this.withCredentials) {
req.withCredentials = true;
}
if (this.basicAuth) {
req.headers.Authorization = this.basicAuth;
}
return this.backendSrv.datasourceRequest(req).then(
result => {
return result;
},
function(err) {
if (err.status !== 0 || err.status >= 300) {
if (err.data && err.data.error) {
throw {
message: 'InfluxDB Error: ' + err.data.error,
data: err.data,
config: err.config,
};
} else {
throw {
message: 'Network Error: ' + err.statusText + '(' + err.status + ')',
data: err.data,
config: err.config,
};
}
}
}
);
}
getTimeFilter(options) {
const from = this.getInfluxTime(options.rangeRaw.from, false);
const to = this.getInfluxTime(options.rangeRaw.to, true);
if (to === 'now') {
return `start: ${from}`;
}
return `start: ${from}, stop: ${to}`;
}
getInfluxTime(date, roundUp) {
if (_.isString(date)) {
if (date === 'now') {
return date;
}
const parts = /^now\s*-\s*(\d+)([d|h|m|s])$/.exec(date);
if (parts) {
const amount = parseInt(parts[1]);
const unit = parts[2];
return '-' + amount + unit;
}
date = dateMath.parse(date, roundUp);
}
return date.toISOString();
}
}
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 78.8 79.9" style="enable-background:new 0 0 78.8 79.9;" xml:space="preserve">
<style type="text/css">
.st0{fill:url(#symbol_1_);}
</style>
<g id="influxdb_logo">
<linearGradient id="symbol_1_" gradientUnits="userSpaceOnUse" x1="41.5273" y1="41.85" x2="319.2919" y2="41.85" gradientTransform="matrix(1 0 0 -1 0 81.8)">
<stop offset="0" style="stop-color:#4591ED"/>
<stop offset="1" style="stop-color:#00C9FF"/>
</linearGradient>
<path id="symbol_2_" class="st0" d="M78.7,48.2L71.1,15c-0.4-1.8-2.1-3.6-3.9-4.1L32.3,0.2c-0.5-0.1-1-0.2-1.5-0.2
c-1.5,0-3.1,0.6-4,1.5l-25,23.2c-1.3,1.2-2.1,3.6-1.7,5.4l8.1,35.5c0.4,1.8,2.1,3.6,3.9,4.1l32.6,10c0.5,0.1,1,0.2,1.5,0.2
c1.5,0,3.1-0.6,4-1.5l26.7-24.8C78.4,52.4,79.1,50,78.7,48.2z M35.9,8l23.9,7.3c0.9,0.3,0.9,0.7,0,0.9l-12.6,2.9
c-1,0.2-2.3-0.2-2.9-0.9l-8.8-9.5C34.8,8.1,35,7.8,35.9,8z M50.8,50.9c0.2,1-0.4,1.5-1.3,1.2l-25.8-7.9c-0.9-0.3-1.1-1.1-0.4-1.7
l19.8-18.4c0.7-0.7,1.5-0.4,1.7,0.5L50.8,50.9z M8.3,27.5L29.3,8c0.7-0.7,1.8-0.6,2.5,0.1l10.5,11.3c0.7,0.7,0.6,1.8-0.1,2.5
l-21,19.5c-0.7,0.7-1.8,0.6-2.5-0.1L8.2,30C7.6,29.3,7.6,28.2,8.3,27.5z M13.4,58.5L7.8,34.2c-0.2-1,0.1-1.1,0.8-0.4l8.8,9.5
c0.7,0.7,1,2.1,0.7,3l-3.8,12.3C14.1,59.4,13.6,59.4,13.4,58.5z M44.1,72.6l-27.3-8.4c-0.9-0.3-1.5-1.3-1.2-2.2l4.5-14.8
c0.3-0.9,1.3-1.5,2.2-1.2l27.3,8.4c0.9,0.3,1.5,1.3,1.2,2.2l-4.5,14.8C46,72.4,45,72.9,44.1,72.6z M68.4,52.7l-18.3,17
c-0.7,0.7-1.1,0.4-0.8-0.5l3.8-12.3c0.3-0.9,1.3-1.9,2.3-2.1L68,51.9C68.9,51.7,69.1,52.1,68.4,52.7z M70.4,49.1l-15.1,3.4
c-1,0.2-1.9-0.4-2.1-1.3l-6.4-27.9c-0.2-1,0.4-1.9,1.3-2.1l15.1-3.4c1-0.2,1.9,0.4,2.1,1.3L71.7,47C71.9,47.9,71.3,48.9,70.4,49.1z
"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -0,0 +1,17 @@
import InfluxDatasource from './datasource';
import { InfluxIfqlQueryCtrl } from './query_ctrl';
class InfluxConfigCtrl {
static templateUrl = 'partials/config.html';
}
class InfluxAnnotationsQueryCtrl {
static templateUrl = 'partials/annotations.editor.html';
}
export {
InfluxDatasource as Datasource,
InfluxIfqlQueryCtrl as QueryCtrl,
InfluxConfigCtrl as ConfigCtrl,
InfluxAnnotationsQueryCtrl as AnnotationsQueryCtrl,
};
@@ -0,0 +1,24 @@
<div class="gf-form-group">
<div class="gf-form">
<input type="text" class="gf-form-input" ng-model='ctrl.annotation.query' placeholder="select text from events where $timeFilter limit 1000"></input>
</div>
</div>
<h5 class="section-heading">Field mappings <tip>If your influxdb query returns more than one field you need to specify the column names below. An annotation event is composed of a title, tags, and an additional text field.</tip></h5>
<div class="gf-form-group">
<div class="gf-form-inline">
<div class="gf-form">
<span class="gf-form-label width-4">Text</span>
<input type="text" class="gf-form-input max-width-10" ng-model='ctrl.annotation.textColumn' placeholder=""></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-4">Tags</span>
<input type="text" class="gf-form-input max-width-10" ng-model='ctrl.annotation.tagsColumn' placeholder=""></input>
</div>
<div class="gf-form" ng-show="ctrl.annotation.titleColumn">
<span class="gf-form-label width-4">Title <em class="muted">(deprecated)</em></span>
<input type="text" class="gf-form-input max-width-10" ng-model='ctrl.annotation.titleColumn' placeholder=""></input>
</div>
</div>
</div>
@@ -0,0 +1,24 @@
<datasource-http-settings current="ctrl.current" no-direct-access="true" suggest-url="http://localhost:8093">
</datasource-http-settings>
<h3 class="page-heading">InfluxDB Details</h3>
<div class="gf-form-group">
<div class="gf-form-inline">
<div class="gf-form max-width-30">
<span class="gf-form-label width-7">Default Database</span>
<input type="text" class="gf-form-input" ng-model='ctrl.current.database' placeholder="" required></input>
</div>
</div>
<div class="gf-form-inline">
<div class="gf-form max-width-15">
<span class="gf-form-label width-7">User</span>
<input type="text" class="gf-form-input" ng-model='ctrl.current.user' placeholder=""></input>
</div>
<div class="gf-form max-width-15">
<span class="gf-form-label width-7">Password</span>
<input type="password" class="gf-form-input" ng-model='ctrl.current.password' placeholder=""></input>
</div>
</div>
</div>
@@ -0,0 +1,24 @@
<query-editor-row query-ctrl="ctrl" can-collapse="true" has-text-edit-mode="true">
<div class="gf-form">
<textarea rows="3" class="gf-form-input" ng-model="ctrl.target.query" spellcheck="false" placeholder="IFQL Query" ng-model-onblur
ng-change="ctrl.refresh()"></textarea>
</div>
<div class="gf-form-inline">
<div class="gf-form">
<label class="gf-form-label query-keyword">FORMAT AS</label>
<div class="gf-form-select-wrapper">
<select class="gf-form-input gf-size-auto" ng-model="ctrl.target.resultFormat" ng-options="f.value as f.text for f in ctrl.resultFormats"
ng-change="ctrl.refresh()"></select>
</div>
</div>
<div class="gf-form max-width-25" ng-hide="ctrl.target.resultFormat === 'table'">
<label class="gf-form-label query-keyword">ALIAS BY</label>
<input type="text" class="gf-form-input" ng-model="ctrl.target.alias" spellcheck='false' placeholder="Naming pattern" ng-blur="ctrl.refresh()">
</div>
<div class="gf-form gf-form--grow">
<div class="gf-form-label gf-form-label--grow"></div>
</div>
</div>
</query-editor-row>
@@ -0,0 +1,24 @@
{
"type": "datasource",
"name": "InfluxDB (IFQL) [BETA]",
"id": "influxdb-ifql",
"defaultMatchFormat": "regex values",
"metrics": true,
"annotations": false,
"alerting": false,
"queryOptions": {
"minInterval": true
},
"info": {
"description": "InfluxDB Data Source for IFQL Queries for Grafana",
"author": {
"name": "Grafana Project",
"url": "https://grafana.com"
},
"logos": {
"small": "img/influxdb_logo.svg",
"large": "img/influxdb_logo.svg"
},
"version": "5.1.0"
}
}
@@ -0,0 +1,27 @@
import { QueryCtrl } from 'app/plugins/sdk';
function makeDefaultQuery(database) {
return `from(db: "${database}")
|> range($range)
|> limit(n:1000)
`;
}
export class InfluxIfqlQueryCtrl extends QueryCtrl {
static templateUrl = 'partials/query.editor.html';
resultFormats: any[];
/** @ngInject **/
constructor($scope, $injector) {
super($scope, $injector);
if (this.target.query === undefined) {
this.target.query = makeDefaultQuery(this.datasource.database);
}
this.resultFormats = [{ text: 'Time series', value: 'time_series' }, { text: 'Table', value: 'table' }];
}
getCollapsedText() {
return this.target.query;
}
}
@@ -0,0 +1,88 @@
import Papa from 'papaparse';
import groupBy from 'lodash/groupBy';
import TableModel from 'app/core/table_model';
const filterColumnKeys = key => key && key[0] !== '_' && key !== 'result' && key !== 'table';
const IGNORE_FIELDS_FOR_NAME = ['result', '', 'table'];
export const getNameFromRecord = record => {
// Measurement and field
const metric = [record._measurement, record._field];
// Add tags
const tags = Object.keys(record)
.filter(key => key[0] !== '_')
.filter(key => IGNORE_FIELDS_FOR_NAME.indexOf(key) === -1)
.map(key => `${key}=${record[key]}`);
return [...metric, ...tags].join(' ');
};
const parseCSV = (input: string) =>
Papa.parse(input, {
header: true,
comments: '#',
}).data;
export const parseValue = (input: string) => {
const value = parseFloat(input);
return isNaN(value) ? null : value;
};
export const parseTime = (input: string) => Date.parse(input);
export function parseResults(response: string): any[] {
return response.trim().split(/\n\s*\s/);
}
export function getTableModelFromResult(result: string) {
const data = parseCSV(result);
const table = new TableModel();
if (data.length > 0) {
// First columns are fixed
const firstColumns = [
{ text: 'Time', id: '_time' },
{ text: 'Measurement', id: '_measurement' },
{ text: 'Field', id: '_field' },
];
// Dynamically add columns for tags
const firstRecord = data[0];
const tags = Object.keys(firstRecord)
.filter(filterColumnKeys)
.map(key => ({ id: key, text: key }));
const valueColumn = { id: '_value', text: 'Value' };
const columns = [...firstColumns, ...tags, valueColumn];
columns.forEach(c => table.addColumn(c));
// Add rows
data.forEach(record => {
const row = columns.map(c => record[c.id]);
table.addRow(row);
});
}
return table;
}
export function getTimeSeriesFromResult(result: string) {
const data = parseCSV(result);
if (data.length === 0) {
return [];
}
// Group results by table ID (assume one table per timeseries for now)
const tables = groupBy(data, 'table');
const seriesList = Object.keys(tables)
.map(id => tables[id])
.map(series => {
const datapoints = series.map(record => [parseValue(record._value), parseTime(record._time)]);
const alias = getNameFromRecord(series[0]);
return { datapoints, target: alias };
});
return seriesList;
}
@@ -0,0 +1,53 @@
import moment from 'moment';
import { TemplateSrv } from 'app/features/templating/template_srv';
import Datasource from '../datasource';
describe('InfluxDB (IFQL)', () => {
const templateSrv = new TemplateSrv();
const ds = new Datasource({ url: '' }, {}, templateSrv);
const DEFAULT_OPTIONS = {
rangeRaw: { to: 'now', from: 'now - 3h' },
scopedVars: {},
targets: [],
};
let queries: any[];
describe('prepareQueries()', () => {
it('filters empty queries', () => {
queries = ds.prepareQueries(DEFAULT_OPTIONS);
expect(queries.length).toBe(0);
queries = ds.prepareQueries({
...DEFAULT_OPTIONS,
targets: [{ query: '' }],
});
expect(queries.length).toBe(0);
});
it('replaces $range variable', () => {
queries = ds.prepareQueries({
...DEFAULT_OPTIONS,
targets: [{ query: 'from(db: "test") |> range($range)' }],
});
expect(queries.length).toBe(1);
expect(queries[0].query).toBe('from(db: "test") |> range(start: -3h)');
});
it('replaces $range variable with custom dates', () => {
const to = moment();
const from = moment().subtract(1, 'hours');
queries = ds.prepareQueries({
...DEFAULT_OPTIONS,
rangeRaw: { to, from },
targets: [{ query: 'from(db: "test") |> range($range)' }],
});
expect(queries.length).toBe(1);
const start = from.toISOString();
const stop = to.toISOString();
expect(queries[0].query).toBe(`from(db: "test") |> range(start: ${start}, stop: ${stop})`);
});
});
});
@@ -0,0 +1,63 @@
import {
getNameFromRecord,
getTableModelFromResult,
getTimeSeriesFromResult,
parseResults,
parseValue,
} from '../response_parser';
import response from './sample_response_csv';
describe('influxdb ifql response parser', () => {
describe('parseResults()', () => {
it('expects three results', () => {
const results = parseResults(response);
expect(results.length).toBe(2);
});
});
describe('getTableModelFromResult()', () => {
it('expects a table model', () => {
const results = parseResults(response);
const table = getTableModelFromResult(results[0]);
expect(table.columns.length).toBe(6);
expect(table.rows.length).toBe(300);
});
});
describe('getTimeSeriesFromResult()', () => {
it('expects time series', () => {
const results = parseResults(response);
const series = getTimeSeriesFromResult(results[0]);
expect(series.length).toBe(50);
expect(series[0].datapoints.length).toBe(6);
});
});
describe('getNameFromRecord()', () => {
it('expects name based on measurements and tags', () => {
const record = {
'': '',
result: '',
table: '0',
_start: '2018-06-02T06:35:25.651942602Z',
_stop: '2018-06-02T07:35:25.651942602Z',
_time: '2018-06-02T06:35:31Z',
_value: '0',
_field: 'usage_guest',
_measurement: 'cpu',
cpu: 'cpu-total',
host: 'kenobi-3.local',
};
expect(getNameFromRecord(record)).toBe('cpu usage_guest cpu=cpu-total host=kenobi-3.local');
});
});
describe('parseValue()', () => {
it('parses a number', () => {
expect(parseValue('42.3')).toBe(42.3);
});
it('parses a non-number to null', () => {
expect(parseValue('foo')).toBe(null);
});
});
});
@@ -0,0 +1,349 @@
const result = `#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,double,string,string,string,string
#partition,false,false,true,true,false,false,true,true,true,true
#default,_result,,,,,,,,,
,result,table,_start,_stop,_time,_value,_field,_measurement,cpu,host
,,0,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_guest,cpu,cpu-total,kenobi-3.local
,,0,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_guest,cpu,cpu-total,kenobi-3.local
,,0,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_guest,cpu,cpu-total,kenobi-3.local
,,0,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_guest,cpu,cpu-total,kenobi-3.local
,,0,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_guest,cpu,cpu-total,kenobi-3.local
,,0,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_guest,cpu,cpu-total,kenobi-3.local
,,1,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_guest_nice,cpu,cpu-total,kenobi-3.local
,,1,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_guest_nice,cpu,cpu-total,kenobi-3.local
,,1,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_guest_nice,cpu,cpu-total,kenobi-3.local
,,1,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_guest_nice,cpu,cpu-total,kenobi-3.local
,,1,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_guest_nice,cpu,cpu-total,kenobi-3.local
,,1,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_guest_nice,cpu,cpu-total,kenobi-3.local
,,2,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,81.87046761690422,usage_idle,cpu,cpu-total,kenobi-3.local
,,2,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,82.03398300849575,usage_idle,cpu,cpu-total,kenobi-3.local
,,2,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,76.26186906546727,usage_idle,cpu,cpu-total,kenobi-3.local
,,2,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,79.65465465465465,usage_idle,cpu,cpu-total,kenobi-3.local
,,2,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,70.72195853110168,usage_idle,cpu,cpu-total,kenobi-3.local
,,2,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,69.86746686671668,usage_idle,cpu,cpu-total,kenobi-3.local
,,3,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_iowait,cpu,cpu-total,kenobi-3.local
,,3,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_iowait,cpu,cpu-total,kenobi-3.local
,,3,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_iowait,cpu,cpu-total,kenobi-3.local
,,3,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_iowait,cpu,cpu-total,kenobi-3.local
,,3,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_iowait,cpu,cpu-total,kenobi-3.local
,,3,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_iowait,cpu,cpu-total,kenobi-3.local
,,4,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_irq,cpu,cpu-total,kenobi-3.local
,,4,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_irq,cpu,cpu-total,kenobi-3.local
,,4,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_irq,cpu,cpu-total,kenobi-3.local
,,4,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_irq,cpu,cpu-total,kenobi-3.local
,,4,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_irq,cpu,cpu-total,kenobi-3.local
,,4,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_irq,cpu,cpu-total,kenobi-3.local
,,5,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_nice,cpu,cpu-total,kenobi-3.local
,,5,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_nice,cpu,cpu-total,kenobi-3.local
,,5,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_nice,cpu,cpu-total,kenobi-3.local
,,5,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_nice,cpu,cpu-total,kenobi-3.local
,,5,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_nice,cpu,cpu-total,kenobi-3.local
,,5,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_nice,cpu,cpu-total,kenobi-3.local
,,6,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_softirq,cpu,cpu-total,kenobi-3.local
,,6,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_softirq,cpu,cpu-total,kenobi-3.local
,,6,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_softirq,cpu,cpu-total,kenobi-3.local
,,6,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_softirq,cpu,cpu-total,kenobi-3.local
,,6,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_softirq,cpu,cpu-total,kenobi-3.local
,,6,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_softirq,cpu,cpu-total,kenobi-3.local
,,7,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_steal,cpu,cpu-total,kenobi-3.local
,,7,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_steal,cpu,cpu-total,kenobi-3.local
,,7,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_steal,cpu,cpu-total,kenobi-3.local
,,7,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_steal,cpu,cpu-total,kenobi-3.local
,,7,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_steal,cpu,cpu-total,kenobi-3.local
,,7,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_steal,cpu,cpu-total,kenobi-3.local
,,8,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,6.25156289072268,usage_system,cpu,cpu-total,kenobi-3.local
,,8,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,8.045977011494253,usage_system,cpu,cpu-total,kenobi-3.local
,,8,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,8.79560219890055,usage_system,cpu,cpu-total,kenobi-3.local
,,8,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,8.408408408408409,usage_system,cpu,cpu-total,kenobi-3.local
,,8,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,11.64126904821384,usage_system,cpu,cpu-total,kenobi-3.local
,,8,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,13.078269567391848,usage_system,cpu,cpu-total,kenobi-3.local
,,9,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,11.877969492373094,usage_user,cpu,cpu-total,kenobi-3.local
,,9,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,9.920039980009996,usage_user,cpu,cpu-total,kenobi-3.local
,,9,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,14.942528735632184,usage_user,cpu,cpu-total,kenobi-3.local
,,9,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,11.936936936936936,usage_user,cpu,cpu-total,kenobi-3.local
,,9,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,17.636772420684487,usage_user,cpu,cpu-total,kenobi-3.local
,,9,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,17.05426356589147,usage_user,cpu,cpu-total,kenobi-3.local
,,10,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_guest,cpu,cpu0,kenobi-3.local
,,10,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_guest,cpu,cpu0,kenobi-3.local
,,10,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_guest,cpu,cpu0,kenobi-3.local
,,10,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_guest,cpu,cpu0,kenobi-3.local
,,10,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_guest,cpu,cpu0,kenobi-3.local
,,10,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_guest,cpu,cpu0,kenobi-3.local
,,11,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_guest_nice,cpu,cpu0,kenobi-3.local
,,11,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_guest_nice,cpu,cpu0,kenobi-3.local
,,11,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_guest_nice,cpu,cpu0,kenobi-3.local
,,11,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_guest_nice,cpu,cpu0,kenobi-3.local
,,11,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_guest_nice,cpu,cpu0,kenobi-3.local
,,11,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_guest_nice,cpu,cpu0,kenobi-3.local
,,12,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,73.1,usage_idle,cpu,cpu0,kenobi-3.local
,,12,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,69.03096903096903,usage_idle,cpu,cpu0,kenobi-3.local
,,12,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,63.63636363636363,usage_idle,cpu,cpu0,kenobi-3.local
,,12,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,67.86786786786787,usage_idle,cpu,cpu0,kenobi-3.local
,,12,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,57.4,usage_idle,cpu,cpu0,kenobi-3.local
,,12,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,57.8,usage_idle,cpu,cpu0,kenobi-3.local
,,13,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_iowait,cpu,cpu0,kenobi-3.local
,,13,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_iowait,cpu,cpu0,kenobi-3.local
,,13,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_iowait,cpu,cpu0,kenobi-3.local
,,13,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_iowait,cpu,cpu0,kenobi-3.local
,,13,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_iowait,cpu,cpu0,kenobi-3.local
,,13,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_iowait,cpu,cpu0,kenobi-3.local
,,14,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_irq,cpu,cpu0,kenobi-3.local
,,14,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_irq,cpu,cpu0,kenobi-3.local
,,14,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_irq,cpu,cpu0,kenobi-3.local
,,14,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_irq,cpu,cpu0,kenobi-3.local
,,14,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_irq,cpu,cpu0,kenobi-3.local
,,14,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_irq,cpu,cpu0,kenobi-3.local
,,15,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_nice,cpu,cpu0,kenobi-3.local
,,15,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_nice,cpu,cpu0,kenobi-3.local
,,15,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_nice,cpu,cpu0,kenobi-3.local
,,15,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_nice,cpu,cpu0,kenobi-3.local
,,15,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_nice,cpu,cpu0,kenobi-3.local
,,15,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_nice,cpu,cpu0,kenobi-3.local
,,16,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_softirq,cpu,cpu0,kenobi-3.local
,,16,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_softirq,cpu,cpu0,kenobi-3.local
,,16,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_softirq,cpu,cpu0,kenobi-3.local
,,16,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_softirq,cpu,cpu0,kenobi-3.local
,,16,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_softirq,cpu,cpu0,kenobi-3.local
,,16,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_softirq,cpu,cpu0,kenobi-3.local
,,17,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_steal,cpu,cpu0,kenobi-3.local
,,17,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_steal,cpu,cpu0,kenobi-3.local
,,17,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_steal,cpu,cpu0,kenobi-3.local
,,17,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_steal,cpu,cpu0,kenobi-3.local
,,17,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_steal,cpu,cpu0,kenobi-3.local
,,17,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_steal,cpu,cpu0,kenobi-3.local
,,18,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,9.6,usage_system,cpu,cpu0,kenobi-3.local
,,18,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,14.985014985014985,usage_system,cpu,cpu0,kenobi-3.local
,,18,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,14.185814185814186,usage_system,cpu,cpu0,kenobi-3.local
,,18,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,13.813813813813814,usage_system,cpu,cpu0,kenobi-3.local
,,18,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,17.9,usage_system,cpu,cpu0,kenobi-3.local
,,18,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,20,usage_system,cpu,cpu0,kenobi-3.local
,,19,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,17.3,usage_user,cpu,cpu0,kenobi-3.local
,,19,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,15.984015984015985,usage_user,cpu,cpu0,kenobi-3.local
,,19,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,22.17782217782218,usage_user,cpu,cpu0,kenobi-3.local
,,19,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,18.31831831831832,usage_user,cpu,cpu0,kenobi-3.local
,,19,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,24.7,usage_user,cpu,cpu0,kenobi-3.local
,,19,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,22.2,usage_user,cpu,cpu0,kenobi-3.local
,,20,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_guest,cpu,cpu1,kenobi-3.local
,,20,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_guest,cpu,cpu1,kenobi-3.local
,,20,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_guest,cpu,cpu1,kenobi-3.local
,,20,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_guest,cpu,cpu1,kenobi-3.local
,,20,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_guest,cpu,cpu1,kenobi-3.local
,,20,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_guest,cpu,cpu1,kenobi-3.local
,,21,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_guest_nice,cpu,cpu1,kenobi-3.local
,,21,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_guest_nice,cpu,cpu1,kenobi-3.local
,,21,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_guest_nice,cpu,cpu1,kenobi-3.local
,,21,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_guest_nice,cpu,cpu1,kenobi-3.local
,,21,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_guest_nice,cpu,cpu1,kenobi-3.local
,,21,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_guest_nice,cpu,cpu1,kenobi-3.local
,,22,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,89.8,usage_idle,cpu,cpu1,kenobi-3.local
,,22,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,91.8,usage_idle,cpu,cpu1,kenobi-3.local
,,22,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,87.11288711288711,usage_idle,cpu,cpu1,kenobi-3.local
,,22,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,89.48948948948949,usage_idle,cpu,cpu1,kenobi-3.local
,,22,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,83,usage_idle,cpu,cpu1,kenobi-3.local
,,22,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,80.1,usage_idle,cpu,cpu1,kenobi-3.local
,,23,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_iowait,cpu,cpu1,kenobi-3.local
,,23,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_iowait,cpu,cpu1,kenobi-3.local
,,23,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_iowait,cpu,cpu1,kenobi-3.local
,,23,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_iowait,cpu,cpu1,kenobi-3.local
,,23,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_iowait,cpu,cpu1,kenobi-3.local
,,23,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_iowait,cpu,cpu1,kenobi-3.local
,,24,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_irq,cpu,cpu1,kenobi-3.local
,,24,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_irq,cpu,cpu1,kenobi-3.local
,,24,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_irq,cpu,cpu1,kenobi-3.local
,,24,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_irq,cpu,cpu1,kenobi-3.local
,,24,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_irq,cpu,cpu1,kenobi-3.local
,,24,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_irq,cpu,cpu1,kenobi-3.local
,,25,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_nice,cpu,cpu1,kenobi-3.local
,,25,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_nice,cpu,cpu1,kenobi-3.local
,,25,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_nice,cpu,cpu1,kenobi-3.local
,,25,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_nice,cpu,cpu1,kenobi-3.local
,,25,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_nice,cpu,cpu1,kenobi-3.local
,,25,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_nice,cpu,cpu1,kenobi-3.local
,,26,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_softirq,cpu,cpu1,kenobi-3.local
,,26,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_softirq,cpu,cpu1,kenobi-3.local
,,26,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_softirq,cpu,cpu1,kenobi-3.local
,,26,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_softirq,cpu,cpu1,kenobi-3.local
,,26,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_softirq,cpu,cpu1,kenobi-3.local
,,26,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_softirq,cpu,cpu1,kenobi-3.local
,,27,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_steal,cpu,cpu1,kenobi-3.local
,,27,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_steal,cpu,cpu1,kenobi-3.local
,,27,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_steal,cpu,cpu1,kenobi-3.local
,,27,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_steal,cpu,cpu1,kenobi-3.local
,,27,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_steal,cpu,cpu1,kenobi-3.local
,,27,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_steal,cpu,cpu1,kenobi-3.local
,,28,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,3.5,usage_system,cpu,cpu1,kenobi-3.local
,,28,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,4,usage_system,cpu,cpu1,kenobi-3.local
,,28,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,4.895104895104895,usage_system,cpu,cpu1,kenobi-3.local
,,28,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,4.504504504504505,usage_system,cpu,cpu1,kenobi-3.local
,,28,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,6.3,usage_system,cpu,cpu1,kenobi-3.local
,,28,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,7.9,usage_system,cpu,cpu1,kenobi-3.local
,,29,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,6.7,usage_user,cpu,cpu1,kenobi-3.local
,,29,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,4.2,usage_user,cpu,cpu1,kenobi-3.local
,,29,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,7.992007992007992,usage_user,cpu,cpu1,kenobi-3.local
,,29,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,6.006006006006006,usage_user,cpu,cpu1,kenobi-3.local
,,29,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,10.7,usage_user,cpu,cpu1,kenobi-3.local
,,29,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,12,usage_user,cpu,cpu1,kenobi-3.local
,,30,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_guest,cpu,cpu2,kenobi-3.local
,,30,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_guest,cpu,cpu2,kenobi-3.local
,,30,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_guest,cpu,cpu2,kenobi-3.local
,,30,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_guest,cpu,cpu2,kenobi-3.local
,,30,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_guest,cpu,cpu2,kenobi-3.local
,,30,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_guest,cpu,cpu2,kenobi-3.local
,,31,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_guest_nice,cpu,cpu2,kenobi-3.local
,,31,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_guest_nice,cpu,cpu2,kenobi-3.local
,,31,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_guest_nice,cpu,cpu2,kenobi-3.local
,,31,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_guest_nice,cpu,cpu2,kenobi-3.local
,,31,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_guest_nice,cpu,cpu2,kenobi-3.local
,,31,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_guest_nice,cpu,cpu2,kenobi-3.local
,,32,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,75.17517517517517,usage_idle,cpu,cpu2,kenobi-3.local
,,32,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,74.82517482517483,usage_idle,cpu,cpu2,kenobi-3.local
,,32,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,67.9,usage_idle,cpu,cpu2,kenobi-3.local
,,32,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,72.47247247247248,usage_idle,cpu,cpu2,kenobi-3.local
,,32,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,61.63836163836164,usage_idle,cpu,cpu2,kenobi-3.local
,,32,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,62,usage_idle,cpu,cpu2,kenobi-3.local
,,33,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_iowait,cpu,cpu2,kenobi-3.local
,,33,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_iowait,cpu,cpu2,kenobi-3.local
,,33,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_iowait,cpu,cpu2,kenobi-3.local
,,33,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_iowait,cpu,cpu2,kenobi-3.local
,,33,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_iowait,cpu,cpu2,kenobi-3.local
,,33,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_iowait,cpu,cpu2,kenobi-3.local
,,34,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_irq,cpu,cpu2,kenobi-3.local
,,34,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_irq,cpu,cpu2,kenobi-3.local
,,34,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_irq,cpu,cpu2,kenobi-3.local
,,34,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_irq,cpu,cpu2,kenobi-3.local
,,34,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_irq,cpu,cpu2,kenobi-3.local
,,34,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_irq,cpu,cpu2,kenobi-3.local
,,35,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_nice,cpu,cpu2,kenobi-3.local
,,35,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_nice,cpu,cpu2,kenobi-3.local
,,35,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_nice,cpu,cpu2,kenobi-3.local
,,35,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_nice,cpu,cpu2,kenobi-3.local
,,35,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_nice,cpu,cpu2,kenobi-3.local
,,35,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_nice,cpu,cpu2,kenobi-3.local
,,36,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_softirq,cpu,cpu2,kenobi-3.local
,,36,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_softirq,cpu,cpu2,kenobi-3.local
,,36,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_softirq,cpu,cpu2,kenobi-3.local
,,36,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_softirq,cpu,cpu2,kenobi-3.local
,,36,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_softirq,cpu,cpu2,kenobi-3.local
,,36,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_softirq,cpu,cpu2,kenobi-3.local
,,37,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_steal,cpu,cpu2,kenobi-3.local
,,37,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_steal,cpu,cpu2,kenobi-3.local
,,37,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_steal,cpu,cpu2,kenobi-3.local
,,37,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_steal,cpu,cpu2,kenobi-3.local
,,37,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_steal,cpu,cpu2,kenobi-3.local
,,37,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_steal,cpu,cpu2,kenobi-3.local
,,38,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,8.208208208208209,usage_system,cpu,cpu2,kenobi-3.local
,,38,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,9.99000999000999,usage_system,cpu,cpu2,kenobi-3.local
,,38,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,11.2,usage_system,cpu,cpu2,kenobi-3.local
,,38,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,10.81081081081081,usage_system,cpu,cpu2,kenobi-3.local
,,38,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,14.785214785214785,usage_system,cpu,cpu2,kenobi-3.local
,,38,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,16.2,usage_system,cpu,cpu2,kenobi-3.local
,,39,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,16.616616616616618,usage_user,cpu,cpu2,kenobi-3.local
,,39,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,15.184815184815184,usage_user,cpu,cpu2,kenobi-3.local
,,39,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,20.9,usage_user,cpu,cpu2,kenobi-3.local
,,39,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,16.716716716716718,usage_user,cpu,cpu2,kenobi-3.local
,,39,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,23.576423576423576,usage_user,cpu,cpu2,kenobi-3.local
,,39,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,21.8,usage_user,cpu,cpu2,kenobi-3.local
,,40,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_guest,cpu,cpu3,kenobi-3.local
,,40,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_guest,cpu,cpu3,kenobi-3.local
,,40,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_guest,cpu,cpu3,kenobi-3.local
,,40,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_guest,cpu,cpu3,kenobi-3.local
,,40,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_guest,cpu,cpu3,kenobi-3.local
,,40,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_guest,cpu,cpu3,kenobi-3.local
,,41,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_guest_nice,cpu,cpu3,kenobi-3.local
,,41,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_guest_nice,cpu,cpu3,kenobi-3.local
,,41,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_guest_nice,cpu,cpu3,kenobi-3.local
,,41,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_guest_nice,cpu,cpu3,kenobi-3.local
,,41,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_guest_nice,cpu,cpu3,kenobi-3.local
,,41,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_guest_nice,cpu,cpu3,kenobi-3.local
,,42,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,89.4,usage_idle,cpu,cpu3,kenobi-3.local
,,42,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,92.5,usage_idle,cpu,cpu3,kenobi-3.local
,,42,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,86.4,usage_idle,cpu,cpu3,kenobi-3.local
,,42,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,88.78878878878879,usage_idle,cpu,cpu3,kenobi-3.local
,,42,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,80.83832335329342,usage_idle,cpu,cpu3,kenobi-3.local
,,42,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,79.57957957957957,usage_idle,cpu,cpu3,kenobi-3.local
,,43,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_iowait,cpu,cpu3,kenobi-3.local
,,43,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_iowait,cpu,cpu3,kenobi-3.local
,,43,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_iowait,cpu,cpu3,kenobi-3.local
,,43,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_iowait,cpu,cpu3,kenobi-3.local
,,43,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_iowait,cpu,cpu3,kenobi-3.local
,,43,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_iowait,cpu,cpu3,kenobi-3.local
,,44,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_irq,cpu,cpu3,kenobi-3.local
,,44,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_irq,cpu,cpu3,kenobi-3.local
,,44,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_irq,cpu,cpu3,kenobi-3.local
,,44,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_irq,cpu,cpu3,kenobi-3.local
,,44,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_irq,cpu,cpu3,kenobi-3.local
,,44,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_irq,cpu,cpu3,kenobi-3.local
,,45,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_nice,cpu,cpu3,kenobi-3.local
,,45,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_nice,cpu,cpu3,kenobi-3.local
,,45,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_nice,cpu,cpu3,kenobi-3.local
,,45,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_nice,cpu,cpu3,kenobi-3.local
,,45,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_nice,cpu,cpu3,kenobi-3.local
,,45,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_nice,cpu,cpu3,kenobi-3.local
,,46,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_softirq,cpu,cpu3,kenobi-3.local
,,46,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_softirq,cpu,cpu3,kenobi-3.local
,,46,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_softirq,cpu,cpu3,kenobi-3.local
,,46,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_softirq,cpu,cpu3,kenobi-3.local
,,46,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_softirq,cpu,cpu3,kenobi-3.local
,,46,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_softirq,cpu,cpu3,kenobi-3.local
,,47,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,0,usage_steal,cpu,cpu3,kenobi-3.local
,,47,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,0,usage_steal,cpu,cpu3,kenobi-3.local
,,47,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,0,usage_steal,cpu,cpu3,kenobi-3.local
,,47,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,0,usage_steal,cpu,cpu3,kenobi-3.local
,,47,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,0,usage_steal,cpu,cpu3,kenobi-3.local
,,47,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,0,usage_steal,cpu,cpu3,kenobi-3.local
,,48,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,3.7,usage_system,cpu,cpu3,kenobi-3.local
,,48,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,3.2,usage_system,cpu,cpu3,kenobi-3.local
,,48,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,4.9,usage_system,cpu,cpu3,kenobi-3.local
,,48,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,4.504504504504505,usage_system,cpu,cpu3,kenobi-3.local
,,48,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,7.584830339321357,usage_system,cpu,cpu3,kenobi-3.local
,,48,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,8.208208208208209,usage_system,cpu,cpu3,kenobi-3.local
,,49,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,6.9,usage_user,cpu,cpu3,kenobi-3.local
,,49,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,4.3,usage_user,cpu,cpu3,kenobi-3.local
,,49,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,8.7,usage_user,cpu,cpu3,kenobi-3.local
,,49,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,6.706706706706707,usage_user,cpu,cpu3,kenobi-3.local
,,49,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,11.57684630738523,usage_user,cpu,cpu3,kenobi-3.local
,,49,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,12.212212212212211,usage_user,cpu,cpu3,kenobi-3.local
#datatype,string,long,dateTime:RFC3339,dateTime:RFC3339,dateTime:RFC3339,long,string,string,string,string,string,string,string
#partition,false,false,true,true,false,false,true,true,true,true,true,true,true
#default,_result,,,,,,,,,,,,
,result,table,_start,_stop,_time,_value,_field,_measurement,device,fstype,host,mode,path
,,50,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,9024180224,free,disk,disk1,hfs,kenobi-3.local,rw,/
,,50,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,9025056768,free,disk,disk1,hfs,kenobi-3.local,rw,/
,,50,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,9024774144,free,disk,disk1,hfs,kenobi-3.local,rw,/
,,50,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,9024638976,free,disk,disk1,hfs,kenobi-3.local,rw,/
,,50,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,9024299008,free,disk,disk1,hfs,kenobi-3.local,rw,/
,,50,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,9024036864,free,disk,disk1,hfs,kenobi-3.local,rw,/
,,51,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,4290025660,inodes_free,disk,disk1,hfs,kenobi-3.local,rw,/
,,51,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,4290025659,inodes_free,disk,disk1,hfs,kenobi-3.local,rw,/
,,51,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,4290025659,inodes_free,disk,disk1,hfs,kenobi-3.local,rw,/
,,51,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,4290025660,inodes_free,disk,disk1,hfs,kenobi-3.local,rw,/
,,51,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,4290025660,inodes_free,disk,disk1,hfs,kenobi-3.local,rw,/
,,51,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,4290025657,inodes_free,disk,disk1,hfs,kenobi-3.local,rw,/
,,52,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,4294967279,inodes_total,disk,disk1,hfs,kenobi-3.local,rw,/
,,52,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,4294967279,inodes_total,disk,disk1,hfs,kenobi-3.local,rw,/
,,52,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,4294967279,inodes_total,disk,disk1,hfs,kenobi-3.local,rw,/
,,52,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,4294967279,inodes_total,disk,disk1,hfs,kenobi-3.local,rw,/
,,52,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,4294967279,inodes_total,disk,disk1,hfs,kenobi-3.local,rw,/
,,52,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,4294967279,inodes_total,disk,disk1,hfs,kenobi-3.local,rw,/
,,53,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,4941619,inodes_used,disk,disk1,hfs,kenobi-3.local,rw,/
,,53,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,4941620,inodes_used,disk,disk1,hfs,kenobi-3.local,rw,/
,,53,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,4941620,inodes_used,disk,disk1,hfs,kenobi-3.local,rw,/
,,53,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,4941619,inodes_used,disk,disk1,hfs,kenobi-3.local,rw,/
,,53,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,4941619,inodes_used,disk,disk1,hfs,kenobi-3.local,rw,/
,,53,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,4941622,inodes_used,disk,disk1,hfs,kenobi-3.local,rw,/
,,54,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,249804886016,total,disk,disk1,hfs,kenobi-3.local,rw,/
,,54,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,249804886016,total,disk,disk1,hfs,kenobi-3.local,rw,/
,,54,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,249804886016,total,disk,disk1,hfs,kenobi-3.local,rw,/
,,54,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,249804886016,total,disk,disk1,hfs,kenobi-3.local,rw,/
,,54,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,249804886016,total,disk,disk1,hfs,kenobi-3.local,rw,/
,,54,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,249804886016,total,disk,disk1,hfs,kenobi-3.local,rw,/
,,55,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:23Z,240518561792,used,disk,disk1,hfs,kenobi-3.local,rw,/
,,55,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:33Z,240517685248,used,disk,disk1,hfs,kenobi-3.local,rw,/
,,55,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:43Z,240517967872,used,disk,disk1,hfs,kenobi-3.local,rw,/
,,55,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:54:53Z,240518103040,used,disk,disk1,hfs,kenobi-3.local,rw,/
,,55,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:03Z,240518443008,used,disk,disk1,hfs,kenobi-3.local,rw,/
,,55,2018-06-01T12:54:13.516195939Z,2018-06-01T12:55:13.516195939Z,2018-06-01T12:55:13Z,240518705152,used,disk,disk1,hfs,kenobi-3.local,rw,/
`;
export default result;
@@ -23,10 +23,11 @@
</div>
<div class="gf-form">
<folder-picker root-name="All"
initial-folder-id="ctrl.panel.folderId"
<folder-picker initial-folder-id="ctrl.panel.folderId"
on-change="ctrl.onFolderChange($folder)"
label-class="width-6">
label-class="width-6"
initial-title="'All'"
enable-reset="true">
</folder-picker>
</div>
+3 -2
View File
@@ -17,7 +17,7 @@ class DashListCtrl extends PanelCtrl {
search: false,
starred: true,
headings: true,
folderId: 0,
folderId: null,
};
/** @ngInject */
@@ -85,7 +85,8 @@ class DashListCtrl extends PanelCtrl {
limit: this.panel.limit,
query: this.panel.query,
tag: this.panel.tags,
folderId: this.panel.folderId,
folderIds: this.panel.folderId,
type: 'dash-db',
};
return this.backendSrv.search(params).then(result => {
+18 -2
View File
@@ -6,6 +6,7 @@ import coreModule from 'app/core/core_module';
import { store } from 'app/stores/store';
import { BackendSrv } from 'app/core/services/backend_srv';
import { DatasourceSrv } from 'app/features/plugins/datasource_srv';
import { ContextSrv } from 'app/core/services/context_srv';
function WrapInProvider(store, Component, props) {
return (
@@ -16,16 +17,31 @@ function WrapInProvider(store, Component, props) {
}
/** @ngInject */
export function reactContainer($route, $location, backendSrv: BackendSrv, datasourceSrv: DatasourceSrv) {
export function reactContainer(
$route,
$location,
backendSrv: BackendSrv,
datasourceSrv: DatasourceSrv,
contextSrv: ContextSrv
) {
return {
restrict: 'E',
template: '',
link(scope, elem) {
let component = $route.current.locals.component;
// Check permissions for this component
const { roles } = $route.current.locals;
if (roles && roles.length) {
if (!roles.some(r => contextSrv.hasRole(r))) {
$location.url('/');
}
}
let { component } = $route.current.locals;
// Dynamic imports return whole module, need to extract default export
if (component.default) {
component = component.default;
}
const props = {
backendSrv: backendSrv,
datasourceSrv: datasourceSrv,
+1
View File
@@ -113,6 +113,7 @@ export function setupAngularRoutes($routeProvider, $locationProvider) {
.when('/explore/:initial?', {
template: '<react-container />',
resolve: {
roles: () => ['Editor', 'Admin'],
component: () => import(/* webpackChunkName: "explore" */ 'app/containers/Explore/Wrapper'),
},
})
+4
View File
@@ -384,6 +384,10 @@ $input-border: 1px solid $input-border-color;
&--header {
margin-bottom: $gf-form-margin;
}
&--no-padding {
padding-left: 0;
}
}
select.gf-form-input ~ .gf-form-help-icon {
@@ -7,14 +7,13 @@
.singlestat-panel-value-container {
line-height: 1;
position: absolute;
display: table-cell;
vertical-align: middle;
text-align: center;
position: relative;
z-index: 1;
font-size: 3em;
font-weight: bold;
margin: 0;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-weight: $font-weight-semi-bold;
}
.singlestat-panel-prefix {
+38
View File
@@ -59,6 +59,14 @@ select:-webkit-autofill:focus {
justify-content: space-between;
width: 100%;
margin-top: 0.5rem;
&--right {
justify-content: flex-end;
& .btn {
margin-left: 1rem;
}
}
}
.login-button-forgot-password {
@@ -75,7 +83,9 @@ select:-webkit-autofill:focus {
align-items: stretch;
flex-direction: column;
position: relative;
justify-content: center;
z-index: 1;
height: 320px;
}
.login-branding {
@@ -100,6 +110,11 @@ select:-webkit-autofill:focus {
}
}
.login-outer-box {
display: flex;
overflow-y: hidden;
}
.login-inner-box {
text-align: center;
padding: 2rem 4rem;
@@ -109,6 +124,22 @@ select:-webkit-autofill:focus {
justify-content: center;
flex-grow: 1;
max-width: 415px;
transform: tranlate(0px, 0px);
transition: 0.25s ease;
&.add {
transform: translate(0px, -320px);
&.hidden {
display: none;
}
}
&.remove {
transform: translate(0px, 320px);
&.hidden {
display: none;
}
}
}
.login-tab-header {
@@ -117,6 +148,13 @@ select:-webkit-autofill:focus {
margin-bottom: 3rem;
}
.login-change-password-info {
padding-bottom: 1.5rem;
& h5 {
text-align: left;
}
}
.btn-signup {
color: $white;
border: 1px solid $login-border;
+2
View File
@@ -11,6 +11,7 @@ export function ControllerTestContext() {
this.$element = {};
this.$sanitize = {};
this.annotationsSrv = {};
this.contextSrv = {};
this.timeSrv = new TimeSrvStub();
this.templateSrv = new TemplateSrvStub();
this.datasourceSrv = {
@@ -27,6 +28,7 @@ export function ControllerTestContext() {
this.providePhase = function(mocks) {
return angularMocks.module(function($provide) {
$provide.value('contextSrv', self.contextSrv);
$provide.value('datasourceSrv', self.datasourceSrv);
$provide.value('annotationsSrv', self.annotationsSrv);
$provide.value('timeSrv', self.timeSrv);
+4
View File
@@ -7928,6 +7928,10 @@ pako@~1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
papaparse@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-4.4.0.tgz#6bcdbda80873e00cfb0bdcd7a4571c72a9a40168"
parallel-transform@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06"