mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge remote-tracking branch 'upstream/master' into postgres-query-builder
This commit is contained in:
@@ -183,16 +183,21 @@ jobs:
|
||||
command: 'sudo pip install awscli'
|
||||
- run:
|
||||
name: deploy to s3
|
||||
command: 'aws s3 sync ./dist s3://$BUCKET_NAME/master'
|
||||
command: |
|
||||
# Also
|
||||
cp dist/grafana-latest.linux-x64.tar.gz dist/grafana-master-$(echo "${CIRCLE_SHA1}" | cut -b1-7).linux-x64.tar.gz
|
||||
aws s3 sync ./dist s3://$BUCKET_NAME/master
|
||||
- run:
|
||||
name: Trigger Windows build
|
||||
command: './scripts/trigger_windows_build.sh ${APPVEYOR_TOKEN} ${CIRCLE_SHA1} master'
|
||||
- run:
|
||||
name: Trigger Docker build
|
||||
command: './scripts/trigger_docker_build.sh ${TRIGGER_GRAFANA_PACKER_CIRCLECI_TOKEN}'
|
||||
command: './scripts/trigger_docker_build.sh ${TRIGGER_GRAFANA_PACKER_CIRCLECI_TOKEN} master-$(echo "${CIRCLE_SHA1}" | cut -b1-7)'
|
||||
- run:
|
||||
name: Publish to Grafana.com
|
||||
command: './scripts/publish -apiKey ${GRAFANA_COM_API_KEY}'
|
||||
command: |
|
||||
rm dist/grafana-master-$(echo "${CIRCLE_SHA1}" | cut -b1-7).linux-x64.tar.gz
|
||||
./scripts/publish -apiKey ${GRAFANA_COM_API_KEY}
|
||||
|
||||
deploy-release:
|
||||
docker:
|
||||
@@ -241,8 +246,8 @@ workflows:
|
||||
- mysql-integration-test
|
||||
- postgres-integration-test
|
||||
filters:
|
||||
branches:
|
||||
only: master
|
||||
branches:
|
||||
only: master
|
||||
release:
|
||||
jobs:
|
||||
- build-all:
|
||||
|
||||
14
CHANGELOG.md
14
CHANGELOG.md
@@ -1,5 +1,19 @@
|
||||
# 5.2.0 (unreleased)
|
||||
|
||||
### New Features
|
||||
|
||||
* **Dashboard**: Import dashboard to folder [#10796](https://github.com/grafana/grafana/issues/10796)
|
||||
|
||||
### Minor
|
||||
|
||||
* **Dashboard**: Fix so panel titles doesn't wrap [#11074](https://github.com/grafana/grafana/issues/11074)
|
||||
* **Dashboard**: Prevent double-click when saving dashboard [#11963](https://github.com/grafana/grafana/issues/11963)
|
||||
* **Dashboard**: AutoFocus the add-panel search filter [#12189](https://github.com/grafana/grafana/pull/12189) thx [@ryantxu](https://github.com/ryantxu)
|
||||
* **Units**: W/m2 (energy), l/h (flow) and kPa (pressure) [#11233](https://github.com/grafana/grafana/pull/11233), thx [@flopp999](https://github.com/flopp999)
|
||||
* **Units**: Litre/min (flow) and milliLitre/min (flow) [#12282](https://github.com/grafana/grafana/pull/12282), thx [@flopp999](https://github.com/flopp999)
|
||||
* **Alerting**: Fix mobile notifications for Microsoft Teams alert notifier [#11484](https://github.com/grafana/grafana/pull/11484), thx [@manacker](https://github.com/manacker)
|
||||
* **Influxdb**: Add support for mode function [#12286](https://github.com/grafana/grafana/issues/12286)
|
||||
|
||||
# 5.2.0-beta1 (2018-06-05)
|
||||
|
||||
### New Features
|
||||
|
||||
6
Gopkg.lock
generated
6
Gopkg.lock
generated
@@ -331,8 +331,8 @@
|
||||
[[projects]]
|
||||
name = "github.com/mattn/go-sqlite3"
|
||||
packages = ["."]
|
||||
revision = "6c771bb9887719704b210e87e934f08be014bdb1"
|
||||
version = "v1.6.0"
|
||||
revision = "323a32be5a2421b8c7087225079c6c900ec397cd"
|
||||
version = "v1.7.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/matttproud/golang_protobuf_extensions"
|
||||
@@ -670,6 +670,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "08b97771990365d506af4788acb33cdf283ce89856669262ecb84860ad45bfcb"
|
||||
inputs-digest = "85cc057e0cc074ab5b43bd620772d63d51e07b04e8782fcfe55e6929d2fc40f7"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
||||
@@ -129,7 +129,7 @@ ignored = [
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/mattn/go-sqlite3"
|
||||
version = "1.6.0"
|
||||
version = "1.7.0"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/opentracing/opentracing-go"
|
||||
|
||||
@@ -76,7 +76,7 @@ Saltstack | [https://github.com/salt-formulas/salt-formula-grafana](https://gith
|
||||
|
||||
> This feature is available from v5.0
|
||||
|
||||
It's possible to manage datasources in Grafana by adding one or more yaml config files in the [`provisioning/datasources`](/installation/configuration/#provisioning) directory. Each config file can contain a list of `datasources` that will be added or updated during start up. If the datasource already exists, Grafana will update it to match the configuration file. The config file can also contain a list of datasources that should be deleted. That list is called `delete_datasources`. Grafana will delete datasources listed in `delete_datasources` before inserting/updating those in the `datasource` list.
|
||||
It's possible to manage datasources in Grafana by adding one or more yaml config files in the [`provisioning/datasources`](/installation/configuration/#provisioning) directory. Each config file can contain a list of `datasources` that will be added or updated during start up. If the datasource already exists, Grafana will update it to match the configuration file. The config file can also contain a list of datasources that should be deleted. That list is called `deleteDatasources`. Grafana will delete datasources listed in `deleteDatasources` before inserting/updating those in the `datasource` list.
|
||||
|
||||
### Running Multiple Grafana Instances
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ queries through the use of query references.
|
||||
## Adding the data source
|
||||
|
||||
1. Open the side menu by clicking the Grafana icon in the top header.
|
||||
2. In the side menu under the `Dashboards` link you should find a link named `Data Sources`.
|
||||
2. In the side menu under the `Configuration` link you should find a link named `Data Sources`.
|
||||
3. Click the `+ Add data source` button in the top header.
|
||||
4. Select `Graphite` from the *Type* dropdown.
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ Grafana v5.1 brings an improved workflow for provisioned dashboards:
|
||||
|
||||
|
||||
Available options in the dialog will let you `Copy JSON to Clipboard` and/or `Save JSON to file` which can help you synchronize your dashboard changes back to the provisioning source.
|
||||
More information in the [Provisioning documentation](/features/datasources/prometheus/).
|
||||
More information in the [Provisioning documentation](/administration/provisioning/).
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
|
||||
@@ -331,6 +331,27 @@ Content-Type: application/json
|
||||
|
||||
```
|
||||
|
||||
## Update Users in Organisation
|
||||
|
||||
`PATCH /api/orgs/:orgId/users/:userId`
|
||||
|
||||
**Example Request**:
|
||||
|
||||
```http
|
||||
PATCH /api/orgs/1/users/2 HTTP/1.1
|
||||
Accept: application/json
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
|
||||
```
|
||||
|
||||
**Example Response**:
|
||||
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
|
||||
```
|
||||
|
||||
## Delete User in Organisation
|
||||
|
||||
|
||||
@@ -49,6 +49,11 @@ $ docker run \
|
||||
grafana/grafana:5.1.0
|
||||
```
|
||||
|
||||
## Running of the master branch
|
||||
|
||||
For every successful commit we publish a Grafana container to [`grafana/grafana`](https://hub.docker.com/r/grafana/grafana/tags/) and [`grafana/grafana-dev`](https://hub.docker.com/r/grafana/grafana-dev/tags/). In `grafana/grafana` container we will always overwrite the `master` tag with the latest version. In `grafana/grafana-dev` we will include
|
||||
the git commit in the tag. If you run Grafana master in production we **strongly** recommend that you use the later since different machines might run different version of grafana if they pull the master tag at different times.
|
||||
|
||||
## Installing Plugins for Grafana
|
||||
|
||||
Pass the plugins you want installed to docker with the `GF_INSTALL_PLUGINS` environment variable as a comma separated list. This will pass each plugin name to `grafana-cli plugins install ${plugin}` and install them when Grafana starts.
|
||||
|
||||
@@ -25,7 +25,6 @@ To interact with the rest of grafana the plugins module file can export 5 differ
|
||||
- Datasource (Required)
|
||||
- QueryCtrl (Required)
|
||||
- ConfigCtrl (Required)
|
||||
- QueryOptionsCtrl
|
||||
- AnnotationsQueryCtrl
|
||||
|
||||
## Plugin json
|
||||
@@ -182,12 +181,6 @@ A JavaScript class that will be instantiated and treated as an Angular controlle
|
||||
|
||||
Requires a static template or templateUrl variable which will be rendered as the view for this controller.
|
||||
|
||||
## QueryOptionsCtrl
|
||||
|
||||
A JavaScript class that will be instantiated and treated as an Angular controller when the user edits metrics in a panel. This controller is responsible for handling panel wide settings for the datasource, such as interval, rate and aggregations if needed.
|
||||
|
||||
Requires a static template or templateUrl variable which will be rendered as the view for this controller.
|
||||
|
||||
## AnnotationsQueryCtrl
|
||||
|
||||
A JavaScript class that will be instantiated and treated as an Angular controller when the user choose this type of datasource in the templating menu in the dashboard.
|
||||
|
||||
@@ -13,7 +13,7 @@ dev environment. Grafana ships with its own required backend server; also comple
|
||||
|
||||
## Dependencies
|
||||
|
||||
- [Go 1.9.2](https://golang.org/dl/)
|
||||
- [Go 1.10](https://golang.org/dl/)
|
||||
- [Git](https://git-scm.com/downloads)
|
||||
- [NodeJS LTS](https://nodejs.org/download/)
|
||||
- node-gyp is the Node.js native addon build tool and it requires extra dependencies: python 2.7, make and GCC. These are already installed for most Linux distros and MacOS. See the Building On Windows section or the [node-gyp installation instructions](https://github.com/nodejs/node-gyp#installation) for more details.
|
||||
@@ -66,13 +66,13 @@ You can run a local instance of Grafana by running:
|
||||
```bash
|
||||
./bin/grafana-server
|
||||
```
|
||||
If you built the binary with `go run build.go build`, run `./bin/grafana-server`
|
||||
Or, if you built the binary with `go run build.go build`, run `./bin/<os>-<architecture>/grafana-server`
|
||||
|
||||
If you built it with `go build .`, run `./grafana`
|
||||
|
||||
Open grafana in your browser (default [http://localhost:3000](http://localhost:3000)) and login with admin user (default user/pass = admin/admin).
|
||||
|
||||
## Developing Grafana
|
||||
# Developing Grafana
|
||||
|
||||
To add features, customize your config, etc, you'll need to rebuild the backend when you change the source code. We use a tool named `bra` that
|
||||
does this.
|
||||
@@ -124,7 +124,7 @@ Learn more about Grafana config options in the [Configuration section](/installa
|
||||
## Create a pull requests
|
||||
Please contribute to the Grafana project and submit a pull request! Build new features, write or update documentation, fix bugs and generally make Grafana even more awesome.
|
||||
|
||||
## Troubleshooting
|
||||
# Troubleshooting
|
||||
|
||||
**Problem**: PhantomJS or node-sass errors when running grunt
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"stable": "5.0.4",
|
||||
"testing": "5.0.4"
|
||||
"stable": "5.1.3",
|
||||
"testing": "5.1.3"
|
||||
}
|
||||
|
||||
@@ -157,7 +157,6 @@
|
||||
"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",
|
||||
|
||||
@@ -57,4 +57,5 @@ type ImportDashboardCommand struct {
|
||||
Overwrite bool `json:"overwrite"`
|
||||
Dashboard *simplejson.Json `json:"dashboard"`
|
||||
Inputs []plugins.ImportDashboardInput `json:"inputs"`
|
||||
FolderId int64 `json:"folderId"`
|
||||
}
|
||||
|
||||
@@ -85,13 +85,6 @@ 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 {
|
||||
@@ -102,10 +95,6 @@ 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
|
||||
@@ -151,6 +140,7 @@ func getFrontendSettingsMap(c *m.ReqContext) (map[string]interface{}, error) {
|
||||
"authProxyEnabled": setting.AuthProxyEnabled,
|
||||
"ldapEnabled": setting.LdapEnabled,
|
||||
"alertingEnabled": setting.AlertingEnabled,
|
||||
"exploreEnabled": setting.ExploreEnabled,
|
||||
"googleAnalyticsId": setting.GoogleAnalyticsId,
|
||||
"disableLoginForm": setting.DisableLoginForm,
|
||||
"externalUserMngInfo": setting.ExternalUserMngInfo,
|
||||
|
||||
@@ -99,9 +99,10 @@ func setIndexViewData(c *m.ReqContext) (*dtos.IndexViewData, error) {
|
||||
|
||||
if c.OrgRole == m.ROLE_ADMIN || c.OrgRole == m.ROLE_EDITOR {
|
||||
children = append(children, &dtos.NavLink{Text: "Folder", SubTitle: "Create a new folder to organize your dashboards", Id: "folder", Icon: "gicon gicon-folder-new", Url: setting.AppSubUrl + "/dashboards/folder/new"})
|
||||
children = append(children, &dtos.NavLink{Text: "Import", SubTitle: "Import dashboard from file or Grafana.com", Id: "import", Icon: "gicon gicon-dashboard-import", Url: setting.AppSubUrl + "/dashboard/import"})
|
||||
}
|
||||
|
||||
children = append(children, &dtos.NavLink{Text: "Import", SubTitle: "Import dashboard from file or Grafana.com", Id: "import", Icon: "gicon gicon-dashboard-import", Url: setting.AppSubUrl + "/dashboard/import"})
|
||||
|
||||
data.NavTree = append(data.NavTree, &dtos.NavLink{
|
||||
Text: "Create",
|
||||
Id: "create",
|
||||
|
||||
@@ -25,12 +25,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
logger = log.New("data-proxy-log")
|
||||
client = &http.Client{
|
||||
Timeout: time.Second * 30,
|
||||
Transport: &http.Transport{Proxy: http.ProxyFromEnvironment},
|
||||
}
|
||||
tokenCache = map[int64]*jwtToken{}
|
||||
logger = log.New("data-proxy-log")
|
||||
tokenCache = map[string]*jwtToken{}
|
||||
client = newHTTPClient()
|
||||
)
|
||||
|
||||
type jwtToken struct {
|
||||
@@ -48,6 +45,10 @@ type DataSourceProxy struct {
|
||||
plugin *plugins.DataSourcePlugin
|
||||
}
|
||||
|
||||
type httpClient interface {
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
}
|
||||
|
||||
func NewDataSourceProxy(ds *m.DataSource, plugin *plugins.DataSourcePlugin, ctx *m.ReqContext, proxyPath string) *DataSourceProxy {
|
||||
targetURL, _ := url.Parse(ds.Url)
|
||||
|
||||
@@ -60,6 +61,13 @@ func NewDataSourceProxy(ds *m.DataSource, plugin *plugins.DataSourcePlugin, ctx
|
||||
}
|
||||
}
|
||||
|
||||
func newHTTPClient() httpClient {
|
||||
return &http.Client{
|
||||
Timeout: time.Second * 30,
|
||||
Transport: &http.Transport{Proxy: http.ProxyFromEnvironment},
|
||||
}
|
||||
}
|
||||
|
||||
func (proxy *DataSourceProxy) HandleRequest() {
|
||||
if err := proxy.validateRequest(); err != nil {
|
||||
proxy.ctx.JsonApiErr(403, err.Error(), nil)
|
||||
@@ -311,7 +319,7 @@ func (proxy *DataSourceProxy) applyRoute(req *http.Request) {
|
||||
}
|
||||
|
||||
func (proxy *DataSourceProxy) getAccessToken(data templateData) (string, error) {
|
||||
if cachedToken, found := tokenCache[proxy.ds.Id]; found {
|
||||
if cachedToken, found := tokenCache[proxy.getAccessTokenCacheKey()]; found {
|
||||
if cachedToken.ExpiresOn.After(time.Now().Add(time.Second * 10)) {
|
||||
logger.Info("Using token from cache")
|
||||
return cachedToken.AccessToken, nil
|
||||
@@ -350,12 +358,16 @@ func (proxy *DataSourceProxy) getAccessToken(data templateData) (string, error)
|
||||
|
||||
expiresOnEpoch, _ := strconv.ParseInt(token.ExpiresOnString, 10, 64)
|
||||
token.ExpiresOn = time.Unix(expiresOnEpoch, 0)
|
||||
tokenCache[proxy.ds.Id] = &token
|
||||
tokenCache[proxy.getAccessTokenCacheKey()] = &token
|
||||
|
||||
logger.Info("Got new access token", "ExpiresOn", token.ExpiresOn)
|
||||
return token.AccessToken, nil
|
||||
}
|
||||
|
||||
func (proxy *DataSourceProxy) getAccessTokenCacheKey() string {
|
||||
return fmt.Sprintf("%v_%v_%v", proxy.ds.Id, proxy.route.Path, proxy.route.Method)
|
||||
}
|
||||
|
||||
func interpolateString(text string, data templateData) (string, error) {
|
||||
t, err := template.New("content").Parse(text)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
package pluginproxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
macaron "gopkg.in/macaron.v1"
|
||||
|
||||
@@ -100,6 +104,112 @@ func TestDSRouteRule(t *testing.T) {
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Plugin with multiple routes for token auth", func() {
|
||||
plugin := &plugins.DataSourcePlugin{
|
||||
Routes: []*plugins.AppPluginRoute{
|
||||
{
|
||||
Path: "pathwithtoken1",
|
||||
Url: "https://api.nr1.io/some/path",
|
||||
TokenAuth: &plugins.JwtTokenAuth{
|
||||
Url: "https://login.server.com/{{.JsonData.tenantId}}/oauth2/token",
|
||||
Params: map[string]string{
|
||||
"grant_type": "client_credentials",
|
||||
"client_id": "{{.JsonData.clientId}}",
|
||||
"client_secret": "{{.SecureJsonData.clientSecret}}",
|
||||
"resource": "https://api.nr1.io",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Path: "pathwithtoken2",
|
||||
Url: "https://api.nr2.io/some/path",
|
||||
TokenAuth: &plugins.JwtTokenAuth{
|
||||
Url: "https://login.server.com/{{.JsonData.tenantId}}/oauth2/token",
|
||||
Params: map[string]string{
|
||||
"grant_type": "client_credentials",
|
||||
"client_id": "{{.JsonData.clientId}}",
|
||||
"client_secret": "{{.SecureJsonData.clientSecret}}",
|
||||
"resource": "https://api.nr2.io",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
setting.SecretKey = "password"
|
||||
key, _ := util.Encrypt([]byte("123"), "password")
|
||||
|
||||
ds := &m.DataSource{
|
||||
JsonData: simplejson.NewFromAny(map[string]interface{}{
|
||||
"clientId": "asd",
|
||||
"tenantId": "mytenantId",
|
||||
}),
|
||||
SecureJsonData: map[string][]byte{
|
||||
"clientSecret": key,
|
||||
},
|
||||
}
|
||||
|
||||
req, _ := http.NewRequest("GET", "http://localhost/asd", nil)
|
||||
ctx := &m.ReqContext{
|
||||
Context: &macaron.Context{
|
||||
Req: macaron.Request{Request: req},
|
||||
},
|
||||
SignedInUser: &m.SignedInUser{OrgRole: m.ROLE_EDITOR},
|
||||
}
|
||||
|
||||
Convey("When creating and caching access tokens", func() {
|
||||
var authorizationHeaderCall1 string
|
||||
var authorizationHeaderCall2 string
|
||||
|
||||
Convey("first call should add authorization header with access token", func() {
|
||||
json, err := ioutil.ReadFile("./test-data/access-token-1.json")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
client = newFakeHTTPClient(json)
|
||||
proxy1 := NewDataSourceProxy(ds, plugin, ctx, "pathwithtoken1")
|
||||
proxy1.route = plugin.Routes[0]
|
||||
proxy1.applyRoute(req)
|
||||
|
||||
authorizationHeaderCall1 = req.Header.Get("Authorization")
|
||||
So(req.URL.String(), ShouldEqual, "https://api.nr1.io/some/path")
|
||||
So(authorizationHeaderCall1, ShouldStartWith, "Bearer eyJ0e")
|
||||
|
||||
Convey("second call to another route should add a different access token", func() {
|
||||
json2, err := ioutil.ReadFile("./test-data/access-token-2.json")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
req, _ := http.NewRequest("GET", "http://localhost/asd", nil)
|
||||
client = newFakeHTTPClient(json2)
|
||||
proxy2 := NewDataSourceProxy(ds, plugin, ctx, "pathwithtoken2")
|
||||
proxy2.route = plugin.Routes[1]
|
||||
proxy2.applyRoute(req)
|
||||
|
||||
authorizationHeaderCall2 = req.Header.Get("Authorization")
|
||||
|
||||
So(req.URL.String(), ShouldEqual, "https://api.nr2.io/some/path")
|
||||
So(authorizationHeaderCall1, ShouldStartWith, "Bearer eyJ0e")
|
||||
So(authorizationHeaderCall2, ShouldStartWith, "Bearer eyJ0e")
|
||||
So(authorizationHeaderCall2, ShouldNotEqual, authorizationHeaderCall1)
|
||||
|
||||
Convey("third call to first route should add cached access token", func() {
|
||||
req, _ := http.NewRequest("GET", "http://localhost/asd", nil)
|
||||
|
||||
client = newFakeHTTPClient([]byte{})
|
||||
proxy3 := NewDataSourceProxy(ds, plugin, ctx, "pathwithtoken1")
|
||||
proxy3.route = plugin.Routes[0]
|
||||
proxy3.applyRoute(req)
|
||||
|
||||
authorizationHeaderCall3 := req.Header.Get("Authorization")
|
||||
So(req.URL.String(), ShouldEqual, "https://api.nr1.io/some/path")
|
||||
So(authorizationHeaderCall1, ShouldStartWith, "Bearer eyJ0e")
|
||||
So(authorizationHeaderCall3, ShouldStartWith, "Bearer eyJ0e")
|
||||
So(authorizationHeaderCall3, ShouldEqual, authorizationHeaderCall1)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Convey("When proxying graphite", func() {
|
||||
plugin := &plugins.DataSourcePlugin{}
|
||||
ds := &m.DataSource{Url: "htttp://graphite:8080", Type: m.DS_GRAPHITE}
|
||||
@@ -214,3 +324,27 @@ func TestDSRouteRule(t *testing.T) {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
type httpClientStub struct {
|
||||
fakeBody []byte
|
||||
}
|
||||
|
||||
func (c *httpClientStub) Do(req *http.Request) (*http.Response, error) {
|
||||
bodyJSON, _ := simplejson.NewJson(c.fakeBody)
|
||||
_, passedTokenCacheTest := bodyJSON.CheckGet("expires_on")
|
||||
So(passedTokenCacheTest, ShouldBeTrue)
|
||||
|
||||
bodyJSON.Set("expires_on", fmt.Sprint(time.Now().Add(time.Second*60).Unix()))
|
||||
body, _ := bodyJSON.MarshalJSON()
|
||||
resp := &http.Response{
|
||||
Body: ioutil.NopCloser(bytes.NewReader(body)),
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func newFakeHTTPClient(fakeBody []byte) httpClient {
|
||||
return &httpClientStub{
|
||||
fakeBody: fakeBody,
|
||||
}
|
||||
}
|
||||
|
||||
9
pkg/api/pluginproxy/test-data/access-token-1.json
Normal file
9
pkg/api/pluginproxy/test-data/access-token-1.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"token_type": "Bearer",
|
||||
"expires_in": "3599",
|
||||
"ext_expires_in": "0",
|
||||
"expires_on": "1528740417",
|
||||
"not_before": "1528736517",
|
||||
"resource": "https://api.nr1.io",
|
||||
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImlCakwxUmNxemhpeTRmcHhJeGRacW9oTTJZayIsImtpZCI6ImlCakwxUmNxemhpeTRmcHhJeGRacW9oTTJZayJ9.eyJhdWQiOiJodHRwczovL2FwaS5sb2dhbmFseXRpY3MuaW8iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9lN2YzZjY2MS1hOTMzLTRiM2YtODE3Ni01MWM0Zjk4MmVjNDgvIiwiaWF0IjoxNTI4NzM2NTE3LCJuYmYiOjE1Mjg3MzY1MTcsImV4cCI6MTUyODc0MDQxNywiYWlvIjoiWTJkZ1lBaStzaWRsT3NmQ2JicGhLMSsremttN0NBQT0iLCJhcHBpZCI6IjdmMzJkYjdjLTZmNmYtNGU4OC05M2Q5LTlhZTEyNmMwYTU1ZiIsImFwcGlkYWNyIjoiMSIsImlkcCI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0L2U3ZjNmNjYxLWE5MzMtNGIzZi04MTc2LTUxYzRmOTgyZWM0OC8iLCJvaWQiOiI1NDQ5ZmJjOS1mYWJhLTRkNjItODE2Yy05ZmMwMzZkMWViN2UiLCJzdWIiOiI1NDQ5ZmJjOS1mYWJhLTRkNjItODE2Yy05ZmMwMzZkMWViN2UiLCJ0aWQiOiJlN2YzZjY2MS1hOTMzLTRiM2YtODE3Ni01MWM0Zjk4MmVjNDgiLCJ1dGkiOiJZQTlQa2lxUy1VV1hMQjhIRnU0U0FBIiwidmVyIjoiMS4wIn0.ga5qudt4LDMKTStAxUmzjyZH8UFBAaFirJqpTdmYny4NtkH6JT2EILvjTjYxlKeTQisvwx9gof0PyicZIab9d6wlMa2xiLzr2nmaOonYClY8fqBaRTgc1xVjrKFw5SCgpx3FnEyJhIWvVPIfaWaogSHcQbIpe4kdk4tz-ccmrx0D1jsziSI4BZcJcX04aJuHZGz9k4mQZ_AA5sQSeQaNuojIng6rYoIifAXFYBZPTbeeeqmiGq8v0IOLeNKbC0POeQCJC_KKBG6Z_MV2KgPxFEzQuX2ZFmRD_wGPteV5TUBxh1kARdqexA3e0zAKSawR9kmrAiZ21lPr4tX2Br_HDg"
|
||||
}
|
||||
9
pkg/api/pluginproxy/test-data/access-token-2.json
Normal file
9
pkg/api/pluginproxy/test-data/access-token-2.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"token_type": "Bearer",
|
||||
"expires_in": "3599",
|
||||
"ext_expires_in": "0",
|
||||
"expires_on": "1528662059",
|
||||
"not_before": "1528658159",
|
||||
"resource": "https://api.nr2.io",
|
||||
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6ImlCakwxUmNxemhpeTRmcHhJeGRacW9oTTJZayIsImtpZCI6ImlCakwxUmNxemhpeTRmcHhJeGRacW9oTTJZayJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuYXp1cmUuY29tLyIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0L2U3ZjNmNjYxLWE5MzMtNGIzZi04MTc2LTUxYzRmOTgyZWM0OC8iLCJpYXQiOjE1Mjg2NTgxNTksIm5iZiI6MTUyODY1ODE1OSwiZXhwIjoxNTI4NjYyMDU5LCJhaW8iOiJZMmRnWUFpK3NpZGxPc2ZDYmJwaEsxKyt6a203Q0FBPSIsImFwcGlkIjoiODg5YjdlZDgtMWFlZC00ODZlLTk3ODktODE5NzcwYmJiNjFhIiwiYXBwaWRhY3IiOiIxIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvZTdmM2Y2NjEtYTkzMy00YjNmLTgxNzYtNTFjNGY5ODJlYzQ4LyIsIm9pZCI6IjY0YzQxNjMyLTliOWUtNDczNy05MTYwLTBlNjAzZTg3NjljYyIsInN1YiI6IjY0YzQxNjMyLTliOWUtNDczNy05MTYwLTBlNjAzZTg3NjljYyIsInRpZCI6ImU3ZjNmNjYxLWE5MzMtNGIzZi04MTc2LTUxYzRmOTgyZWM0OCIsInV0aSI6IkQ1ODZHSGUySDBPd0ptOU0xeVlKQUEiLCJ2ZXIiOiIxLjAifQ.Pw8c8gpoZptw3lGreQoHQaMVOozSaTE5D38Vm2aCHRB3DvD3N-Qcm1x0ZCakUEV2sJd7jvx4XtPFuW7063T0V1deExL4rzzvIo0ZfMmURf9tCTiKFKYibqf8_PtfPSz0t9eNDEUGmWDh1Wgssb4W_H-wPqgl9VPMT7T6ynkfIm0-ODPZTBzgSHiY8C_L1-DkhsK7XiqbUlSDgx9FpfChZS3ah8QhA8geqnb_HVuSktg7WhpxmogSpK5QdrwSE3jsbItpzOfLJ4iBd2ExzS2C0y8H_Coluk3Y1YA07tAxJ6Y7oBv-XwGqNfZhveOCQOzX-U3dFod3fXXysjB0UB89WQ"
|
||||
}
|
||||
@@ -174,6 +174,7 @@ func ImportDashboard(c *m.ReqContext, apiCmd dtos.ImportDashboardCommand) Respon
|
||||
Path: apiCmd.Path,
|
||||
Inputs: apiCmd.Inputs,
|
||||
Overwrite: apiCmd.Overwrite,
|
||||
FolderId: apiCmd.FolderId,
|
||||
Dashboard: apiCmd.Dashboard,
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ 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"
|
||||
|
||||
@@ -16,6 +16,7 @@ type ImportDashboardCommand struct {
|
||||
Path string
|
||||
Inputs []ImportDashboardInput
|
||||
Overwrite bool
|
||||
FolderId int64
|
||||
|
||||
OrgId int64
|
||||
User *m.SignedInUser
|
||||
@@ -70,7 +71,7 @@ func ImportDashboard(cmd *ImportDashboardCommand) error {
|
||||
UserId: cmd.User.UserId,
|
||||
Overwrite: cmd.Overwrite,
|
||||
PluginId: cmd.PluginId,
|
||||
FolderId: dashboard.FolderId,
|
||||
FolderId: cmd.FolderId,
|
||||
}
|
||||
|
||||
dto := &dashboards.SaveDashboardDTO{
|
||||
@@ -91,6 +92,7 @@ func ImportDashboard(cmd *ImportDashboardCommand) error {
|
||||
Title: savedDash.Title,
|
||||
Path: cmd.Path,
|
||||
Revision: savedDash.Data.Get("revision").MustInt64(1),
|
||||
FolderId: savedDash.FolderId,
|
||||
ImportedUri: "db/" + savedDash.Slug,
|
||||
ImportedUrl: savedDash.GetUrl(),
|
||||
ImportedRevision: dashboard.Data.Get("revision").MustInt64(1),
|
||||
|
||||
@@ -17,6 +17,7 @@ type PluginDashboardInfoDTO struct {
|
||||
ImportedUrl string `json:"importedUrl"`
|
||||
Slug string `json:"slug"`
|
||||
DashboardId int64 `json:"dashboardId"`
|
||||
FolderId int64 `json:"folderId"`
|
||||
ImportedRevision int64 `json:"importedRevision"`
|
||||
Revision int64 `json:"revision"`
|
||||
Description string `json:"description"`
|
||||
|
||||
@@ -41,10 +41,8 @@ func NewTeamsNotifier(model *m.AlertNotification) (alerting.Notifier, error) {
|
||||
|
||||
type TeamsNotifier struct {
|
||||
NotifierBase
|
||||
Url string
|
||||
Recipient string
|
||||
Mention string
|
||||
log log.Logger
|
||||
Url string
|
||||
log log.Logger
|
||||
}
|
||||
|
||||
func (this *TeamsNotifier) Notify(evalContext *alerting.EvalContext) error {
|
||||
@@ -75,17 +73,17 @@ func (this *TeamsNotifier) Notify(evalContext *alerting.EvalContext) error {
|
||||
})
|
||||
}
|
||||
|
||||
message := this.Mention
|
||||
if evalContext.Rule.State != m.AlertStateOK { //don't add message when going back to alert state ok.
|
||||
message += " " + evalContext.Rule.Message
|
||||
} else {
|
||||
message += " " // summary must not be empty
|
||||
message := ""
|
||||
if evalContext.Rule.State != m.AlertStateOK { //dont add message when going back to alert state ok.
|
||||
message = evalContext.Rule.Message
|
||||
}
|
||||
|
||||
body := map[string]interface{}{
|
||||
"@type": "MessageCard",
|
||||
"@context": "http://schema.org/extensions",
|
||||
"summary": message,
|
||||
"@type": "MessageCard",
|
||||
"@context": "http://schema.org/extensions",
|
||||
// summary MUST not be empty or the webhook request fails
|
||||
// summary SHOULD contain some meaningful information, since it is used for mobile notifications
|
||||
"summary": evalContext.GetNotificationTitle(),
|
||||
"title": evalContext.GetNotificationTitle(),
|
||||
"themeColor": evalContext.GetStateModel().Color,
|
||||
"sections": []map[string]interface{}{
|
||||
|
||||
@@ -89,7 +89,7 @@ func (ss *SqlStore) ensureAdminUser() error {
|
||||
systemUserCountQuery := m.GetSystemUserCountStatsQuery{}
|
||||
|
||||
if err := bus.Dispatch(&systemUserCountQuery); err != nil {
|
||||
fmt.Errorf("Could not determine if admin user exists: %v", err)
|
||||
return fmt.Errorf("Could not determine if admin user exists: %v", err)
|
||||
}
|
||||
|
||||
if systemUserCountQuery.Result.Count > 0 {
|
||||
|
||||
@@ -43,12 +43,12 @@ type Client interface {
|
||||
var NewClient = func(ctx context.Context, ds *models.DataSource, timeRange *tsdb.TimeRange) (Client, error) {
|
||||
version, err := ds.JsonData.Get("esVersion").Int()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("eleasticsearch version is required, err=%v", err)
|
||||
return nil, fmt.Errorf("elasticsearch version is required, err=%v", err)
|
||||
}
|
||||
|
||||
timeField, err := ds.JsonData.Get("timeField").String()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("eleasticsearch time field name is required, err=%v", err)
|
||||
return nil, fmt.Errorf("elasticsearch time field name is required, err=%v", err)
|
||||
}
|
||||
|
||||
indexInterval := ds.JsonData.Get("interval").MustString()
|
||||
|
||||
@@ -31,6 +31,7 @@ func init() {
|
||||
renders["mean"] = QueryDefinition{Renderer: functionRenderer}
|
||||
renders["median"] = QueryDefinition{Renderer: functionRenderer}
|
||||
renders["sum"] = QueryDefinition{Renderer: functionRenderer}
|
||||
renders["mode"] = QueryDefinition{Renderer: functionRenderer}
|
||||
|
||||
renders["holt_winters"] = QueryDefinition{
|
||||
Renderer: functionRenderer,
|
||||
|
||||
@@ -4,85 +4,39 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/tsdb"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestInfluxdbQueryPart(t *testing.T) {
|
||||
Convey("Influxdb query parts", t, func() {
|
||||
tcs := []struct {
|
||||
mode string
|
||||
input string
|
||||
params []string
|
||||
expected string
|
||||
}{
|
||||
{mode: "field", params: []string{"value"}, input: "value", expected: `"value"`},
|
||||
{mode: "derivative", params: []string{"10s"}, input: "mean(value)", expected: `derivative(mean(value), 10s)`},
|
||||
{mode: "bottom", params: []string{"3"}, input: "value", expected: `bottom(value, 3)`},
|
||||
{mode: "time", params: []string{"$interval"}, input: "", expected: `time($interval)`},
|
||||
{mode: "time", params: []string{"auto"}, input: "", expected: `time($__interval)`},
|
||||
{mode: "spread", params: []string{}, input: "value", expected: `spread(value)`},
|
||||
{mode: "math", params: []string{"/ 100"}, input: "mean(value)", expected: `mean(value) / 100`},
|
||||
{mode: "alias", params: []string{"test"}, input: "mean(value)", expected: `mean(value) AS "test"`},
|
||||
{mode: "count", params: []string{}, input: "distinct(value)", expected: `count(distinct(value))`},
|
||||
{mode: "mode", params: []string{}, input: "value", expected: `mode(value)`},
|
||||
}
|
||||
|
||||
queryContext := &tsdb.TsdbQuery{TimeRange: tsdb.NewTimeRange("5m", "now")}
|
||||
query := &Query{}
|
||||
queryContext := &tsdb.TsdbQuery{TimeRange: tsdb.NewTimeRange("5m", "now")}
|
||||
query := &Query{}
|
||||
|
||||
Convey("render field ", func() {
|
||||
part, err := NewQueryPart("field", []string{"value"})
|
||||
So(err, ShouldBeNil)
|
||||
for _, tc := range tcs {
|
||||
part, err := NewQueryPart(tc.mode, tc.params)
|
||||
if err != nil {
|
||||
t.Errorf("Expected NewQueryPart to not return an error. error: %v", err)
|
||||
}
|
||||
|
||||
res := part.Render(query, queryContext, "value")
|
||||
So(res, ShouldEqual, `"value"`)
|
||||
})
|
||||
|
||||
Convey("render nested part", func() {
|
||||
part, err := NewQueryPart("derivative", []string{"10s"})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res := part.Render(query, queryContext, "mean(value)")
|
||||
So(res, ShouldEqual, "derivative(mean(value), 10s)")
|
||||
})
|
||||
|
||||
Convey("render bottom", func() {
|
||||
part, err := NewQueryPart("bottom", []string{"3"})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res := part.Render(query, queryContext, "value")
|
||||
So(res, ShouldEqual, "bottom(value, 3)")
|
||||
})
|
||||
|
||||
Convey("render time with $interval", func() {
|
||||
part, err := NewQueryPart("time", []string{"$interval"})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res := part.Render(query, queryContext, "")
|
||||
So(res, ShouldEqual, "time($interval)")
|
||||
})
|
||||
|
||||
Convey("render time with auto", func() {
|
||||
part, err := NewQueryPart("time", []string{"auto"})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res := part.Render(query, queryContext, "")
|
||||
So(res, ShouldEqual, "time($__interval)")
|
||||
})
|
||||
|
||||
Convey("render spread", func() {
|
||||
part, err := NewQueryPart("spread", []string{})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res := part.Render(query, queryContext, "value")
|
||||
So(res, ShouldEqual, `spread(value)`)
|
||||
})
|
||||
|
||||
Convey("render suffix", func() {
|
||||
part, err := NewQueryPart("math", []string{"/ 100"})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res := part.Render(query, queryContext, "mean(value)")
|
||||
So(res, ShouldEqual, "mean(value) / 100")
|
||||
})
|
||||
|
||||
Convey("render alias", func() {
|
||||
part, err := NewQueryPart("alias", []string{"test"})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res := part.Render(query, queryContext, "mean(value)")
|
||||
So(res, ShouldEqual, `mean(value) AS "test"`)
|
||||
})
|
||||
|
||||
Convey("render count distinct", func() {
|
||||
part, err := NewQueryPart("count", []string{})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res := part.Render(query, queryContext, "distinct(value)")
|
||||
So(res, ShouldEqual, `count(distinct(value))`)
|
||||
})
|
||||
})
|
||||
res := part.Render(query, queryContext, tc.input)
|
||||
if res != tc.expected {
|
||||
t.Errorf("expected %v to render into %s", tc, tc.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
|
||||
body.mousemove(userActivityDetected);
|
||||
body.keydown(userActivityDetected);
|
||||
// set useCapture = true to catch event here
|
||||
document.addEventListener('wheel', userActivityDetected, true);
|
||||
document.addEventListener('wheel', userActivityDetected, { capture: true, passive: true });
|
||||
// treat tab change as activity
|
||||
document.addEventListener('visibilitychange', userActivityDetected);
|
||||
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
<i class="fa fa-plus"></i>
|
||||
Folder
|
||||
</a>
|
||||
<a class="btn btn-success" href="{{ctrl.importDashboardUrl()}}" ng-if="ctrl.hasEditPermissionInFolders || ctrl.canSave">
|
||||
<i class="fa fa-plus"></i>
|
||||
Import
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="page-action-bar page-action-bar--narrow" ng-show="ctrl.hasFilters">
|
||||
|
||||
@@ -294,6 +294,16 @@ export class ManageDashboardsCtrl {
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
importDashboardUrl() {
|
||||
let url = 'dashboard/import';
|
||||
|
||||
if (this.folderId) {
|
||||
url += `?folderId=${this.folderId}`;
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
export function manageDashboardsDirective() {
|
||||
|
||||
@@ -52,11 +52,11 @@
|
||||
<a href="dashboards/folder/new" class="search-filter-box-link" ng-if="ctrl.isEditor">
|
||||
<i class="gicon gicon-folder-new"></i> New folder
|
||||
</a>
|
||||
<a href="dashboard/import" class="search-filter-box-link" ng-if="ctrl.isEditor">
|
||||
<a href="dashboard/import" class="search-filter-box-link" ng-if="ctrl.isEditor || ctrl.hasEditPermissionInFolders">
|
||||
<i class="gicon gicon-dashboard-import"></i> Import dashboard
|
||||
</a>
|
||||
<a class="search-filter-box-link" target="_blank" href="https://grafana.com/dashboards?utm_source=grafana_search">
|
||||
<img src="public/img/icn-dashboard-tiny.svg" width="20" /> Find dashboards on Grafana.com
|
||||
<img src="public/img/icn-dashboard-tiny.svg" width="20" /> Find dashboards on Grafana.com
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,6 +16,7 @@ class Settings {
|
||||
defaultDatasource: string;
|
||||
alertingEnabled: boolean;
|
||||
authProxyEnabled: boolean;
|
||||
exploreEnabled: boolean;
|
||||
ldapEnabled: boolean;
|
||||
oauth: any;
|
||||
disableUserSignUp: boolean;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import $ from 'jquery';
|
||||
import _ from 'lodash';
|
||||
|
||||
import config from 'app/core/config';
|
||||
import coreModule from 'app/core/core_module';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { encodePathComponent } from 'app/core/utils/location_util';
|
||||
@@ -178,7 +179,7 @@ export class KeybindingSrv {
|
||||
});
|
||||
|
||||
// jump to explore if permissions allow
|
||||
if (this.contextSrv.isEditor) {
|
||||
if (this.contextSrv.isEditor && config.exploreEnabled) {
|
||||
this.bind('x', async () => {
|
||||
if (dashboard.meta.focusPanelId) {
|
||||
const panel = dashboard.getPanelById(dashboard.meta.focusPanelId);
|
||||
|
||||
@@ -499,6 +499,7 @@ kbn.valueFormats.watt = kbn.formatBuilders.decimalSIPrefix('W');
|
||||
kbn.valueFormats.kwatt = kbn.formatBuilders.decimalSIPrefix('W', 1);
|
||||
kbn.valueFormats.mwatt = kbn.formatBuilders.decimalSIPrefix('W', -1);
|
||||
kbn.valueFormats.kwattm = kbn.formatBuilders.decimalSIPrefix('W/Min', 1);
|
||||
kbn.valueFormats.Wm2 = kbn.formatBuilders.fixedUnit('W/m2');
|
||||
kbn.valueFormats.voltamp = kbn.formatBuilders.decimalSIPrefix('VA');
|
||||
kbn.valueFormats.kvoltamp = kbn.formatBuilders.decimalSIPrefix('VA', 1);
|
||||
kbn.valueFormats.voltampreact = kbn.formatBuilders.decimalSIPrefix('var');
|
||||
@@ -528,6 +529,7 @@ kbn.valueFormats.pressurebar = kbn.formatBuilders.decimalSIPrefix('bar');
|
||||
kbn.valueFormats.pressurembar = kbn.formatBuilders.decimalSIPrefix('bar', -1);
|
||||
kbn.valueFormats.pressurekbar = kbn.formatBuilders.decimalSIPrefix('bar', 1);
|
||||
kbn.valueFormats.pressurehpa = kbn.formatBuilders.fixedUnit('hPa');
|
||||
kbn.valueFormats.pressurekpa = kbn.formatBuilders.fixedUnit('kPa');
|
||||
kbn.valueFormats.pressurehg = kbn.formatBuilders.fixedUnit('"Hg');
|
||||
kbn.valueFormats.pressurepsi = kbn.formatBuilders.scaledUnits(1000, [' psi', ' ksi', ' Mpsi']);
|
||||
|
||||
@@ -579,6 +581,9 @@ kbn.valueFormats.flowgpm = kbn.formatBuilders.fixedUnit('gpm');
|
||||
kbn.valueFormats.flowcms = kbn.formatBuilders.fixedUnit('cms');
|
||||
kbn.valueFormats.flowcfs = kbn.formatBuilders.fixedUnit('cfs');
|
||||
kbn.valueFormats.flowcfm = kbn.formatBuilders.fixedUnit('cfm');
|
||||
kbn.valueFormats.litreh = kbn.formatBuilders.fixedUnit('l/h');
|
||||
kbn.valueFormats.flowlpm = kbn.formatBuilders.decimalSIPrefix('L');
|
||||
kbn.valueFormats.flowmlpm = kbn.formatBuilders.decimalSIPrefix('L', -1);
|
||||
|
||||
// Angle
|
||||
kbn.valueFormats.degree = kbn.formatBuilders.fixedUnit('°');
|
||||
@@ -1014,6 +1019,7 @@ kbn.getUnitFormats = function() {
|
||||
{ text: 'Watt (W)', value: 'watt' },
|
||||
{ text: 'Kilowatt (kW)', value: 'kwatt' },
|
||||
{ text: 'Milliwatt (mW)', value: 'mwatt' },
|
||||
{ text: 'Watt per square metre (W/m2)', value: 'Wm2' },
|
||||
{ text: 'Volt-ampere (VA)', value: 'voltamp' },
|
||||
{ text: 'Kilovolt-ampere (kVA)', value: 'kvoltamp' },
|
||||
{ text: 'Volt-ampere reactive (var)', value: 'voltampreact' },
|
||||
@@ -1049,6 +1055,7 @@ kbn.getUnitFormats = function() {
|
||||
{ text: 'Bars', value: 'pressurebar' },
|
||||
{ text: 'Kilobars', value: 'pressurekbar' },
|
||||
{ text: 'Hectopascals', value: 'pressurehpa' },
|
||||
{ text: 'Kilopascals', value: 'pressurekpa' },
|
||||
{ text: 'Inches of mercury', value: 'pressurehg' },
|
||||
{ text: 'PSI', value: 'pressurepsi' },
|
||||
],
|
||||
@@ -1069,6 +1076,9 @@ kbn.getUnitFormats = function() {
|
||||
{ text: 'Cubic meters/sec (cms)', value: 'flowcms' },
|
||||
{ text: 'Cubic feet/sec (cfs)', value: 'flowcfs' },
|
||||
{ text: 'Cubic feet/min (cfm)', value: 'flowcfm' },
|
||||
{ text: 'Litre/hour', value: 'litreh' },
|
||||
{ text: 'Litre/min (l/min)', value: 'flowlpm' },
|
||||
{ text: 'milliLitre/min (mL/min)', value: 'flowmlpm' },
|
||||
],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -18,9 +18,9 @@ describe('ThresholdMapper', () => {
|
||||
};
|
||||
|
||||
var updated = ThresholdMapper.alertToGraphThresholds(panel);
|
||||
expect(updated).to.be(true);
|
||||
expect(panel.thresholds[0].op).to.be('gt');
|
||||
expect(panel.thresholds[0].value).to.be(100);
|
||||
expect(updated).toBe(true);
|
||||
expect(panel.thresholds[0].op).toBe('gt');
|
||||
expect(panel.thresholds[0].value).toBe(100);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -39,12 +39,12 @@ describe('ThresholdMapper', () => {
|
||||
};
|
||||
|
||||
var updated = ThresholdMapper.alertToGraphThresholds(panel);
|
||||
expect(updated).to.be(true);
|
||||
expect(panel.thresholds[0].op).to.be('lt');
|
||||
expect(panel.thresholds[0].value).to.be(100);
|
||||
expect(updated).toBe(true);
|
||||
expect(panel.thresholds[0].op).toBe('lt');
|
||||
expect(panel.thresholds[0].value).toBe(100);
|
||||
|
||||
expect(panel.thresholds[1].op).to.be('gt');
|
||||
expect(panel.thresholds[1].value).to.be(200);
|
||||
expect(panel.thresholds[1].op).toBe('gt');
|
||||
expect(panel.thresholds[1].value).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -63,12 +63,12 @@ describe('ThresholdMapper', () => {
|
||||
};
|
||||
|
||||
var updated = ThresholdMapper.alertToGraphThresholds(panel);
|
||||
expect(updated).to.be(true);
|
||||
expect(panel.thresholds[0].op).to.be('gt');
|
||||
expect(panel.thresholds[0].value).to.be(100);
|
||||
expect(updated).toBe(true);
|
||||
expect(panel.thresholds[0].op).toBe('gt');
|
||||
expect(panel.thresholds[0].value).toBe(100);
|
||||
|
||||
expect(panel.thresholds[1].op).to.be('lt');
|
||||
expect(panel.thresholds[1].value).to.be(200);
|
||||
expect(panel.thresholds[1].op).toBe('lt');
|
||||
expect(panel.thresholds[1].value).toBe(200);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -21,6 +21,9 @@ export class DashboardImportCtrl {
|
||||
uidValidationError: any;
|
||||
autoGenerateUid: boolean;
|
||||
autoGenerateUidValue: string;
|
||||
folderId: number;
|
||||
initialFolderTitle: string;
|
||||
isValidFolderSelection: boolean;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private backendSrv, private validationSrv, navModelSrv, private $location, $routeParams) {
|
||||
@@ -31,6 +34,8 @@ export class DashboardImportCtrl {
|
||||
this.uidExists = false;
|
||||
this.autoGenerateUid = true;
|
||||
this.autoGenerateUidValue = 'auto-generated';
|
||||
this.folderId = $routeParams.folderId ? Number($routeParams.folderId) || 0 : null;
|
||||
this.initialFolderTitle = 'Select a folder';
|
||||
|
||||
// check gnetId in url
|
||||
if ($routeParams.gnetId) {
|
||||
@@ -102,8 +107,9 @@ export class DashboardImportCtrl {
|
||||
this.nameExists = false;
|
||||
|
||||
this.validationSrv
|
||||
.validateNewDashboardName(0, this.dash.title)
|
||||
.validateNewDashboardName(this.folderId, this.dash.title)
|
||||
.then(() => {
|
||||
this.nameExists = false;
|
||||
this.hasNameValidationError = false;
|
||||
})
|
||||
.catch(err => {
|
||||
@@ -138,6 +144,23 @@ export class DashboardImportCtrl {
|
||||
});
|
||||
}
|
||||
|
||||
onFolderChange(folder) {
|
||||
this.folderId = folder.id;
|
||||
this.titleChanged();
|
||||
}
|
||||
|
||||
onEnterFolderCreation() {
|
||||
this.inputsValid = false;
|
||||
}
|
||||
|
||||
onExitFolderCreation() {
|
||||
this.inputValueChanged();
|
||||
}
|
||||
|
||||
isValid() {
|
||||
return this.inputsValid && this.folderId !== null;
|
||||
}
|
||||
|
||||
saveDashboard() {
|
||||
var inputs = this.inputs.map(input => {
|
||||
return {
|
||||
@@ -153,6 +176,7 @@ export class DashboardImportCtrl {
|
||||
dashboard: this.dash,
|
||||
overwrite: true,
|
||||
inputs: inputs,
|
||||
folderId: this.folderId,
|
||||
})
|
||||
.then(res => {
|
||||
this.$location.url(res.importedUrl);
|
||||
|
||||
@@ -154,6 +154,15 @@ export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelP
|
||||
});
|
||||
}
|
||||
|
||||
filterKeyPress(evt) {
|
||||
if (evt.key === 'Enter') {
|
||||
let panel = _.head(this.state.panelPlugins);
|
||||
if (panel) {
|
||||
this.onAddPanel(panel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filterPanels(panels, filter) {
|
||||
let regex = new RegExp(filter, 'i');
|
||||
return panels.filter(panel => {
|
||||
@@ -229,10 +238,12 @@ export class AddPanelPanel extends React.Component<AddPanelPanelProps, AddPanelP
|
||||
<label className="gf-form gf-form--grow gf-form--has-input-icon">
|
||||
<input
|
||||
type="text"
|
||||
className="gf-form-input max-width-20"
|
||||
autoFocus
|
||||
className="gf-form-input gf-form--grow"
|
||||
placeholder="Panel Search Filter"
|
||||
value={this.state.filter}
|
||||
onChange={this.filterChange.bind(this)}
|
||||
onKeyPress={this.filterKeyPress.bind(this)}
|
||||
/>
|
||||
<i className="gf-form-input-icon fa fa-search" />
|
||||
</label>
|
||||
|
||||
@@ -84,15 +84,18 @@ export class DashboardRow extends React.Component<DashboardRowProps, any> {
|
||||
'fa-chevron-right': this.state.collapsed,
|
||||
});
|
||||
|
||||
let title = templateSrv.replaceWithText(this.props.panel.title, this.props.panel.scopedVars);
|
||||
const hiddenPanels = this.props.panel.panels ? this.props.panel.panels.length : 0;
|
||||
const title = templateSrv.replaceWithText(this.props.panel.title, this.props.panel.scopedVars);
|
||||
const count = this.props.panel.panels ? this.props.panel.panels.length : 0;
|
||||
const panels = count === 1 ? 'panel' : 'panels';
|
||||
|
||||
return (
|
||||
<div className={classes}>
|
||||
<a className="dashboard-row__title pointer" onClick={this.toggle}>
|
||||
<i className={chevronClass} />
|
||||
{title}
|
||||
<span className="dashboard-row__panel_count">({hiddenPanels} hidden panels)</span>
|
||||
<span className="dashboard-row__panel_count">
|
||||
({count} {panels})
|
||||
</span>
|
||||
</a>
|
||||
{this.dashboard.meta.canEdit === true && (
|
||||
<div className="dashboard-row__actions">
|
||||
@@ -104,6 +107,11 @@ export class DashboardRow extends React.Component<DashboardRowProps, any> {
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
{this.state.collapsed === true && (
|
||||
<div className="dashboard-row__toggle-target" onClick={this.toggle}>
|
||||
|
||||
</div>
|
||||
)}
|
||||
<div className="dashboard-row__drag grid-drag-handle" />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -132,23 +132,26 @@ export class FolderPickerCtrl {
|
||||
}
|
||||
|
||||
private loadInitialValue() {
|
||||
if (this.initialFolderId && this.initialFolderId > 0) {
|
||||
this.getOptions('').then(result => {
|
||||
this.folder = _.find(result, { value: this.initialFolderId });
|
||||
if (!this.folder) {
|
||||
this.folder = { text: this.initialTitle, value: this.initialFolderId };
|
||||
}
|
||||
this.onFolderLoad();
|
||||
});
|
||||
} else {
|
||||
if (this.initialTitle && this.initialFolderId === null) {
|
||||
this.folder = { text: this.initialTitle, value: null };
|
||||
} else {
|
||||
this.folder = { text: this.rootName, value: 0 };
|
||||
const resetFolder = { text: this.initialTitle, value: null };
|
||||
const rootFolder = { text: this.rootName, value: 0 };
|
||||
this.getOptions('').then(result => {
|
||||
let folder;
|
||||
if (this.initialFolderId) {
|
||||
folder = _.find(result, { value: this.initialFolderId });
|
||||
} else if (this.enableReset && this.initialTitle && this.initialFolderId === null) {
|
||||
folder = resetFolder;
|
||||
}
|
||||
|
||||
if (!folder) {
|
||||
if (this.isEditor) {
|
||||
folder = rootFolder;
|
||||
} else {
|
||||
folder = result.length > 0 ? result[0] : resetFolder;
|
||||
}
|
||||
}
|
||||
this.folder = folder;
|
||||
this.onFolderLoad();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private onFolderLoad() {
|
||||
|
||||
@@ -80,6 +80,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form gf-form--grow">
|
||||
<folder-picker label-class="width-15"
|
||||
initial-folder-id="ctrl.folderId"
|
||||
initial-title="ctrl.initialFolderTitle"
|
||||
on-change="ctrl.onFolderChange($folder)"
|
||||
on-load="ctrl.onFolderChange($folder)"
|
||||
enter-folder-creation="ctrl.onEnterFolderCreation()"
|
||||
exit-folder-creation="ctrl.onExitFolderCreation()"
|
||||
enable-create-new="true">
|
||||
</folder-picker>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form gf-form--grow">
|
||||
<span class="gf-form-label width-15">
|
||||
@@ -132,10 +146,10 @@
|
||||
</div>
|
||||
|
||||
<div class="gf-form-button-row">
|
||||
<button type="button" class="btn btn-success width-12" ng-click="ctrl.saveDashboard()" ng-hide="ctrl.nameExists || ctrl.uidExists" ng-disabled="!ctrl.inputsValid">
|
||||
<button type="button" class="btn btn-success width-12" ng-click="ctrl.saveDashboard()" ng-hide="ctrl.nameExists || ctrl.uidExists" ng-disabled="!ctrl.isValid()">
|
||||
<i class="fa fa-save"></i> Import
|
||||
</button>
|
||||
<button type="button" class="btn btn-danger width-12" ng-click="ctrl.saveDashboard()" ng-show="ctrl.nameExists || ctrl.uidExists" ng-disabled="!ctrl.inputsValid">
|
||||
<button type="button" class="btn btn-danger width-12" ng-click="ctrl.saveDashboard()" ng-show="ctrl.nameExists || ctrl.uidExists" ng-disabled="!ctrl.isValid()">
|
||||
<i class="fa fa-save"></i> Import (Overwrite)
|
||||
</button>
|
||||
<a class="btn btn-link" ng-click="ctrl.back()">Cancel</a>
|
||||
|
||||
@@ -50,8 +50,17 @@ const template = `
|
||||
</div>
|
||||
|
||||
<div class="gf-form-button-row text-center">
|
||||
<button type="submit" class="btn btn-success" ng-disabled="ctrl.saveForm.$invalid">Save</button>
|
||||
<a class="btn btn-link" ng-click="ctrl.dismiss();">Cancel</a>
|
||||
<button
|
||||
id="saveBtn"
|
||||
type="submit"
|
||||
class="btn btn-success"
|
||||
ng-class="{'btn-success--processing': ctrl.isSaving}"
|
||||
ng-disabled="ctrl.saveForm.$invalid || ctrl.isSaving"
|
||||
>
|
||||
<span ng-if="!ctrl.isSaving">Save</span>
|
||||
<span ng-if="ctrl.isSaving === true">Saving...</span>
|
||||
</button>
|
||||
<button class="btn btn-inverse" ng-click="ctrl.dismiss();">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@@ -68,6 +77,7 @@ export class SaveDashboardModalCtrl {
|
||||
originalCurrent = [];
|
||||
max: number;
|
||||
saveForm: any;
|
||||
isSaving: boolean;
|
||||
dismiss: () => void;
|
||||
timeChange = false;
|
||||
variableValueChange = false;
|
||||
@@ -76,6 +86,7 @@ export class SaveDashboardModalCtrl {
|
||||
constructor(private dashboardSrv) {
|
||||
this.message = '';
|
||||
this.max = 64;
|
||||
this.isSaving = false;
|
||||
this.templating = dashboardSrv.dash.templating.list;
|
||||
|
||||
this.compareTemplating();
|
||||
@@ -126,6 +137,8 @@ export class SaveDashboardModalCtrl {
|
||||
var dashboard = this.dashboardSrv.getCurrent();
|
||||
var saveModel = dashboard.getSaveModelClone(options);
|
||||
|
||||
this.isSaving = true;
|
||||
|
||||
return this.dashboardSrv.save(saveModel, options).then(this.dismiss);
|
||||
}
|
||||
}
|
||||
|
||||
194
public/app/features/dashboard/specs/exporter.jest.ts
Normal file
194
public/app/features/dashboard/specs/exporter.jest.ts
Normal file
@@ -0,0 +1,194 @@
|
||||
jest.mock('app/core/store', () => {
|
||||
return {
|
||||
getBool: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
import _ from 'lodash';
|
||||
import config from 'app/core/config';
|
||||
import { DashboardExporter } from '../export/exporter';
|
||||
import { DashboardModel } from '../dashboard_model';
|
||||
|
||||
describe('given dashboard with repeated panels', () => {
|
||||
var dash, exported;
|
||||
|
||||
beforeEach(done => {
|
||||
dash = {
|
||||
templating: {
|
||||
list: [
|
||||
{
|
||||
name: 'apps',
|
||||
type: 'query',
|
||||
datasource: 'gfdb',
|
||||
current: { value: 'Asd', text: 'Asd' },
|
||||
options: [{ value: 'Asd', text: 'Asd' }],
|
||||
},
|
||||
{
|
||||
name: 'prefix',
|
||||
type: 'constant',
|
||||
current: { value: 'collectd', text: 'collectd' },
|
||||
options: [],
|
||||
},
|
||||
{
|
||||
name: 'ds',
|
||||
type: 'datasource',
|
||||
query: 'testdb',
|
||||
current: { value: 'prod', text: 'prod' },
|
||||
options: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
annotations: {
|
||||
list: [
|
||||
{
|
||||
name: 'logs',
|
||||
datasource: 'gfdb',
|
||||
},
|
||||
],
|
||||
},
|
||||
panels: [
|
||||
{ id: 6, datasource: 'gfdb', type: 'graph' },
|
||||
{ id: 7 },
|
||||
{
|
||||
id: 8,
|
||||
datasource: '-- Mixed --',
|
||||
targets: [{ datasource: 'other' }],
|
||||
},
|
||||
{ id: 9, datasource: '$ds' },
|
||||
{
|
||||
id: 2,
|
||||
repeat: 'apps',
|
||||
datasource: 'gfdb',
|
||||
type: 'graph',
|
||||
},
|
||||
{ id: 3, repeat: null, repeatPanelId: 2 },
|
||||
],
|
||||
};
|
||||
|
||||
config.buildInfo = {
|
||||
version: '3.0.2',
|
||||
};
|
||||
|
||||
//Stubs test function calls
|
||||
var datasourceSrvStub = { get: jest.fn(arg => getStub(arg)) };
|
||||
|
||||
config.panels['graph'] = {
|
||||
id: 'graph',
|
||||
name: 'Graph',
|
||||
info: { version: '1.1.0' },
|
||||
};
|
||||
|
||||
dash = new DashboardModel(dash, {});
|
||||
var exporter = new DashboardExporter(datasourceSrvStub);
|
||||
exporter.makeExportable(dash).then(clean => {
|
||||
exported = clean;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should replace datasource refs', () => {
|
||||
var panel = exported.panels[0];
|
||||
expect(panel.datasource).toBe('${DS_GFDB}');
|
||||
});
|
||||
|
||||
it('should replace datasource in variable query', () => {
|
||||
expect(exported.templating.list[0].datasource).toBe('${DS_GFDB}');
|
||||
expect(exported.templating.list[0].options.length).toBe(0);
|
||||
expect(exported.templating.list[0].current.value).toBe(undefined);
|
||||
expect(exported.templating.list[0].current.text).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should replace datasource in annotation query', () => {
|
||||
expect(exported.annotations.list[1].datasource).toBe('${DS_GFDB}');
|
||||
});
|
||||
|
||||
it('should add datasource as input', () => {
|
||||
expect(exported.__inputs[0].name).toBe('DS_GFDB');
|
||||
expect(exported.__inputs[0].pluginId).toBe('testdb');
|
||||
expect(exported.__inputs[0].type).toBe('datasource');
|
||||
});
|
||||
|
||||
it('should add datasource to required', () => {
|
||||
var require = _.find(exported.__requires, { name: 'TestDB' });
|
||||
expect(require.name).toBe('TestDB');
|
||||
expect(require.id).toBe('testdb');
|
||||
expect(require.type).toBe('datasource');
|
||||
expect(require.version).toBe('1.2.1');
|
||||
});
|
||||
|
||||
it('should not add built in datasources to required', () => {
|
||||
var require = _.find(exported.__requires, { name: 'Mixed' });
|
||||
expect(require).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should add datasources used in mixed mode', () => {
|
||||
var require = _.find(exported.__requires, { name: 'OtherDB' });
|
||||
expect(require).not.toBe(undefined);
|
||||
});
|
||||
|
||||
it('should add panel to required', () => {
|
||||
var require = _.find(exported.__requires, { name: 'Graph' });
|
||||
expect(require.name).toBe('Graph');
|
||||
expect(require.id).toBe('graph');
|
||||
expect(require.version).toBe('1.1.0');
|
||||
});
|
||||
|
||||
it('should add grafana version', () => {
|
||||
var require = _.find(exported.__requires, { name: 'Grafana' });
|
||||
expect(require.type).toBe('grafana');
|
||||
expect(require.id).toBe('grafana');
|
||||
expect(require.version).toBe('3.0.2');
|
||||
});
|
||||
|
||||
it('should add constant template variables as inputs', () => {
|
||||
var input = _.find(exported.__inputs, { name: 'VAR_PREFIX' });
|
||||
expect(input.type).toBe('constant');
|
||||
expect(input.label).toBe('prefix');
|
||||
expect(input.value).toBe('collectd');
|
||||
});
|
||||
|
||||
it('should templatize constant variables', () => {
|
||||
var variable = _.find(exported.templating.list, { name: 'prefix' });
|
||||
expect(variable.query).toBe('${VAR_PREFIX}');
|
||||
expect(variable.current.text).toBe('${VAR_PREFIX}');
|
||||
expect(variable.current.value).toBe('${VAR_PREFIX}');
|
||||
expect(variable.options[0].text).toBe('${VAR_PREFIX}');
|
||||
expect(variable.options[0].value).toBe('${VAR_PREFIX}');
|
||||
});
|
||||
});
|
||||
|
||||
// Stub responses
|
||||
var stubs = [];
|
||||
stubs['gfdb'] = {
|
||||
name: 'gfdb',
|
||||
meta: { id: 'testdb', info: { version: '1.2.1' }, name: 'TestDB' },
|
||||
};
|
||||
|
||||
stubs['other'] = {
|
||||
name: 'other',
|
||||
meta: { id: 'other', info: { version: '1.2.1' }, name: 'OtherDB' },
|
||||
};
|
||||
|
||||
stubs['-- Mixed --'] = {
|
||||
name: 'mixed',
|
||||
meta: {
|
||||
id: 'mixed',
|
||||
info: { version: '1.2.1' },
|
||||
name: 'Mixed',
|
||||
builtIn: true,
|
||||
},
|
||||
};
|
||||
|
||||
stubs['-- Grafana --'] = {
|
||||
name: '-- Grafana --',
|
||||
meta: {
|
||||
id: 'grafana',
|
||||
info: { version: '1.2.1' },
|
||||
name: 'grafana',
|
||||
builtIn: true,
|
||||
},
|
||||
};
|
||||
|
||||
function getStub(arg) {
|
||||
return Promise.resolve(stubs[arg]);
|
||||
}
|
||||
@@ -1,187 +0,0 @@
|
||||
import { describe, beforeEach, it, sinon, expect } from 'test/lib/common';
|
||||
|
||||
import _ from 'lodash';
|
||||
import config from 'app/core/config';
|
||||
import { DashboardExporter } from '../export/exporter';
|
||||
import { DashboardModel } from '../dashboard_model';
|
||||
|
||||
describe('given dashboard with repeated panels', function() {
|
||||
var dash, exported;
|
||||
|
||||
beforeEach(done => {
|
||||
dash = {
|
||||
templating: { list: [] },
|
||||
annotations: { list: [] },
|
||||
};
|
||||
|
||||
config.buildInfo = {
|
||||
version: '3.0.2',
|
||||
};
|
||||
|
||||
dash.templating.list.push({
|
||||
name: 'apps',
|
||||
type: 'query',
|
||||
datasource: 'gfdb',
|
||||
current: { value: 'Asd', text: 'Asd' },
|
||||
options: [{ value: 'Asd', text: 'Asd' }],
|
||||
});
|
||||
|
||||
dash.templating.list.push({
|
||||
name: 'prefix',
|
||||
type: 'constant',
|
||||
current: { value: 'collectd', text: 'collectd' },
|
||||
options: [],
|
||||
});
|
||||
|
||||
dash.templating.list.push({
|
||||
name: 'ds',
|
||||
type: 'datasource',
|
||||
query: 'testdb',
|
||||
current: { value: 'prod', text: 'prod' },
|
||||
options: [],
|
||||
});
|
||||
|
||||
dash.annotations.list.push({
|
||||
name: 'logs',
|
||||
datasource: 'gfdb',
|
||||
});
|
||||
|
||||
dash.panels = [
|
||||
{ id: 6, datasource: 'gfdb', type: 'graph' },
|
||||
{ id: 7 },
|
||||
{
|
||||
id: 8,
|
||||
datasource: '-- Mixed --',
|
||||
targets: [{ datasource: 'other' }],
|
||||
},
|
||||
{ id: 9, datasource: '$ds' },
|
||||
];
|
||||
|
||||
dash.panels.push({
|
||||
id: 2,
|
||||
repeat: 'apps',
|
||||
datasource: 'gfdb',
|
||||
type: 'graph',
|
||||
});
|
||||
dash.panels.push({ id: 3, repeat: null, repeatPanelId: 2 });
|
||||
|
||||
var datasourceSrvStub = { get: sinon.stub() };
|
||||
datasourceSrvStub.get.withArgs('gfdb').returns(
|
||||
Promise.resolve({
|
||||
name: 'gfdb',
|
||||
meta: { id: 'testdb', info: { version: '1.2.1' }, name: 'TestDB' },
|
||||
})
|
||||
);
|
||||
datasourceSrvStub.get.withArgs('other').returns(
|
||||
Promise.resolve({
|
||||
name: 'other',
|
||||
meta: { id: 'other', info: { version: '1.2.1' }, name: 'OtherDB' },
|
||||
})
|
||||
);
|
||||
datasourceSrvStub.get.withArgs('-- Mixed --').returns(
|
||||
Promise.resolve({
|
||||
name: 'mixed',
|
||||
meta: {
|
||||
id: 'mixed',
|
||||
info: { version: '1.2.1' },
|
||||
name: 'Mixed',
|
||||
builtIn: true,
|
||||
},
|
||||
})
|
||||
);
|
||||
datasourceSrvStub.get.withArgs('-- Grafana --').returns(
|
||||
Promise.resolve({
|
||||
name: '-- Grafana --',
|
||||
meta: {
|
||||
id: 'grafana',
|
||||
info: { version: '1.2.1' },
|
||||
name: 'grafana',
|
||||
builtIn: true,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
config.panels['graph'] = {
|
||||
id: 'graph',
|
||||
name: 'Graph',
|
||||
info: { version: '1.1.0' },
|
||||
};
|
||||
|
||||
dash = new DashboardModel(dash, {});
|
||||
var exporter = new DashboardExporter(datasourceSrvStub);
|
||||
exporter.makeExportable(dash).then(clean => {
|
||||
exported = clean;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should replace datasource refs', function() {
|
||||
var panel = exported.panels[0];
|
||||
expect(panel.datasource).to.be('${DS_GFDB}');
|
||||
});
|
||||
|
||||
it('should replace datasource in variable query', function() {
|
||||
expect(exported.templating.list[0].datasource).to.be('${DS_GFDB}');
|
||||
expect(exported.templating.list[0].options.length).to.be(0);
|
||||
expect(exported.templating.list[0].current.value).to.be(undefined);
|
||||
expect(exported.templating.list[0].current.text).to.be(undefined);
|
||||
});
|
||||
|
||||
it('should replace datasource in annotation query', function() {
|
||||
expect(exported.annotations.list[1].datasource).to.be('${DS_GFDB}');
|
||||
});
|
||||
|
||||
it('should add datasource as input', function() {
|
||||
expect(exported.__inputs[0].name).to.be('DS_GFDB');
|
||||
expect(exported.__inputs[0].pluginId).to.be('testdb');
|
||||
expect(exported.__inputs[0].type).to.be('datasource');
|
||||
});
|
||||
|
||||
it('should add datasource to required', function() {
|
||||
var require = _.find(exported.__requires, { name: 'TestDB' });
|
||||
expect(require.name).to.be('TestDB');
|
||||
expect(require.id).to.be('testdb');
|
||||
expect(require.type).to.be('datasource');
|
||||
expect(require.version).to.be('1.2.1');
|
||||
});
|
||||
|
||||
it('should not add built in datasources to required', function() {
|
||||
var require = _.find(exported.__requires, { name: 'Mixed' });
|
||||
expect(require).to.be(undefined);
|
||||
});
|
||||
|
||||
it('should add datasources used in mixed mode', function() {
|
||||
var require = _.find(exported.__requires, { name: 'OtherDB' });
|
||||
expect(require).to.not.be(undefined);
|
||||
});
|
||||
|
||||
it('should add panel to required', function() {
|
||||
var require = _.find(exported.__requires, { name: 'Graph' });
|
||||
expect(require.name).to.be('Graph');
|
||||
expect(require.id).to.be('graph');
|
||||
expect(require.version).to.be('1.1.0');
|
||||
});
|
||||
|
||||
it('should add grafana version', function() {
|
||||
var require = _.find(exported.__requires, { name: 'Grafana' });
|
||||
expect(require.type).to.be('grafana');
|
||||
expect(require.id).to.be('grafana');
|
||||
expect(require.version).to.be('3.0.2');
|
||||
});
|
||||
|
||||
it('should add constant template variables as inputs', function() {
|
||||
var input = _.find(exported.__inputs, { name: 'VAR_PREFIX' });
|
||||
expect(input.type).to.be('constant');
|
||||
expect(input.label).to.be('prefix');
|
||||
expect(input.value).to.be('collectd');
|
||||
});
|
||||
|
||||
it('should templatize constant variables', function() {
|
||||
var variable = _.find(exported.templating.list, { name: 'prefix' });
|
||||
expect(variable.query).to.be('${VAR_PREFIX}');
|
||||
expect(variable.current.text).to.be('${VAR_PREFIX}');
|
||||
expect(variable.current.value).to.be('${VAR_PREFIX}');
|
||||
expect(variable.options[0].text).to.be('${VAR_PREFIX}');
|
||||
expect(variable.options[0].value).to.be('${VAR_PREFIX}');
|
||||
});
|
||||
});
|
||||
@@ -314,7 +314,7 @@ class MetricsPanelCtrl extends PanelCtrl {
|
||||
|
||||
getAdditionalMenuItems() {
|
||||
const items = [];
|
||||
if (this.contextSrv.isEditor && this.datasource && this.datasource.supportsExplore) {
|
||||
if (config.exploreEnabled && this.contextSrv.isEditor && this.datasource && this.datasource.supportsExplore) {
|
||||
items.push({
|
||||
text: 'Explore',
|
||||
click: 'ctrl.explore();',
|
||||
|
||||
@@ -25,7 +25,7 @@ var template = `
|
||||
<li><a ng-click="ctrl.addDataQuery(datasource);"><i class="fa fa-trash"></i> Remove</a></li>
|
||||
</ul>
|
||||
</span>
|
||||
<span class="panel-time-info" ng-show="ctrl.timeInfo"><i class="fa fa-clock-o"></i> {{ctrl.timeInfo}}</span>
|
||||
<span class="panel-time-info" ng-if="ctrl.timeInfo"><i class="fa fa-clock-o"></i> {{ctrl.timeInfo}}</span>
|
||||
</span>`;
|
||||
|
||||
function renderMenuItem(item, ctrl) {
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
jest.mock('app/core/core', () => ({}));
|
||||
jest.mock('app/core/config', () => {
|
||||
return {
|
||||
exploreEnabled: true,
|
||||
panels: {
|
||||
test: {
|
||||
id: 'test',
|
||||
name: 'test',
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
import { MetricsPanelCtrl } from '../metrics_panel_ctrl';
|
||||
import q from 'q';
|
||||
import { PanelModel } from 'app/features/dashboard/panel_model';
|
||||
import { MetricsPanelCtrl } from '../metrics_panel_ctrl';
|
||||
|
||||
describe('MetricsPanelCtrl', () => {
|
||||
let ctrl;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import '../playlist_edit_ctrl';
|
||||
import { describe, beforeEach, it, expect } from 'test/lib/common';
|
||||
import { PlaylistEditCtrl } from '../playlist_edit_ctrl';
|
||||
|
||||
describe('PlaylistEditCtrl', () => {
|
||||
@@ -20,13 +19,13 @@ describe('PlaylistEditCtrl', () => {
|
||||
|
||||
describe('searchresult returns 2 dashboards, ', () => {
|
||||
it('found dashboard should be 2', () => {
|
||||
expect(ctx.dashboardresult.length).to.be(2);
|
||||
expect(ctx.dashboardresult.length).toBe(2);
|
||||
});
|
||||
|
||||
it('filtred result should be 2', () => {
|
||||
ctx.filterFoundPlaylistItems();
|
||||
expect(ctx.filteredDashboards.length).to.be(2);
|
||||
expect(ctx.filteredTags.length).to.be(2);
|
||||
expect(ctx.filteredDashboards.length).toBe(2);
|
||||
expect(ctx.filteredTags.length).toBe(2);
|
||||
});
|
||||
|
||||
describe('adds one dashboard to playlist, ', () => {
|
||||
@@ -37,16 +36,16 @@ describe('PlaylistEditCtrl', () => {
|
||||
});
|
||||
|
||||
it('playlistitems should be increased by one', () => {
|
||||
expect(ctx.playlistItems.length).to.be(2);
|
||||
expect(ctx.playlistItems.length).toBe(2);
|
||||
});
|
||||
|
||||
it('filtred playlistitems should be reduced by one', () => {
|
||||
expect(ctx.filteredDashboards.length).to.be(1);
|
||||
expect(ctx.filteredTags.length).to.be(1);
|
||||
expect(ctx.filteredDashboards.length).toBe(1);
|
||||
expect(ctx.filteredTags.length).toBe(1);
|
||||
});
|
||||
|
||||
it('found dashboard should be 2', () => {
|
||||
expect(ctx.dashboardresult.length).to.be(2);
|
||||
expect(ctx.dashboardresult.length).toBe(2);
|
||||
});
|
||||
|
||||
describe('removes one dashboard from playlist, ', () => {
|
||||
@@ -57,14 +56,14 @@ describe('PlaylistEditCtrl', () => {
|
||||
});
|
||||
|
||||
it('playlistitems should be increased by one', () => {
|
||||
expect(ctx.playlistItems.length).to.be(0);
|
||||
expect(ctx.playlistItems.length).toBe(0);
|
||||
});
|
||||
|
||||
it('found dashboard should be 2', () => {
|
||||
expect(ctx.dashboardresult.length).to.be(2);
|
||||
expect(ctx.filteredDashboards.length).to.be(2);
|
||||
expect(ctx.filteredTags.length).to.be(2);
|
||||
expect(ctx.tagresult.length).to.be(2);
|
||||
expect(ctx.dashboardresult.length).toBe(2);
|
||||
expect(ctx.filteredDashboards.length).toBe(2);
|
||||
expect(ctx.filteredTags.length).toBe(2);
|
||||
expect(ctx.tagresult.length).toBe(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -4,7 +4,6 @@ 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';
|
||||
@@ -31,7 +30,6 @@ 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,
|
||||
|
||||
@@ -6,7 +6,6 @@ import coreModule from 'app/core/core_module';
|
||||
import { importPluginModule } from './plugin_loader';
|
||||
|
||||
import { UnknownPanelCtrl } from 'app/plugins/panel/unknown/module';
|
||||
import { DashboardRowCtrl } from './row_ctrl';
|
||||
|
||||
/** @ngInject **/
|
||||
function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $templateCache) {
|
||||
@@ -59,15 +58,6 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $
|
||||
}
|
||||
|
||||
function loadPanelComponentInfo(scope, attrs) {
|
||||
if (scope.panel.type === 'row') {
|
||||
return $q.when({
|
||||
name: 'dashboard-row',
|
||||
bindings: { dashboard: '=', panel: '=' },
|
||||
attrs: { dashboard: 'ctrl.dashboard', panel: 'panel' },
|
||||
Component: DashboardRowCtrl,
|
||||
});
|
||||
}
|
||||
|
||||
var componentInfo: any = {
|
||||
name: 'panel-plugin-' + scope.panel.type,
|
||||
bindings: { dashboard: '=', panel: '=', row: '=' },
|
||||
@@ -136,24 +126,6 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q, $http, $
|
||||
});
|
||||
});
|
||||
}
|
||||
// QueryOptionsCtrl
|
||||
case 'query-options-ctrl': {
|
||||
return datasourceSrv.get(scope.ctrl.panel.datasource).then(ds => {
|
||||
return importPluginModule(ds.meta.module).then((dsModule): any => {
|
||||
if (!dsModule.QueryOptionsCtrl) {
|
||||
return { notFound: true };
|
||||
}
|
||||
|
||||
return {
|
||||
baseUrl: ds.meta.baseUrl,
|
||||
name: 'query-options-ctrl-' + ds.meta.id,
|
||||
bindings: { panelCtrl: '=' },
|
||||
attrs: { 'panel-ctrl': 'ctrl.panelCtrl' },
|
||||
Component: dsModule.QueryOptionsCtrl,
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
// Annotations
|
||||
case 'annotations-query-ctrl': {
|
||||
return importPluginModule(scope.ctrl.currentDatasource.meta.module).then(function(dsModule) {
|
||||
|
||||
@@ -5,6 +5,15 @@ import kbn from 'app/core/utils/kbn';
|
||||
import moment from 'moment';
|
||||
import angular from 'angular';
|
||||
import jquery from 'jquery';
|
||||
|
||||
// Experimental module exports
|
||||
import prismjs from 'prismjs';
|
||||
import slate from 'slate';
|
||||
import slateReact from 'slate-react';
|
||||
import slatePlain from 'slate-plain-serializer';
|
||||
import react from 'react';
|
||||
import reactDom from 'react-dom';
|
||||
|
||||
import config from 'app/core/config';
|
||||
import TimeSeries from 'app/core/time_series2';
|
||||
import TableModel from 'app/core/table_model';
|
||||
@@ -69,6 +78,14 @@ exposeToPlugin('d3', d3);
|
||||
exposeToPlugin('rxjs/Subject', Subject);
|
||||
exposeToPlugin('rxjs/Observable', Observable);
|
||||
|
||||
// Experimental modules
|
||||
exposeToPlugin('prismjs', prismjs);
|
||||
exposeToPlugin('slate', slate);
|
||||
exposeToPlugin('slate-react', slateReact);
|
||||
exposeToPlugin('slate-plain-serializer', slatePlain);
|
||||
exposeToPlugin('react', react);
|
||||
exposeToPlugin('react-dom', reactDom);
|
||||
|
||||
// backward compatible path
|
||||
exposeToPlugin('vendor/npm/rxjs/Rx', {
|
||||
Subject: Subject,
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
|
||||
export class DashboardRowCtrl {
|
||||
static template = `
|
||||
<div class="dashboard-row__center">
|
||||
<div class="dashboard-row__actions-left">
|
||||
<i class="fa fa-chevron-down" ng-hide="ctrl.panel.collapse"></i>
|
||||
<i class="fa fa-chevron-right" ng-show="ctrl.panel.collapse"></i>
|
||||
</div>
|
||||
<a class="dashboard-row__title pointer" ng-click="ctrl.toggle()">
|
||||
<span class="dashboard-row__title-text">
|
||||
{{ctrl.panel.title | interpolateTemplateVars:this}}
|
||||
</span>
|
||||
</a>
|
||||
<div class="dashboard-row__actions-right">
|
||||
<a class="pointer" ng-click="ctrl.openSettings()"><span class="fa fa-cog"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dashboard-row__panel_count">
|
||||
({{ctrl.panel.hiddenPanels.length}} hidden panels)
|
||||
</div>
|
||||
<div class="dashboard-row__drag grid-drag-handle">
|
||||
</div>
|
||||
`;
|
||||
|
||||
dashboard: any;
|
||||
panel: any;
|
||||
|
||||
constructor() {
|
||||
this.panel.hiddenPanels = this.panel.hiddenPanels || [];
|
||||
}
|
||||
|
||||
toggle() {
|
||||
if (this.panel.collapse) {
|
||||
let panelIndex = _.indexOf(this.dashboard.panels, this.panel);
|
||||
|
||||
for (let child of this.panel.hiddenPanels) {
|
||||
this.dashboard.panels.splice(panelIndex + 1, 0, child);
|
||||
child.y = this.panel.y + 1;
|
||||
console.log('restoring child', child);
|
||||
}
|
||||
|
||||
this.panel.hiddenPanels = [];
|
||||
this.panel.collapse = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.panel.collapse = true;
|
||||
let foundRow = false;
|
||||
|
||||
for (let i = 0; i < this.dashboard.panels.length; i++) {
|
||||
let panel = this.dashboard.panels[i];
|
||||
|
||||
if (panel === this.panel) {
|
||||
console.log('found row');
|
||||
foundRow = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!foundRow) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (panel.type === 'row') {
|
||||
break;
|
||||
}
|
||||
|
||||
this.panel.hiddenPanels.push(panel);
|
||||
console.log('hiding child', panel.id);
|
||||
}
|
||||
|
||||
for (let hiddenPanel of this.panel.hiddenPanels) {
|
||||
this.dashboard.removePanel(hiddenPanel, false);
|
||||
}
|
||||
}
|
||||
|
||||
moveUp() {
|
||||
// let panelIndex = _.indexOf(this.dashboard.panels, this.panel);
|
||||
// let rowAbove = null;
|
||||
// for (let index = panelIndex-1; index > 0; index--) {
|
||||
// panel = this.dashboard.panels[index];
|
||||
// if (panel.type === 'row') {
|
||||
// rowAbove = panel;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (rowAbove) {
|
||||
// this.panel.y = rowAbove.y;
|
||||
// }
|
||||
}
|
||||
|
||||
link(scope, elem) {
|
||||
elem.addClass('dashboard-row');
|
||||
|
||||
scope.$watch('ctrl.panel.collapse', () => {
|
||||
elem.toggleClass('dashboard-row--collapse', this.panel.collapse === true);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,6 @@ import { ElasticDatasource } from './datasource';
|
||||
import { ElasticQueryCtrl } from './query_ctrl';
|
||||
import { ElasticConfigCtrl } from './config_ctrl';
|
||||
|
||||
class ElasticQueryOptionsCtrl {
|
||||
static templateUrl = 'partials/query.options.html';
|
||||
}
|
||||
|
||||
class ElasticAnnotationsQueryCtrl {
|
||||
static templateUrl = 'partials/annotations.editor.html';
|
||||
}
|
||||
@@ -14,6 +10,5 @@ export {
|
||||
ElasticDatasource as Datasource,
|
||||
ElasticQueryCtrl as QueryCtrl,
|
||||
ElasticConfigCtrl as ConfigCtrl,
|
||||
ElasticQueryOptionsCtrl as QueryOptionsCtrl,
|
||||
ElasticAnnotationsQueryCtrl as AnnotationsQueryCtrl,
|
||||
};
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import { describe, beforeEach, it, expect } from 'test/lib/common';
|
||||
import { ElasticResponse } from '../elastic_response';
|
||||
|
||||
describe('ElasticResponse', function() {
|
||||
describe('ElasticResponse', () => {
|
||||
var targets;
|
||||
var response;
|
||||
var result;
|
||||
|
||||
describe('simple query and count', function() {
|
||||
beforeEach(function() {
|
||||
describe('simple query and count', () => {
|
||||
beforeEach(() => {
|
||||
targets = [
|
||||
{
|
||||
refId: 'A',
|
||||
@@ -39,19 +38,19 @@ describe('ElasticResponse', function() {
|
||||
result = new ElasticResponse(targets, response).getTimeSeries();
|
||||
});
|
||||
|
||||
it('should return 1 series', function() {
|
||||
expect(result.data.length).to.be(1);
|
||||
expect(result.data[0].target).to.be('Count');
|
||||
expect(result.data[0].datapoints.length).to.be(2);
|
||||
expect(result.data[0].datapoints[0][0]).to.be(10);
|
||||
expect(result.data[0].datapoints[0][1]).to.be(1000);
|
||||
it('should return 1 series', () => {
|
||||
expect(result.data.length).toBe(1);
|
||||
expect(result.data[0].target).toBe('Count');
|
||||
expect(result.data[0].datapoints.length).toBe(2);
|
||||
expect(result.data[0].datapoints[0][0]).toBe(10);
|
||||
expect(result.data[0].datapoints[0][1]).toBe(1000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('simple query count & avg aggregation', function() {
|
||||
describe('simple query count & avg aggregation', () => {
|
||||
var result;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(() => {
|
||||
targets = [
|
||||
{
|
||||
refId: 'A',
|
||||
@@ -85,22 +84,22 @@ describe('ElasticResponse', function() {
|
||||
result = new ElasticResponse(targets, response).getTimeSeries();
|
||||
});
|
||||
|
||||
it('should return 2 series', function() {
|
||||
expect(result.data.length).to.be(2);
|
||||
expect(result.data[0].datapoints.length).to.be(2);
|
||||
expect(result.data[0].datapoints[0][0]).to.be(10);
|
||||
expect(result.data[0].datapoints[0][1]).to.be(1000);
|
||||
it('should return 2 series', () => {
|
||||
expect(result.data.length).toBe(2);
|
||||
expect(result.data[0].datapoints.length).toBe(2);
|
||||
expect(result.data[0].datapoints[0][0]).toBe(10);
|
||||
expect(result.data[0].datapoints[0][1]).toBe(1000);
|
||||
|
||||
expect(result.data[1].target).to.be('Average value');
|
||||
expect(result.data[1].datapoints[0][0]).to.be(88);
|
||||
expect(result.data[1].datapoints[1][0]).to.be(99);
|
||||
expect(result.data[1].target).toBe('Average value');
|
||||
expect(result.data[1].datapoints[0][0]).toBe(88);
|
||||
expect(result.data[1].datapoints[1][0]).toBe(99);
|
||||
});
|
||||
});
|
||||
|
||||
describe('single group by query one metric', function() {
|
||||
describe('single group by query one metric', () => {
|
||||
var result;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(() => {
|
||||
targets = [
|
||||
{
|
||||
refId: 'A',
|
||||
@@ -141,18 +140,18 @@ describe('ElasticResponse', function() {
|
||||
result = new ElasticResponse(targets, response).getTimeSeries();
|
||||
});
|
||||
|
||||
it('should return 2 series', function() {
|
||||
expect(result.data.length).to.be(2);
|
||||
expect(result.data[0].datapoints.length).to.be(2);
|
||||
expect(result.data[0].target).to.be('server1');
|
||||
expect(result.data[1].target).to.be('server2');
|
||||
it('should return 2 series', () => {
|
||||
expect(result.data.length).toBe(2);
|
||||
expect(result.data[0].datapoints.length).toBe(2);
|
||||
expect(result.data[0].target).toBe('server1');
|
||||
expect(result.data[1].target).toBe('server2');
|
||||
});
|
||||
});
|
||||
|
||||
describe('single group by query two metrics', function() {
|
||||
describe('single group by query two metrics', () => {
|
||||
var result;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(() => {
|
||||
targets = [
|
||||
{
|
||||
refId: 'A',
|
||||
@@ -199,20 +198,20 @@ describe('ElasticResponse', function() {
|
||||
result = new ElasticResponse(targets, response).getTimeSeries();
|
||||
});
|
||||
|
||||
it('should return 2 series', function() {
|
||||
expect(result.data.length).to.be(4);
|
||||
expect(result.data[0].datapoints.length).to.be(2);
|
||||
expect(result.data[0].target).to.be('server1 Count');
|
||||
expect(result.data[1].target).to.be('server1 Average @value');
|
||||
expect(result.data[2].target).to.be('server2 Count');
|
||||
expect(result.data[3].target).to.be('server2 Average @value');
|
||||
it('should return 2 series', () => {
|
||||
expect(result.data.length).toBe(4);
|
||||
expect(result.data[0].datapoints.length).toBe(2);
|
||||
expect(result.data[0].target).toBe('server1 Count');
|
||||
expect(result.data[1].target).toBe('server1 Average @value');
|
||||
expect(result.data[2].target).toBe('server2 Count');
|
||||
expect(result.data[3].target).toBe('server2 Average @value');
|
||||
});
|
||||
});
|
||||
|
||||
describe('with percentiles ', function() {
|
||||
describe('with percentiles ', () => {
|
||||
var result;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(() => {
|
||||
targets = [
|
||||
{
|
||||
refId: 'A',
|
||||
@@ -246,21 +245,21 @@ describe('ElasticResponse', function() {
|
||||
result = new ElasticResponse(targets, response).getTimeSeries();
|
||||
});
|
||||
|
||||
it('should return 2 series', function() {
|
||||
expect(result.data.length).to.be(2);
|
||||
expect(result.data[0].datapoints.length).to.be(2);
|
||||
expect(result.data[0].target).to.be('p75');
|
||||
expect(result.data[1].target).to.be('p90');
|
||||
expect(result.data[0].datapoints[0][0]).to.be(3.3);
|
||||
expect(result.data[0].datapoints[0][1]).to.be(1000);
|
||||
expect(result.data[1].datapoints[1][0]).to.be(4.5);
|
||||
it('should return 2 series', () => {
|
||||
expect(result.data.length).toBe(2);
|
||||
expect(result.data[0].datapoints.length).toBe(2);
|
||||
expect(result.data[0].target).toBe('p75');
|
||||
expect(result.data[1].target).toBe('p90');
|
||||
expect(result.data[0].datapoints[0][0]).toBe(3.3);
|
||||
expect(result.data[0].datapoints[0][1]).toBe(1000);
|
||||
expect(result.data[1].datapoints[1][0]).toBe(4.5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with extended_stats', function() {
|
||||
describe('with extended_stats', () => {
|
||||
var result;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(() => {
|
||||
targets = [
|
||||
{
|
||||
refId: 'A',
|
||||
@@ -322,21 +321,21 @@ describe('ElasticResponse', function() {
|
||||
result = new ElasticResponse(targets, response).getTimeSeries();
|
||||
});
|
||||
|
||||
it('should return 4 series', function() {
|
||||
expect(result.data.length).to.be(4);
|
||||
expect(result.data[0].datapoints.length).to.be(1);
|
||||
expect(result.data[0].target).to.be('server1 Max');
|
||||
expect(result.data[1].target).to.be('server1 Std Dev Upper');
|
||||
it('should return 4 series', () => {
|
||||
expect(result.data.length).toBe(4);
|
||||
expect(result.data[0].datapoints.length).toBe(1);
|
||||
expect(result.data[0].target).toBe('server1 Max');
|
||||
expect(result.data[1].target).toBe('server1 Std Dev Upper');
|
||||
|
||||
expect(result.data[0].datapoints[0][0]).to.be(10.2);
|
||||
expect(result.data[1].datapoints[0][0]).to.be(3);
|
||||
expect(result.data[0].datapoints[0][0]).toBe(10.2);
|
||||
expect(result.data[1].datapoints[0][0]).toBe(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('single group by with alias pattern', function() {
|
||||
describe('single group by with alias pattern', () => {
|
||||
var result;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(() => {
|
||||
targets = [
|
||||
{
|
||||
refId: 'A',
|
||||
@@ -385,19 +384,19 @@ describe('ElasticResponse', function() {
|
||||
result = new ElasticResponse(targets, response).getTimeSeries();
|
||||
});
|
||||
|
||||
it('should return 2 series', function() {
|
||||
expect(result.data.length).to.be(3);
|
||||
expect(result.data[0].datapoints.length).to.be(2);
|
||||
expect(result.data[0].target).to.be('server1 Count and {{not_exist}} server1');
|
||||
expect(result.data[1].target).to.be('server2 Count and {{not_exist}} server2');
|
||||
expect(result.data[2].target).to.be('0 Count and {{not_exist}} 0');
|
||||
it('should return 2 series', () => {
|
||||
expect(result.data.length).toBe(3);
|
||||
expect(result.data[0].datapoints.length).toBe(2);
|
||||
expect(result.data[0].target).toBe('server1 Count and {{not_exist}} server1');
|
||||
expect(result.data[1].target).toBe('server2 Count and {{not_exist}} server2');
|
||||
expect(result.data[2].target).toBe('0 Count and {{not_exist}} 0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('histogram response', function() {
|
||||
describe('histogram response', () => {
|
||||
var result;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(() => {
|
||||
targets = [
|
||||
{
|
||||
refId: 'A',
|
||||
@@ -420,16 +419,16 @@ describe('ElasticResponse', function() {
|
||||
result = new ElasticResponse(targets, response).getTimeSeries();
|
||||
});
|
||||
|
||||
it('should return table with byte and count', function() {
|
||||
expect(result.data[0].rows.length).to.be(3);
|
||||
expect(result.data[0].columns).to.eql([{ text: 'bytes', filterable: true }, { text: 'Count' }]);
|
||||
it('should return table with byte and count', () => {
|
||||
expect(result.data[0].rows.length).toBe(3);
|
||||
expect(result.data[0].columns).toEqual([{ text: 'bytes', filterable: true }, { text: 'Count' }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with two filters agg', function() {
|
||||
describe('with two filters agg', () => {
|
||||
var result;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(() => {
|
||||
targets = [
|
||||
{
|
||||
refId: 'A',
|
||||
@@ -472,16 +471,16 @@ describe('ElasticResponse', function() {
|
||||
result = new ElasticResponse(targets, response).getTimeSeries();
|
||||
});
|
||||
|
||||
it('should return 2 series', function() {
|
||||
expect(result.data.length).to.be(2);
|
||||
expect(result.data[0].datapoints.length).to.be(2);
|
||||
expect(result.data[0].target).to.be('@metric:cpu');
|
||||
expect(result.data[1].target).to.be('@metric:logins.count');
|
||||
it('should return 2 series', () => {
|
||||
expect(result.data.length).toBe(2);
|
||||
expect(result.data[0].datapoints.length).toBe(2);
|
||||
expect(result.data[0].target).toBe('@metric:cpu');
|
||||
expect(result.data[1].target).toBe('@metric:logins.count');
|
||||
});
|
||||
});
|
||||
|
||||
describe('with dropfirst and last aggregation', function() {
|
||||
beforeEach(function() {
|
||||
describe('with dropfirst and last aggregation', () => {
|
||||
beforeEach(() => {
|
||||
targets = [
|
||||
{
|
||||
refId: 'A',
|
||||
@@ -528,14 +527,14 @@ describe('ElasticResponse', function() {
|
||||
result = new ElasticResponse(targets, response).getTimeSeries();
|
||||
});
|
||||
|
||||
it('should remove first and last value', function() {
|
||||
expect(result.data.length).to.be(2);
|
||||
expect(result.data[0].datapoints.length).to.be(1);
|
||||
it('should remove first and last value', () => {
|
||||
expect(result.data.length).toBe(2);
|
||||
expect(result.data[0].datapoints.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('No group by time', function() {
|
||||
beforeEach(function() {
|
||||
describe('No group by time', () => {
|
||||
beforeEach(() => {
|
||||
targets = [
|
||||
{
|
||||
refId: 'A',
|
||||
@@ -570,21 +569,21 @@ describe('ElasticResponse', function() {
|
||||
result = new ElasticResponse(targets, response).getTimeSeries();
|
||||
});
|
||||
|
||||
it('should return table', function() {
|
||||
expect(result.data.length).to.be(1);
|
||||
expect(result.data[0].type).to.be('table');
|
||||
expect(result.data[0].rows.length).to.be(2);
|
||||
expect(result.data[0].rows[0][0]).to.be('server-1');
|
||||
expect(result.data[0].rows[0][1]).to.be(1000);
|
||||
expect(result.data[0].rows[0][2]).to.be(369);
|
||||
it('should return table', () => {
|
||||
expect(result.data.length).toBe(1);
|
||||
expect(result.data[0].type).toBe('table');
|
||||
expect(result.data[0].rows.length).toBe(2);
|
||||
expect(result.data[0].rows[0][0]).toBe('server-1');
|
||||
expect(result.data[0].rows[0][1]).toBe(1000);
|
||||
expect(result.data[0].rows[0][2]).toBe(369);
|
||||
|
||||
expect(result.data[0].rows[1][0]).to.be('server-2');
|
||||
expect(result.data[0].rows[1][1]).to.be(2000);
|
||||
expect(result.data[0].rows[1][0]).toBe('server-2');
|
||||
expect(result.data[0].rows[1][1]).toBe(2000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Multiple metrics of same type', function() {
|
||||
beforeEach(function() {
|
||||
describe('Multiple metrics of same type', () => {
|
||||
beforeEach(() => {
|
||||
targets = [
|
||||
{
|
||||
refId: 'A',
|
||||
@@ -615,15 +614,15 @@ describe('ElasticResponse', function() {
|
||||
result = new ElasticResponse(targets, response).getTimeSeries();
|
||||
});
|
||||
|
||||
it('should include field in metric name', function() {
|
||||
expect(result.data[0].type).to.be('table');
|
||||
expect(result.data[0].rows[0][1]).to.be(1000);
|
||||
expect(result.data[0].rows[0][2]).to.be(3000);
|
||||
it('should include field in metric name', () => {
|
||||
expect(result.data[0].type).toBe('table');
|
||||
expect(result.data[0].rows[0][1]).toBe(1000);
|
||||
expect(result.data[0].rows[0][2]).toBe(3000);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Raw documents query', function() {
|
||||
beforeEach(function() {
|
||||
describe('Raw documents query', () => {
|
||||
beforeEach(() => {
|
||||
targets = [
|
||||
{
|
||||
refId: 'A',
|
||||
@@ -657,13 +656,13 @@ describe('ElasticResponse', function() {
|
||||
result = new ElasticResponse(targets, response).getTimeSeries();
|
||||
});
|
||||
|
||||
it('should return docs', function() {
|
||||
expect(result.data.length).to.be(1);
|
||||
expect(result.data[0].type).to.be('docs');
|
||||
expect(result.data[0].total).to.be(100);
|
||||
expect(result.data[0].datapoints.length).to.be(2);
|
||||
expect(result.data[0].datapoints[0].sourceProp).to.be('asd');
|
||||
expect(result.data[0].datapoints[0].fieldProp).to.be('field');
|
||||
it('should return docs', () => {
|
||||
expect(result.data.length).toBe(1);
|
||||
expect(result.data[0].type).toBe('docs');
|
||||
expect(result.data[0].total).toBe(100);
|
||||
expect(result.data[0].datapoints.length).toBe(2);
|
||||
expect(result.data[0].datapoints[0].sourceProp).toBe('asd');
|
||||
expect(result.data[0].datapoints[0].fieldProp).toBe('field');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,38 +1,37 @@
|
||||
///<amd-dependency path="test/specs/helpers" name="helpers" />
|
||||
|
||||
import { describe, it, expect } from 'test/lib/common';
|
||||
import moment from 'moment';
|
||||
import { IndexPattern } from '../index_pattern';
|
||||
|
||||
describe('IndexPattern', function() {
|
||||
describe('when getting index for today', function() {
|
||||
it('should return correct index name', function() {
|
||||
describe('IndexPattern', () => {
|
||||
describe('when getting index for today', () => {
|
||||
test('should return correct index name', () => {
|
||||
var pattern = new IndexPattern('[asd-]YYYY.MM.DD', 'Daily');
|
||||
var expected = 'asd-' + moment.utc().format('YYYY.MM.DD');
|
||||
|
||||
expect(pattern.getIndexForToday()).to.be(expected);
|
||||
expect(pattern.getIndexForToday()).toBe(expected);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when getting index list for time range', function() {
|
||||
describe('no interval', function() {
|
||||
it('should return correct index', function() {
|
||||
describe('when getting index list for time range', () => {
|
||||
describe('no interval', () => {
|
||||
test('should return correct index', () => {
|
||||
var pattern = new IndexPattern('my-metrics', null);
|
||||
var from = new Date(2015, 4, 30, 1, 2, 3);
|
||||
var to = new Date(2015, 5, 1, 12, 5, 6);
|
||||
expect(pattern.getIndexList(from, to)).to.eql('my-metrics');
|
||||
expect(pattern.getIndexList(from, to)).toEqual('my-metrics');
|
||||
});
|
||||
});
|
||||
|
||||
describe('daily', function() {
|
||||
it('should return correct index list', function() {
|
||||
describe('daily', () => {
|
||||
test('should return correct index list', () => {
|
||||
var pattern = new IndexPattern('[asd-]YYYY.MM.DD', 'Daily');
|
||||
var from = new Date(1432940523000);
|
||||
var to = new Date(1433153106000);
|
||||
|
||||
var expected = ['asd-2015.05.29', 'asd-2015.05.30', 'asd-2015.05.31', 'asd-2015.06.01'];
|
||||
|
||||
expect(pattern.getIndexList(from, to)).to.eql(expected);
|
||||
expect(pattern.getIndexList(from, to)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,25 +1,24 @@
|
||||
import { describe, beforeEach, it, expect } from 'test/lib/common';
|
||||
import { ElasticQueryBuilder } from '../query_builder';
|
||||
|
||||
describe('ElasticQueryBuilder', function() {
|
||||
describe('ElasticQueryBuilder', () => {
|
||||
var builder;
|
||||
|
||||
beforeEach(function() {
|
||||
beforeEach(() => {
|
||||
builder = new ElasticQueryBuilder({ timeField: '@timestamp' });
|
||||
});
|
||||
|
||||
it('with defaults', function() {
|
||||
it('with defaults', () => {
|
||||
var query = builder.build({
|
||||
metrics: [{ type: 'Count', id: '0' }],
|
||||
timeField: '@timestamp',
|
||||
bucketAggs: [{ type: 'date_histogram', field: '@timestamp', id: '1' }],
|
||||
});
|
||||
|
||||
expect(query.query.bool.filter[0].range['@timestamp'].gte).to.be('$timeFrom');
|
||||
expect(query.aggs['1'].date_histogram.extended_bounds.min).to.be('$timeFrom');
|
||||
expect(query.query.bool.filter[0].range['@timestamp'].gte).toBe('$timeFrom');
|
||||
expect(query.aggs['1'].date_histogram.extended_bounds.min).toBe('$timeFrom');
|
||||
});
|
||||
|
||||
it('with defaults on es5.x', function() {
|
||||
it('with defaults on es5.x', () => {
|
||||
var builder_5x = new ElasticQueryBuilder({
|
||||
timeField: '@timestamp',
|
||||
esVersion: 5,
|
||||
@@ -31,11 +30,11 @@ describe('ElasticQueryBuilder', function() {
|
||||
bucketAggs: [{ type: 'date_histogram', field: '@timestamp', id: '1' }],
|
||||
});
|
||||
|
||||
expect(query.query.bool.filter[0].range['@timestamp'].gte).to.be('$timeFrom');
|
||||
expect(query.aggs['1'].date_histogram.extended_bounds.min).to.be('$timeFrom');
|
||||
expect(query.query.bool.filter[0].range['@timestamp'].gte).toBe('$timeFrom');
|
||||
expect(query.aggs['1'].date_histogram.extended_bounds.min).toBe('$timeFrom');
|
||||
});
|
||||
|
||||
it('with multiple bucket aggs', function() {
|
||||
it('with multiple bucket aggs', () => {
|
||||
var query = builder.build({
|
||||
metrics: [{ type: 'count', id: '1' }],
|
||||
timeField: '@timestamp',
|
||||
@@ -45,11 +44,11 @@ describe('ElasticQueryBuilder', function() {
|
||||
],
|
||||
});
|
||||
|
||||
expect(query.aggs['2'].terms.field).to.be('@host');
|
||||
expect(query.aggs['2'].aggs['3'].date_histogram.field).to.be('@timestamp');
|
||||
expect(query.aggs['2'].terms.field).toBe('@host');
|
||||
expect(query.aggs['2'].aggs['3'].date_histogram.field).toBe('@timestamp');
|
||||
});
|
||||
|
||||
it('with select field', function() {
|
||||
it('with select field', () => {
|
||||
var query = builder.build(
|
||||
{
|
||||
metrics: [{ type: 'avg', field: '@value', id: '1' }],
|
||||
@@ -60,10 +59,10 @@ describe('ElasticQueryBuilder', function() {
|
||||
);
|
||||
|
||||
var aggs = query.aggs['2'].aggs;
|
||||
expect(aggs['1'].avg.field).to.be('@value');
|
||||
expect(aggs['1'].avg.field).toBe('@value');
|
||||
});
|
||||
|
||||
it('with term agg and order by metric agg', function() {
|
||||
it('with term agg and order by metric agg', () => {
|
||||
var query = builder.build(
|
||||
{
|
||||
metrics: [{ type: 'count', id: '1' }, { type: 'avg', field: '@value', id: '5' }],
|
||||
@@ -84,11 +83,11 @@ describe('ElasticQueryBuilder', function() {
|
||||
var firstLevel = query.aggs['2'];
|
||||
var secondLevel = firstLevel.aggs['3'];
|
||||
|
||||
expect(firstLevel.aggs['5'].avg.field).to.be('@value');
|
||||
expect(secondLevel.aggs['5'].avg.field).to.be('@value');
|
||||
expect(firstLevel.aggs['5'].avg.field).toBe('@value');
|
||||
expect(secondLevel.aggs['5'].avg.field).toBe('@value');
|
||||
});
|
||||
|
||||
it('with metric percentiles', function() {
|
||||
it('with metric percentiles', () => {
|
||||
var query = builder.build(
|
||||
{
|
||||
metrics: [
|
||||
@@ -109,11 +108,11 @@ describe('ElasticQueryBuilder', function() {
|
||||
|
||||
var firstLevel = query.aggs['3'];
|
||||
|
||||
expect(firstLevel.aggs['1'].percentiles.field).to.be('@load_time');
|
||||
expect(firstLevel.aggs['1'].percentiles.percents).to.eql([1, 2, 3, 4]);
|
||||
expect(firstLevel.aggs['1'].percentiles.field).toBe('@load_time');
|
||||
expect(firstLevel.aggs['1'].percentiles.percents).toEqual([1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
it('with filters aggs', function() {
|
||||
it('with filters aggs', () => {
|
||||
var query = builder.build({
|
||||
metrics: [{ type: 'count', id: '1' }],
|
||||
timeField: '@timestamp',
|
||||
@@ -129,12 +128,12 @@ describe('ElasticQueryBuilder', function() {
|
||||
],
|
||||
});
|
||||
|
||||
expect(query.aggs['2'].filters.filters['@metric:cpu'].query_string.query).to.be('@metric:cpu');
|
||||
expect(query.aggs['2'].filters.filters['@metric:logins.count'].query_string.query).to.be('@metric:logins.count');
|
||||
expect(query.aggs['2'].aggs['4'].date_histogram.field).to.be('@timestamp');
|
||||
expect(query.aggs['2'].filters.filters['@metric:cpu'].query_string.query).toBe('@metric:cpu');
|
||||
expect(query.aggs['2'].filters.filters['@metric:logins.count'].query_string.query).toBe('@metric:logins.count');
|
||||
expect(query.aggs['2'].aggs['4'].date_histogram.field).toBe('@timestamp');
|
||||
});
|
||||
|
||||
it('with filters aggs on es5.x', function() {
|
||||
it('with filters aggs on es5.x', () => {
|
||||
var builder_5x = new ElasticQueryBuilder({
|
||||
timeField: '@timestamp',
|
||||
esVersion: 5,
|
||||
@@ -154,31 +153,31 @@ describe('ElasticQueryBuilder', function() {
|
||||
],
|
||||
});
|
||||
|
||||
expect(query.aggs['2'].filters.filters['@metric:cpu'].query_string.query).to.be('@metric:cpu');
|
||||
expect(query.aggs['2'].filters.filters['@metric:logins.count'].query_string.query).to.be('@metric:logins.count');
|
||||
expect(query.aggs['2'].aggs['4'].date_histogram.field).to.be('@timestamp');
|
||||
expect(query.aggs['2'].filters.filters['@metric:cpu'].query_string.query).toBe('@metric:cpu');
|
||||
expect(query.aggs['2'].filters.filters['@metric:logins.count'].query_string.query).toBe('@metric:logins.count');
|
||||
expect(query.aggs['2'].aggs['4'].date_histogram.field).toBe('@timestamp');
|
||||
});
|
||||
|
||||
it('with raw_document metric', function() {
|
||||
it('with raw_document metric', () => {
|
||||
var query = builder.build({
|
||||
metrics: [{ type: 'raw_document', id: '1', settings: {} }],
|
||||
timeField: '@timestamp',
|
||||
bucketAggs: [],
|
||||
});
|
||||
|
||||
expect(query.size).to.be(500);
|
||||
expect(query.size).toBe(500);
|
||||
});
|
||||
it('with raw_document metric size set', function() {
|
||||
it('with raw_document metric size set', () => {
|
||||
var query = builder.build({
|
||||
metrics: [{ type: 'raw_document', id: '1', settings: { size: 1337 } }],
|
||||
timeField: '@timestamp',
|
||||
bucketAggs: [],
|
||||
});
|
||||
|
||||
expect(query.size).to.be(1337);
|
||||
expect(query.size).toBe(1337);
|
||||
});
|
||||
|
||||
it('with moving average', function() {
|
||||
it('with moving average', () => {
|
||||
var query = builder.build({
|
||||
metrics: [
|
||||
{
|
||||
@@ -198,12 +197,12 @@ describe('ElasticQueryBuilder', function() {
|
||||
|
||||
var firstLevel = query.aggs['3'];
|
||||
|
||||
expect(firstLevel.aggs['2']).not.to.be(undefined);
|
||||
expect(firstLevel.aggs['2'].moving_avg).not.to.be(undefined);
|
||||
expect(firstLevel.aggs['2'].moving_avg.buckets_path).to.be('3');
|
||||
expect(firstLevel.aggs['2']).not.toBe(undefined);
|
||||
expect(firstLevel.aggs['2'].moving_avg).not.toBe(undefined);
|
||||
expect(firstLevel.aggs['2'].moving_avg.buckets_path).toBe('3');
|
||||
});
|
||||
|
||||
it('with broken moving average', function() {
|
||||
it('with broken moving average', () => {
|
||||
var query = builder.build({
|
||||
metrics: [
|
||||
{
|
||||
@@ -227,13 +226,13 @@ describe('ElasticQueryBuilder', function() {
|
||||
|
||||
var firstLevel = query.aggs['3'];
|
||||
|
||||
expect(firstLevel.aggs['2']).not.to.be(undefined);
|
||||
expect(firstLevel.aggs['2'].moving_avg).not.to.be(undefined);
|
||||
expect(firstLevel.aggs['2'].moving_avg.buckets_path).to.be('3');
|
||||
expect(firstLevel.aggs['4']).to.be(undefined);
|
||||
expect(firstLevel.aggs['2']).not.toBe(undefined);
|
||||
expect(firstLevel.aggs['2'].moving_avg).not.toBe(undefined);
|
||||
expect(firstLevel.aggs['2'].moving_avg.buckets_path).toBe('3');
|
||||
expect(firstLevel.aggs['4']).toBe(undefined);
|
||||
});
|
||||
|
||||
it('with derivative', function() {
|
||||
it('with derivative', () => {
|
||||
var query = builder.build({
|
||||
metrics: [
|
||||
{
|
||||
@@ -252,12 +251,12 @@ describe('ElasticQueryBuilder', function() {
|
||||
|
||||
var firstLevel = query.aggs['3'];
|
||||
|
||||
expect(firstLevel.aggs['2']).not.to.be(undefined);
|
||||
expect(firstLevel.aggs['2'].derivative).not.to.be(undefined);
|
||||
expect(firstLevel.aggs['2'].derivative.buckets_path).to.be('3');
|
||||
expect(firstLevel.aggs['2']).not.toBe(undefined);
|
||||
expect(firstLevel.aggs['2'].derivative).not.toBe(undefined);
|
||||
expect(firstLevel.aggs['2'].derivative.buckets_path).toBe('3');
|
||||
});
|
||||
|
||||
it('with histogram', function() {
|
||||
it('with histogram', () => {
|
||||
var query = builder.build({
|
||||
metrics: [{ id: '1', type: 'count' }],
|
||||
bucketAggs: [
|
||||
@@ -271,13 +270,13 @@ describe('ElasticQueryBuilder', function() {
|
||||
});
|
||||
|
||||
var firstLevel = query.aggs['3'];
|
||||
expect(firstLevel.histogram.field).to.be('bytes');
|
||||
expect(firstLevel.histogram.interval).to.be(10);
|
||||
expect(firstLevel.histogram.min_doc_count).to.be(2);
|
||||
expect(firstLevel.histogram.missing).to.be(5);
|
||||
expect(firstLevel.histogram.field).toBe('bytes');
|
||||
expect(firstLevel.histogram.interval).toBe(10);
|
||||
expect(firstLevel.histogram.min_doc_count).toBe(2);
|
||||
expect(firstLevel.histogram.missing).toBe(5);
|
||||
});
|
||||
|
||||
it('with adhoc filters', function() {
|
||||
it('with adhoc filters', () => {
|
||||
var query = builder.build(
|
||||
{
|
||||
metrics: [{ type: 'Count', id: '0' }],
|
||||
@@ -295,12 +294,12 @@ describe('ElasticQueryBuilder', function() {
|
||||
]
|
||||
);
|
||||
|
||||
expect(query.query.bool.must[0].match_phrase['key1'].query).to.be('value1');
|
||||
expect(query.query.bool.must[1].match_phrase['key2'].query).to.be('value2');
|
||||
expect(query.query.bool.must_not[0].match_phrase['key2'].query).to.be('value2');
|
||||
expect(query.query.bool.filter[2].range['key3'].lt).to.be('value3');
|
||||
expect(query.query.bool.filter[3].range['key4'].gt).to.be('value4');
|
||||
expect(query.query.bool.filter[4].regexp['key5']).to.be('value5');
|
||||
expect(query.query.bool.filter[5].bool.must_not.regexp['key6']).to.be('value6');
|
||||
expect(query.query.bool.must[0].match_phrase['key1'].query).toBe('value1');
|
||||
expect(query.query.bool.must[1].match_phrase['key2'].query).toBe('value2');
|
||||
expect(query.query.bool.must_not[0].match_phrase['key2'].query).toBe('value2');
|
||||
expect(query.query.bool.filter[2].range['key3'].lt).toBe('value3');
|
||||
expect(query.query.bool.filter[3].range['key4'].gt).toBe('value4');
|
||||
expect(query.query.bool.filter[4].regexp['key5']).toBe('value5');
|
||||
expect(query.query.bool.filter[5].bool.must_not.regexp['key6']).toBe('value6');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,93 @@
|
||||
import * as queryDef from '../query_def';
|
||||
|
||||
describe('ElasticQueryDef', () => {
|
||||
describe('getPipelineAggOptions', () => {
|
||||
describe('with zero targets', () => {
|
||||
var response = queryDef.getPipelineAggOptions([]);
|
||||
|
||||
test('should return zero', () => {
|
||||
expect(response.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with count and sum targets', () => {
|
||||
var targets = {
|
||||
metrics: [{ type: 'count', field: '@value' }, { type: 'sum', field: '@value' }],
|
||||
};
|
||||
|
||||
var response = queryDef.getPipelineAggOptions(targets);
|
||||
|
||||
test('should return zero', () => {
|
||||
expect(response.length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with count and moving average targets', () => {
|
||||
var targets = {
|
||||
metrics: [{ type: 'count', field: '@value' }, { type: 'moving_avg', field: '@value' }],
|
||||
};
|
||||
|
||||
var response = queryDef.getPipelineAggOptions(targets);
|
||||
|
||||
test('should return one', () => {
|
||||
expect(response.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with derivatives targets', () => {
|
||||
var targets = {
|
||||
metrics: [{ type: 'derivative', field: '@value' }],
|
||||
};
|
||||
|
||||
var response = queryDef.getPipelineAggOptions(targets);
|
||||
|
||||
test('should return zero', () => {
|
||||
expect(response.length).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isPipelineMetric', () => {
|
||||
describe('moving_avg', () => {
|
||||
var result = queryDef.isPipelineAgg('moving_avg');
|
||||
|
||||
test('is pipe line metric', () => {
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('count', () => {
|
||||
var result = queryDef.isPipelineAgg('count');
|
||||
|
||||
test('is not pipe line metric', () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('pipeline aggs depending on esverison', () => {
|
||||
describe('using esversion undefined', () => {
|
||||
test('should not get pipeline aggs', () => {
|
||||
expect(queryDef.getMetricAggTypes(undefined).length).toBe(9);
|
||||
});
|
||||
});
|
||||
|
||||
describe('using esversion 1', () => {
|
||||
test('should not get pipeline aggs', () => {
|
||||
expect(queryDef.getMetricAggTypes(1).length).toBe(9);
|
||||
});
|
||||
});
|
||||
|
||||
describe('using esversion 2', () => {
|
||||
test('should get pipeline aggs', () => {
|
||||
expect(queryDef.getMetricAggTypes(2).length).toBe(11);
|
||||
});
|
||||
});
|
||||
|
||||
describe('using esversion 5', () => {
|
||||
test('should get pipeline aggs', () => {
|
||||
expect(queryDef.getMetricAggTypes(5).length).toBe(11);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,95 +0,0 @@
|
||||
import { describe, it, expect } from 'test/lib/common';
|
||||
|
||||
import * as queryDef from '../query_def';
|
||||
|
||||
describe('ElasticQueryDef', function() {
|
||||
describe('getPipelineAggOptions', function() {
|
||||
describe('with zero targets', function() {
|
||||
var response = queryDef.getPipelineAggOptions([]);
|
||||
|
||||
it('should return zero', function() {
|
||||
expect(response.length).to.be(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with count and sum targets', function() {
|
||||
var targets = {
|
||||
metrics: [{ type: 'count', field: '@value' }, { type: 'sum', field: '@value' }],
|
||||
};
|
||||
|
||||
var response = queryDef.getPipelineAggOptions(targets);
|
||||
|
||||
it('should return zero', function() {
|
||||
expect(response.length).to.be(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with count and moving average targets', function() {
|
||||
var targets = {
|
||||
metrics: [{ type: 'count', field: '@value' }, { type: 'moving_avg', field: '@value' }],
|
||||
};
|
||||
|
||||
var response = queryDef.getPipelineAggOptions(targets);
|
||||
|
||||
it('should return one', function() {
|
||||
expect(response.length).to.be(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with derivatives targets', function() {
|
||||
var targets = {
|
||||
metrics: [{ type: 'derivative', field: '@value' }],
|
||||
};
|
||||
|
||||
var response = queryDef.getPipelineAggOptions(targets);
|
||||
|
||||
it('should return zero', function() {
|
||||
expect(response.length).to.be(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isPipelineMetric', function() {
|
||||
describe('moving_avg', function() {
|
||||
var result = queryDef.isPipelineAgg('moving_avg');
|
||||
|
||||
it('is pipe line metric', function() {
|
||||
expect(result).to.be(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('count', function() {
|
||||
var result = queryDef.isPipelineAgg('count');
|
||||
|
||||
it('is not pipe line metric', function() {
|
||||
expect(result).to.be(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('pipeline aggs depending on esverison', function() {
|
||||
describe('using esversion undefined', function() {
|
||||
it('should not get pipeline aggs', function() {
|
||||
expect(queryDef.getMetricAggTypes(undefined).length).to.be(9);
|
||||
});
|
||||
});
|
||||
|
||||
describe('using esversion 1', function() {
|
||||
it('should not get pipeline aggs', function() {
|
||||
expect(queryDef.getMetricAggTypes(1).length).to.be(9);
|
||||
});
|
||||
});
|
||||
|
||||
describe('using esversion 2', function() {
|
||||
it('should get pipeline aggs', function() {
|
||||
expect(queryDef.getMetricAggTypes(2).length).to.be(11);
|
||||
});
|
||||
});
|
||||
|
||||
describe('using esversion 5', function() {
|
||||
it('should get pipeline aggs', function() {
|
||||
expect(queryDef.getMetricAggTypes(5).length).to.be(11);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,26 +0,0 @@
|
||||
# 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
|
||||
@@ -1,233 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<?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>
|
||||
|
Before Width: | Height: | Size: 1.9 KiB |
@@ -1,17 +0,0 @@
|
||||
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,
|
||||
};
|
||||
@@ -1,24 +0,0 @@
|
||||
|
||||
<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>
|
||||
@@ -1,24 +0,0 @@
|
||||
<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>
|
||||
@@ -1,24 +0,0 @@
|
||||
<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>
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
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;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
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})`);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,63 +0,0 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,349 +0,0 @@
|
||||
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;
|
||||
@@ -1,4 +1,3 @@
|
||||
import { describe, it, expect } from 'test/lib/common';
|
||||
import { InfluxQueryBuilder } from '../query_builder';
|
||||
|
||||
describe('InfluxQueryBuilder', function() {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { describe, beforeEach, it, sinon, expect } from '../../../../../test/lib/common';
|
||||
jest.mock('app/core/core', () => ({}));
|
||||
|
||||
import $ from 'jquery';
|
||||
import GraphTooltip from '../graph_tooltip';
|
||||
|
||||
var scope = {
|
||||
appEvent: sinon.spy(),
|
||||
onAppEvent: sinon.spy(),
|
||||
appEvent: jest.fn(),
|
||||
onAppEvent: jest.fn(),
|
||||
ctrl: {},
|
||||
};
|
||||
|
||||
@@ -47,22 +47,22 @@ describe('findHoverIndexFromData', function() {
|
||||
|
||||
it('should return 0 if posX out of lower bounds', function() {
|
||||
var posX = 99;
|
||||
expect(tooltip.findHoverIndexFromData(posX, series)).to.be(0);
|
||||
expect(tooltip.findHoverIndexFromData(posX, series)).toBe(0);
|
||||
});
|
||||
|
||||
it('should return n - 1 if posX out of upper bounds', function() {
|
||||
var posX = 108;
|
||||
expect(tooltip.findHoverIndexFromData(posX, series)).to.be(series.data.length - 1);
|
||||
expect(tooltip.findHoverIndexFromData(posX, series)).toBe(series.data.length - 1);
|
||||
});
|
||||
|
||||
it('should return i if posX in series', function() {
|
||||
var posX = 104;
|
||||
expect(tooltip.findHoverIndexFromData(posX, series)).to.be(4);
|
||||
expect(tooltip.findHoverIndexFromData(posX, series)).toBe(4);
|
||||
});
|
||||
|
||||
it('should return i if posX not in series and i + 1 > posX', function() {
|
||||
var posX = 104.9;
|
||||
expect(tooltip.findHoverIndexFromData(posX, series)).to.be(4);
|
||||
expect(tooltip.findHoverIndexFromData(posX, series)).toBe(4);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -73,17 +73,17 @@ describeSharedTooltip('steppedLine false, stack false', function(ctx) {
|
||||
});
|
||||
|
||||
it('should return 2 series', function() {
|
||||
expect(ctx.results.length).to.be(2);
|
||||
expect(ctx.results.length).toBe(2);
|
||||
});
|
||||
|
||||
it('should add time to results array', function() {
|
||||
expect(ctx.results.time).to.be(10);
|
||||
expect(ctx.results.time).toBe(10);
|
||||
});
|
||||
|
||||
it('should set value and hoverIndex', function() {
|
||||
expect(ctx.results[0].value).to.be(15);
|
||||
expect(ctx.results[1].value).to.be(2);
|
||||
expect(ctx.results[0].hoverIndex).to.be(0);
|
||||
expect(ctx.results[0].value).toBe(15);
|
||||
expect(ctx.results[1].value).toBe(2);
|
||||
expect(ctx.results[0].hoverIndex).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -121,7 +121,7 @@ describeSharedTooltip('steppedLine false, stack true, individual false', functio
|
||||
});
|
||||
|
||||
it('should show stacked value', function() {
|
||||
expect(ctx.results[1].value).to.be(17);
|
||||
expect(ctx.results[1].value).toBe(17);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -152,7 +152,7 @@ describeSharedTooltip('steppedLine false, stack true, individual false, series s
|
||||
});
|
||||
|
||||
it('should not show stacked value', function() {
|
||||
expect(ctx.results[1].value).to.be(2);
|
||||
expect(ctx.results[1].value).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -184,6 +184,6 @@ describeSharedTooltip('steppedLine false, stack true, individual true', function
|
||||
});
|
||||
|
||||
it('should not show stacked value', function() {
|
||||
expect(ctx.results[1].value).to.be(2);
|
||||
expect(ctx.results[1].value).toBe(2);
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,3 @@
|
||||
import { describe, it, expect } from '../../../../../test/lib/common';
|
||||
|
||||
import angular from 'angular';
|
||||
import TimeSeries from 'app/core/time_series2';
|
||||
import { ThresholdManager } from '../threshold_manager';
|
||||
@@ -38,16 +36,16 @@ describe('ThresholdManager', function() {
|
||||
it('should add fill for threshold with fill: true', function() {
|
||||
var markings = ctx.options.grid.markings;
|
||||
|
||||
expect(markings[0].yaxis.from).to.be(300);
|
||||
expect(markings[0].yaxis.to).to.be(Infinity);
|
||||
expect(markings[0].color).to.be('rgba(234, 112, 112, 0.12)');
|
||||
expect(markings[0].yaxis.from).toBe(300);
|
||||
expect(markings[0].yaxis.to).toBe(Infinity);
|
||||
expect(markings[0].color).toBe('rgba(234, 112, 112, 0.12)');
|
||||
});
|
||||
|
||||
it('should add line', function() {
|
||||
var markings = ctx.options.grid.markings;
|
||||
expect(markings[1].yaxis.from).to.be(300);
|
||||
expect(markings[1].yaxis.to).to.be(300);
|
||||
expect(markings[1].color).to.be('rgba(237, 46, 24, 0.60)');
|
||||
expect(markings[1].yaxis.from).toBe(300);
|
||||
expect(markings[1].yaxis.to).toBe(300);
|
||||
expect(markings[1].color).toBe('rgba(237, 46, 24, 0.60)');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -59,14 +57,14 @@ describe('ThresholdManager', function() {
|
||||
|
||||
it('should add fill for first thresholds to next threshold', function() {
|
||||
var markings = ctx.options.grid.markings;
|
||||
expect(markings[0].yaxis.from).to.be(200);
|
||||
expect(markings[0].yaxis.to).to.be(300);
|
||||
expect(markings[0].yaxis.from).toBe(200);
|
||||
expect(markings[0].yaxis.to).toBe(300);
|
||||
});
|
||||
|
||||
it('should add fill for last thresholds to infinity', function() {
|
||||
var markings = ctx.options.grid.markings;
|
||||
expect(markings[1].yaxis.from).to.be(300);
|
||||
expect(markings[1].yaxis.to).to.be(Infinity);
|
||||
expect(markings[1].yaxis.from).toBe(300);
|
||||
expect(markings[1].yaxis.to).toBe(Infinity);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -78,14 +76,14 @@ describe('ThresholdManager', function() {
|
||||
|
||||
it('should add fill for first thresholds to next threshold', function() {
|
||||
var markings = ctx.options.grid.markings;
|
||||
expect(markings[0].yaxis.from).to.be(300);
|
||||
expect(markings[0].yaxis.to).to.be(200);
|
||||
expect(markings[0].yaxis.from).toBe(300);
|
||||
expect(markings[0].yaxis.to).toBe(200);
|
||||
});
|
||||
|
||||
it('should add fill for last thresholds to itself', function() {
|
||||
var markings = ctx.options.grid.markings;
|
||||
expect(markings[1].yaxis.from).to.be(200);
|
||||
expect(markings[1].yaxis.to).to.be(200);
|
||||
expect(markings[1].yaxis.from).toBe(200);
|
||||
expect(markings[1].yaxis.to).toBe(200);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -97,14 +95,14 @@ describe('ThresholdManager', function() {
|
||||
|
||||
it('should add fill for first thresholds to next threshold', function() {
|
||||
var markings = ctx.options.grid.markings;
|
||||
expect(markings[0].yaxis.from).to.be(300);
|
||||
expect(markings[0].yaxis.to).to.be(Infinity);
|
||||
expect(markings[0].yaxis.from).toBe(300);
|
||||
expect(markings[0].yaxis.to).toBe(Infinity);
|
||||
});
|
||||
|
||||
it('should add fill for last thresholds to itself', function() {
|
||||
var markings = ctx.options.grid.markings;
|
||||
expect(markings[1].yaxis.from).to.be(200);
|
||||
expect(markings[1].yaxis.to).to.be(-Infinity);
|
||||
expect(markings[1].yaxis.from).toBe(200);
|
||||
expect(markings[1].yaxis.to).toBe(-Infinity);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -130,12 +128,12 @@ describe('ThresholdManager', function() {
|
||||
|
||||
it('should add first threshold for left axis', function() {
|
||||
var markings = ctx.options.grid.markings;
|
||||
expect(markings[0].yaxis.from).to.be(100);
|
||||
expect(markings[0].yaxis.from).toBe(100);
|
||||
});
|
||||
|
||||
it('should add second threshold for right axis', function() {
|
||||
var markings = ctx.options.grid.markings;
|
||||
expect(markings[1].y2axis.from).to.be(200);
|
||||
expect(markings[1].y2axis.from).toBe(200);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,5 +1,3 @@
|
||||
import { describe, it, expect } from 'test/lib/common';
|
||||
|
||||
import { getColorForValue } from '../module';
|
||||
|
||||
describe('grafanaSingleStat', function() {
|
||||
@@ -11,31 +9,31 @@ describe('grafanaSingleStat', function() {
|
||||
};
|
||||
|
||||
it('5 should return green', () => {
|
||||
expect(getColorForValue(data, 5)).to.be('green');
|
||||
expect(getColorForValue(data, 5)).toBe('green');
|
||||
});
|
||||
|
||||
it('19.9 should return green', () => {
|
||||
expect(getColorForValue(data, 19.9)).to.be('green');
|
||||
expect(getColorForValue(data, 19.9)).toBe('green');
|
||||
});
|
||||
|
||||
it('20 should return yellow', () => {
|
||||
expect(getColorForValue(data, 20)).to.be('yellow');
|
||||
expect(getColorForValue(data, 20)).toBe('yellow');
|
||||
});
|
||||
|
||||
it('20.1 should return yellow', () => {
|
||||
expect(getColorForValue(data, 20.1)).to.be('yellow');
|
||||
expect(getColorForValue(data, 20.1)).toBe('yellow');
|
||||
});
|
||||
|
||||
it('25 should return yellow', () => {
|
||||
expect(getColorForValue(data, 25)).to.be('yellow');
|
||||
expect(getColorForValue(data, 25)).toBe('yellow');
|
||||
});
|
||||
|
||||
it('50 should return red', () => {
|
||||
expect(getColorForValue(data, 50)).to.be('red');
|
||||
expect(getColorForValue(data, 50)).toBe('red');
|
||||
});
|
||||
|
||||
it('55 should return red', () => {
|
||||
expect(getColorForValue(data, 55)).to.be('red');
|
||||
expect(getColorForValue(data, 55)).toBe('red');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -47,15 +45,15 @@ describe('grafanaSingleStat', function() {
|
||||
};
|
||||
|
||||
it('-30 should return green', () => {
|
||||
expect(getColorForValue(data, -30)).to.be('green');
|
||||
expect(getColorForValue(data, -30)).toBe('green');
|
||||
});
|
||||
|
||||
it('1 should return green', () => {
|
||||
expect(getColorForValue(data, 1)).to.be('yellow');
|
||||
expect(getColorForValue(data, 1)).toBe('yellow');
|
||||
});
|
||||
|
||||
it('22 should return green', () => {
|
||||
expect(getColorForValue(data, 22)).to.be('red');
|
||||
expect(getColorForValue(data, 22)).toBe('red');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -66,7 +64,7 @@ describe('grafanaSingleStat', function() {
|
||||
};
|
||||
|
||||
it('-30 should return green', () => {
|
||||
expect(getColorForValue(data, -26)).to.be('yellow');
|
||||
expect(getColorForValue(data, -26)).toBe('yellow');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -100,6 +100,22 @@
|
||||
// Success appears as green
|
||||
.btn-success {
|
||||
@include buttonBackground($btn-success-bg, $btn-success-bg-hl);
|
||||
|
||||
&--processing {
|
||||
@include button-outline-variant($gray-1);
|
||||
@include box-shadow(none);
|
||||
cursor: default;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:active:hover,
|
||||
&:focus,
|
||||
&:disabled {
|
||||
color: $gray-1;
|
||||
background-color: transparent;
|
||||
border-color: $gray-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Info appears as a neutral blue
|
||||
.btn-secondary {
|
||||
|
||||
@@ -11,11 +11,20 @@
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.dashboard-row__drag,
|
||||
.dashboard-row__actions {
|
||||
.dashboard-row__drag {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.dashboard-row__actions {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.dashboard-row__toggle-target {
|
||||
flex: 1;
|
||||
cursor: pointer;
|
||||
margin-right: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
@@ -43,7 +52,6 @@
|
||||
color: $text-muted;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
flex-grow: 1;
|
||||
transition: 200ms opacity ease-in 200ms;
|
||||
|
||||
a {
|
||||
@@ -69,7 +77,7 @@
|
||||
cursor: move;
|
||||
width: 1rem;
|
||||
height: 100%;
|
||||
background: url("../img/grab_dark.svg") no-repeat 50% 50%;
|
||||
background: url('../img/grab_dark.svg') no-repeat 50% 50%;
|
||||
background-size: 8px;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
.panel-alert-icon:before {
|
||||
content: '\e611';
|
||||
position: relative;
|
||||
top: 1px;
|
||||
top: 5px;
|
||||
left: -3px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,17 +68,26 @@ div.flot-text {
|
||||
font-weight: $font-weight-semi-bold;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
display: block;
|
||||
padding-bottom: 2px;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: center;
|
||||
padding: 4px 0 4px;
|
||||
}
|
||||
|
||||
.panel-title-text {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
max-width: calc(100% - 38px);
|
||||
cursor: pointer;
|
||||
font-weight: $font-weight-semi-bold;
|
||||
|
||||
&:hover {
|
||||
color: $link-hover-color;
|
||||
}
|
||||
.panel-has-alert & {
|
||||
max-width: calc(100% - 54px);
|
||||
}
|
||||
}
|
||||
|
||||
.panel-menu-container {
|
||||
@@ -97,7 +106,7 @@ div.flot-text {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
left: 1px;
|
||||
top: 4px;
|
||||
top: 2px;
|
||||
|
||||
&:hover {
|
||||
color: $link-hover-color;
|
||||
@@ -114,8 +123,6 @@ div.flot-text {
|
||||
}
|
||||
|
||||
.panel-header {
|
||||
text-align: center;
|
||||
|
||||
&:hover {
|
||||
transition: background-color 0.1s ease-in-out;
|
||||
background-color: $panel-header-hover-bg;
|
||||
@@ -156,8 +163,8 @@ div.flot-text {
|
||||
|
||||
.fa {
|
||||
position: relative;
|
||||
top: -4px;
|
||||
left: -6px;
|
||||
top: -2px;
|
||||
left: 6px;
|
||||
font-size: 75%;
|
||||
z-index: 1;
|
||||
}
|
||||
@@ -174,7 +181,7 @@ div.flot-text {
|
||||
display: block;
|
||||
@include panel-corner-color(lighten($panel-bg, 4%));
|
||||
.fa {
|
||||
left: -5px;
|
||||
left: 4px;
|
||||
}
|
||||
.fa:before {
|
||||
content: '\f08e';
|
||||
|
||||
@@ -13,6 +13,13 @@ $login-border: #8daac5;
|
||||
justify-content: center;
|
||||
background-image: url(../img/heatmap_bg_test.svg);
|
||||
background-size: cover;
|
||||
color: #d8d9da;
|
||||
& a {
|
||||
color: #d8d9da !important;
|
||||
}
|
||||
& .btn-primary {
|
||||
@include buttonBackground(#ff6600, #bc3e06);
|
||||
}
|
||||
}
|
||||
|
||||
input:-webkit-autofill,
|
||||
@@ -25,8 +32,9 @@ textarea:-webkit-autofill:focus,
|
||||
select:-webkit-autofill,
|
||||
select:-webkit-autofill:hover,
|
||||
select:-webkit-autofill:focus {
|
||||
-webkit-box-shadow: 0 0 0px 1000px $black inset;
|
||||
-webkit-text-fill-color: $gray-7 !important;
|
||||
-webkit-box-shadow: 0 0 0px 1000px $black inset !important;
|
||||
-webkit-text-fill-color: #fbfbfb !important;
|
||||
box-shadow: 0 0 0px 1000px $black inset;
|
||||
}
|
||||
|
||||
.login-form-group {
|
||||
@@ -46,6 +54,8 @@ select:-webkit-autofill:focus {
|
||||
border: 1px solid $login-border;
|
||||
border-radius: 4px;
|
||||
opacity: 0.6;
|
||||
background: $black;
|
||||
color: #fbfbfb;
|
||||
|
||||
&:focus {
|
||||
border: 1px solid $login-border;
|
||||
@@ -103,7 +113,7 @@ select:-webkit-autofill:focus {
|
||||
}
|
||||
|
||||
.icon-gf-grafana_wordmark {
|
||||
color: $link-color;
|
||||
color: darken($white, 11%);
|
||||
position: relative;
|
||||
font-size: 2rem;
|
||||
text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import {describe, beforeEach, it, expect} from 'test/lib/common';
|
||||
|
||||
import {SemVersion, isVersionGtOrEq} from 'app/core/utils/version';
|
||||
|
||||
describe("SemVersion", () => {
|
||||
@@ -8,10 +6,10 @@ describe("SemVersion", () => {
|
||||
describe('parsing', () => {
|
||||
it('should parse version properly', () => {
|
||||
let semver = new SemVersion(version);
|
||||
expect(semver.major).to.be(1);
|
||||
expect(semver.minor).to.be(0);
|
||||
expect(semver.patch).to.be(0);
|
||||
expect(semver.meta).to.be('alpha.1');
|
||||
expect(semver.major).toBe(1);
|
||||
expect(semver.minor).toBe(0);
|
||||
expect(semver.patch).toBe(0);
|
||||
expect(semver.meta).toBe('alpha.1');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,7 +28,7 @@ describe("SemVersion", () => {
|
||||
{value: '3.5', expected: false},
|
||||
];
|
||||
cases.forEach((testCase) => {
|
||||
expect(semver.isGtOrEq(testCase.value)).to.be(testCase.expected);
|
||||
expect(semver.isGtOrEq(testCase.value)).toBe(testCase.expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -48,7 +46,7 @@ describe("SemVersion", () => {
|
||||
{values: ['3.4.5', '3.5'], expected: false},
|
||||
];
|
||||
cases.forEach((testCase) => {
|
||||
expect(isVersionGtOrEq(testCase.values[0], testCase.values[1])).to.be(testCase.expected);
|
||||
expect(isVersionGtOrEq(testCase.values[0], testCase.values[1])).toBe(testCase.expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,22 @@
|
||||
import { configure } from 'enzyme';
|
||||
import Adapter from 'enzyme-adapter-react-16';
|
||||
import 'jquery';
|
||||
import $ from 'jquery';
|
||||
import 'angular';
|
||||
import angular from 'angular';
|
||||
|
||||
angular.module('grafana', ['ngRoute']);
|
||||
angular.module('grafana.services', ['ngRoute', '$strap.directives']);
|
||||
angular.module('grafana.panels', []);
|
||||
angular.module('grafana.controllers', []);
|
||||
angular.module('grafana.directives', []);
|
||||
angular.module('grafana.filters', []);
|
||||
angular.module('grafana.routes', ['ngRoute']);
|
||||
|
||||
jest.mock('app/core/core', () => ({}));
|
||||
jest.mock('app/features/plugins/plugin_loader', () => ({}));
|
||||
|
||||
configure({ adapter: new Adapter() });
|
||||
|
||||
var global = <any>window;
|
||||
global.$ = global.jQuery = $;
|
||||
|
||||
@@ -23,7 +23,7 @@ module.exports = merge(common, {
|
||||
},
|
||||
|
||||
resolve: {
|
||||
extensions: ['.scss', '.ts', '.tsx', '.es6', '.js', '.json', '.svg', '.woff2', '.png'],
|
||||
extensions: ['.scss', '.ts', '.tsx', '.es6', '.js', '.json', '.svg', '.woff2', '.png', '.html'],
|
||||
},
|
||||
|
||||
devtool: 'eval-source-map',
|
||||
|
||||
12299
vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c
generated
vendored
12299
vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c
generated
vendored
File diff suppressed because it is too large
Load Diff
658
vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h
generated
vendored
658
vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h
generated
vendored
File diff suppressed because it is too large
Load Diff
92
vendor/github.com/mattn/go-sqlite3/sqlite3.go
generated
vendored
92
vendor/github.com/mattn/go-sqlite3/sqlite3.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
// +build cgo
|
||||
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
@@ -7,10 +9,13 @@ package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -std=gnu99
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE=1
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_RTREE -DSQLITE_THREADSAFE=1 -DHAVE_USLEEP=1
|
||||
#cgo linux,!android CFLAGS: -DHAVE_PREAD64=1 -DHAVE_PWRITE64=1
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4_UNICODE61
|
||||
#cgo CFLAGS: -DSQLITE_TRACE_SIZE_LIMIT=15
|
||||
#cgo CFLAGS: -DSQLITE_OMIT_DEPRECATED
|
||||
#cgo CFLAGS: -DSQLITE_DISABLE_INTRINSIC
|
||||
#cgo CFLAGS: -DSQLITE_ENABLE_UPDATE_DELETE_LIMIT
|
||||
#cgo CFLAGS: -Wno-deprecated-declarations
|
||||
#ifndef USE_LIBSQLITE3
|
||||
#include <sqlite3-binding.h>
|
||||
@@ -170,6 +175,12 @@ var SQLiteTimestampFormats = []string{
|
||||
"2006-01-02",
|
||||
}
|
||||
|
||||
const (
|
||||
columnDate string = "date"
|
||||
columnDatetime string = "datetime"
|
||||
columnTimestamp string = "timestamp"
|
||||
)
|
||||
|
||||
func init() {
|
||||
sql.Register("sqlite3", &SQLiteDriver{})
|
||||
}
|
||||
@@ -389,7 +400,7 @@ func (c *SQLiteConn) RegisterCommitHook(callback func() int) {
|
||||
if callback == nil {
|
||||
C.sqlite3_commit_hook(c.db, nil, nil)
|
||||
} else {
|
||||
C.sqlite3_commit_hook(c.db, (*[0]byte)(unsafe.Pointer(C.commitHookTrampoline)), unsafe.Pointer(newHandle(c, callback)))
|
||||
C.sqlite3_commit_hook(c.db, (*[0]byte)(C.commitHookTrampoline), unsafe.Pointer(newHandle(c, callback)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +413,7 @@ func (c *SQLiteConn) RegisterRollbackHook(callback func()) {
|
||||
if callback == nil {
|
||||
C.sqlite3_rollback_hook(c.db, nil, nil)
|
||||
} else {
|
||||
C.sqlite3_rollback_hook(c.db, (*[0]byte)(unsafe.Pointer(C.rollbackHookTrampoline)), unsafe.Pointer(newHandle(c, callback)))
|
||||
C.sqlite3_rollback_hook(c.db, (*[0]byte)(C.rollbackHookTrampoline), unsafe.Pointer(newHandle(c, callback)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -419,7 +430,7 @@ func (c *SQLiteConn) RegisterUpdateHook(callback func(int, string, string, int64
|
||||
if callback == nil {
|
||||
C.sqlite3_update_hook(c.db, nil, nil)
|
||||
} else {
|
||||
C.sqlite3_update_hook(c.db, (*[0]byte)(unsafe.Pointer(C.updateHookTrampoline)), unsafe.Pointer(newHandle(c, callback)))
|
||||
C.sqlite3_update_hook(c.db, (*[0]byte)(C.updateHookTrampoline), unsafe.Pointer(newHandle(c, callback)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,7 +512,7 @@ func (c *SQLiteConn) RegisterFunc(name string, impl interface{}, pure bool) erro
|
||||
}
|
||||
|
||||
func sqlite3CreateFunction(db *C.sqlite3, zFunctionName *C.char, nArg C.int, eTextRep C.int, pApp uintptr, xFunc unsafe.Pointer, xStep unsafe.Pointer, xFinal unsafe.Pointer) C.int {
|
||||
return C._sqlite3_create_function(db, zFunctionName, nArg, eTextRep, C.uintptr_t(pApp), (*[0]byte)(unsafe.Pointer(xFunc)), (*[0]byte)(unsafe.Pointer(xStep)), (*[0]byte)(unsafe.Pointer(xFinal)))
|
||||
return C._sqlite3_create_function(db, zFunctionName, nArg, eTextRep, C.uintptr_t(pApp), (*[0]byte)(xFunc), (*[0]byte)(xStep), (*[0]byte)(xFinal))
|
||||
}
|
||||
|
||||
// RegisterAggregator makes a Go type available as a SQLite aggregation function.
|
||||
@@ -780,6 +791,8 @@ func errorString(err Error) string {
|
||||
// Enable or disable enforcement of foreign keys. X can be 1 or 0.
|
||||
// _recursive_triggers=X
|
||||
// Enable or disable recursive triggers. X can be 1 or 0.
|
||||
// _mutex=XXX
|
||||
// Specify mutex mode. XXX can be "no", "full".
|
||||
func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
if C.sqlite3_threadsafe() == 0 {
|
||||
return nil, errors.New("sqlite library was not compiled for thread-safe operation")
|
||||
@@ -790,6 +803,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
busyTimeout := 5000
|
||||
foreignKeys := -1
|
||||
recursiveTriggers := -1
|
||||
mutex := C.int(C.SQLITE_OPEN_FULLMUTEX)
|
||||
pos := strings.IndexRune(dsn, '?')
|
||||
if pos >= 1 {
|
||||
params, err := url.ParseQuery(dsn[pos+1:])
|
||||
@@ -856,6 +870,18 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// _mutex
|
||||
if val := params.Get("_mutex"); val != "" {
|
||||
switch val {
|
||||
case "no":
|
||||
mutex = C.SQLITE_OPEN_NOMUTEX
|
||||
case "full":
|
||||
mutex = C.SQLITE_OPEN_FULLMUTEX
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid _mutex: %v", val)
|
||||
}
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(dsn, "file:") {
|
||||
dsn = dsn[:pos]
|
||||
}
|
||||
@@ -865,9 +891,7 @@ func (d *SQLiteDriver) Open(dsn string) (driver.Conn, error) {
|
||||
name := C.CString(dsn)
|
||||
defer C.free(unsafe.Pointer(name))
|
||||
rv := C._sqlite3_open_v2(name, &db,
|
||||
C.SQLITE_OPEN_FULLMUTEX|
|
||||
C.SQLITE_OPEN_READWRITE|
|
||||
C.SQLITE_OPEN_CREATE,
|
||||
mutex|C.SQLITE_OPEN_READWRITE|C.SQLITE_OPEN_CREATE,
|
||||
nil)
|
||||
if rv != 0 {
|
||||
return nil, Error{Code: ErrNo(rv)}
|
||||
@@ -1070,7 +1094,7 @@ func (s *SQLiteStmt) bind(args []namedValue) error {
|
||||
case int64:
|
||||
rv = C.sqlite3_bind_int64(s.s, n, C.sqlite3_int64(v))
|
||||
case bool:
|
||||
if bool(v) {
|
||||
if v {
|
||||
rv = C.sqlite3_bind_int(s.s, n, 1)
|
||||
} else {
|
||||
rv = C.sqlite3_bind_int(s.s, n, 0)
|
||||
@@ -1121,18 +1145,20 @@ func (s *SQLiteStmt) query(ctx context.Context, args []namedValue) (driver.Rows,
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
go func(db *C.sqlite3) {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
if ctxdone := ctx.Done(); ctxdone != nil {
|
||||
go func(db *C.sqlite3) {
|
||||
select {
|
||||
case <-ctxdone:
|
||||
select {
|
||||
case <-rows.done:
|
||||
default:
|
||||
C.sqlite3_interrupt(db)
|
||||
rows.Close()
|
||||
}
|
||||
case <-rows.done:
|
||||
default:
|
||||
C.sqlite3_interrupt(db)
|
||||
rows.Close()
|
||||
}
|
||||
case <-rows.done:
|
||||
}
|
||||
}(s.c.db)
|
||||
}(s.c.db)
|
||||
}
|
||||
|
||||
return rows, nil
|
||||
}
|
||||
@@ -1166,19 +1192,21 @@ func (s *SQLiteStmt) exec(ctx context.Context, args []namedValue) (driver.Result
|
||||
return nil, err
|
||||
}
|
||||
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
go func(db *C.sqlite3) {
|
||||
select {
|
||||
case <-done:
|
||||
case <-ctx.Done():
|
||||
if ctxdone := ctx.Done(); ctxdone != nil {
|
||||
done := make(chan struct{})
|
||||
defer close(done)
|
||||
go func(db *C.sqlite3) {
|
||||
select {
|
||||
case <-done:
|
||||
default:
|
||||
C.sqlite3_interrupt(db)
|
||||
case <-ctxdone:
|
||||
select {
|
||||
case <-done:
|
||||
default:
|
||||
C.sqlite3_interrupt(db)
|
||||
}
|
||||
}
|
||||
}
|
||||
}(s.c.db)
|
||||
}(s.c.db)
|
||||
}
|
||||
|
||||
var rowid, changes C.longlong
|
||||
rv := C._sqlite3_step(s.s, &rowid, &changes)
|
||||
@@ -1272,7 +1300,7 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||
case C.SQLITE_INTEGER:
|
||||
val := int64(C.sqlite3_column_int64(rc.s.s, C.int(i)))
|
||||
switch rc.decltype[i] {
|
||||
case "timestamp", "datetime", "date":
|
||||
case columnTimestamp, columnDatetime, columnDate:
|
||||
var t time.Time
|
||||
// Assume a millisecond unix timestamp if it's 13 digits -- too
|
||||
// large to be a reasonable timestamp in seconds.
|
||||
@@ -1303,10 +1331,10 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||
n := int(C.sqlite3_column_bytes(rc.s.s, C.int(i)))
|
||||
switch dest[i].(type) {
|
||||
case sql.RawBytes:
|
||||
dest[i] = (*[1 << 30]byte)(unsafe.Pointer(p))[0:n]
|
||||
dest[i] = (*[1 << 30]byte)(p)[0:n]
|
||||
default:
|
||||
slice := make([]byte, n)
|
||||
copy(slice[:], (*[1 << 30]byte)(unsafe.Pointer(p))[0:n])
|
||||
copy(slice[:], (*[1 << 30]byte)(p)[0:n])
|
||||
dest[i] = slice
|
||||
}
|
||||
case C.SQLITE_NULL:
|
||||
@@ -1319,7 +1347,7 @@ func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||
s := C.GoStringN((*C.char)(unsafe.Pointer(C.sqlite3_column_text(rc.s.s, C.int(i)))), C.int(n))
|
||||
|
||||
switch rc.decltype[i] {
|
||||
case "timestamp", "datetime", "date":
|
||||
case columnTimestamp, columnDatetime, columnDate:
|
||||
var t time.Time
|
||||
s = strings.TrimSuffix(s, "Z")
|
||||
for _, format := range SQLiteTimestampFormats {
|
||||
|
||||
2
vendor/github.com/mattn/go-sqlite3/sqlite3_go18.go
generated
vendored
2
vendor/github.com/mattn/go-sqlite3/sqlite3_go18.go
generated
vendored
@@ -1,3 +1,5 @@
|
||||
// +build cgo
|
||||
|
||||
// Copyright (C) 2014 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
|
||||
12
vendor/github.com/mattn/go-sqlite3/sqlite3_solaris.go
generated
vendored
Normal file
12
vendor/github.com/mattn/go-sqlite3/sqlite3_solaris.go
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright (C) 2018 Yasuhiro Matsumoto <mattn.jp@gmail.com>.
|
||||
//
|
||||
// Use of this source code is governed by an MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
// +build solaris
|
||||
|
||||
package sqlite3
|
||||
|
||||
/*
|
||||
#cgo CFLAGS: -D__EXTENSIONS__=1
|
||||
*/
|
||||
import "C"
|
||||
22
vendor/github.com/mattn/go-sqlite3/sqlite3_trace.go
generated
vendored
22
vendor/github.com/mattn/go-sqlite3/sqlite3_trace.go
generated
vendored
@@ -28,10 +28,10 @@ import (
|
||||
// Trace... constants identify the possible events causing callback invocation.
|
||||
// Values are same as the corresponding SQLite Trace Event Codes.
|
||||
const (
|
||||
TraceStmt = C.SQLITE_TRACE_STMT
|
||||
TraceProfile = C.SQLITE_TRACE_PROFILE
|
||||
TraceRow = C.SQLITE_TRACE_ROW
|
||||
TraceClose = C.SQLITE_TRACE_CLOSE
|
||||
TraceStmt = uint32(C.SQLITE_TRACE_STMT)
|
||||
TraceProfile = uint32(C.SQLITE_TRACE_PROFILE)
|
||||
TraceRow = uint32(C.SQLITE_TRACE_ROW)
|
||||
TraceClose = uint32(C.SQLITE_TRACE_CLOSE)
|
||||
)
|
||||
|
||||
type TraceInfo struct {
|
||||
@@ -71,7 +71,7 @@ type TraceUserCallback func(TraceInfo) int
|
||||
|
||||
type TraceConfig struct {
|
||||
Callback TraceUserCallback
|
||||
EventMask C.uint
|
||||
EventMask uint32
|
||||
WantExpandedSQL bool
|
||||
}
|
||||
|
||||
@@ -105,6 +105,8 @@ func traceCallbackTrampoline(
|
||||
// Parameter named 'X' in SQLite docs (eXtra event data?):
|
||||
xValue unsafe.Pointer) C.int {
|
||||
|
||||
eventCode := uint32(traceEventCode)
|
||||
|
||||
if ctx == nil {
|
||||
panic(fmt.Sprintf("No context (ev 0x%x)", traceEventCode))
|
||||
}
|
||||
@@ -114,7 +116,7 @@ func traceCallbackTrampoline(
|
||||
|
||||
var traceConf TraceConfig
|
||||
var found bool
|
||||
if traceEventCode == TraceClose {
|
||||
if eventCode == TraceClose {
|
||||
// clean up traceMap: 'pop' means get and delete
|
||||
traceConf, found = popTraceMapping(connHandle)
|
||||
} else {
|
||||
@@ -123,16 +125,16 @@ func traceCallbackTrampoline(
|
||||
|
||||
if !found {
|
||||
panic(fmt.Sprintf("Mapping not found for handle 0x%x (ev 0x%x)",
|
||||
connHandle, traceEventCode))
|
||||
connHandle, eventCode))
|
||||
}
|
||||
|
||||
var info TraceInfo
|
||||
|
||||
info.EventCode = uint32(traceEventCode)
|
||||
info.EventCode = eventCode
|
||||
info.AutoCommit = (int(C.sqlite3_get_autocommit(contextDB)) != 0)
|
||||
info.ConnHandle = connHandle
|
||||
|
||||
switch traceEventCode {
|
||||
switch eventCode {
|
||||
case TraceStmt:
|
||||
info.StmtHandle = uintptr(p)
|
||||
|
||||
@@ -183,7 +185,7 @@ func traceCallbackTrampoline(
|
||||
// registering this callback trampoline with SQLite --- for cleanup.
|
||||
// In the future there may be more events forced to "selected" in SQLite
|
||||
// for the driver's needs.
|
||||
if traceConf.EventMask&traceEventCode == 0 {
|
||||
if traceConf.EventMask&eventCode == 0 {
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
7
vendor/github.com/mattn/go-sqlite3/sqlite3ext.h
generated
vendored
7
vendor/github.com/mattn/go-sqlite3/sqlite3ext.h
generated
vendored
@@ -293,6 +293,9 @@ struct sqlite3_api_routines {
|
||||
int (*bind_pointer)(sqlite3_stmt*,int,void*,const char*,void(*)(void*));
|
||||
void (*result_pointer)(sqlite3_context*,void*,const char*,void(*)(void*));
|
||||
void *(*value_pointer)(sqlite3_value*,const char*);
|
||||
int (*vtab_nochange)(sqlite3_context*);
|
||||
int (*value_nochange)(sqlite3_value*);
|
||||
const char *(*vtab_collation)(sqlite3_index_info*,int);
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -559,6 +562,10 @@ typedef int (*sqlite3_loadext_entry)(
|
||||
#define sqlite3_bind_pointer sqlite3_api->bind_pointer
|
||||
#define sqlite3_result_pointer sqlite3_api->result_pointer
|
||||
#define sqlite3_value_pointer sqlite3_api->value_pointer
|
||||
/* Version 3.22.0 and later */
|
||||
#define sqlite3_vtab_nochange sqlite3_api->vtab_nochange
|
||||
#define sqlite3_value_nochange sqlite3_api->value_nochange
|
||||
#define sqlite3_vtab_collation sqlite3_api->vtab_collation
|
||||
#endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
|
||||
|
||||
#if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
|
||||
|
||||
21
vendor/github.com/mattn/go-sqlite3/static_mock.go
generated
vendored
Normal file
21
vendor/github.com/mattn/go-sqlite3/static_mock.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// +build !cgo
|
||||
|
||||
package sqlite3
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
)
|
||||
|
||||
func init() {
|
||||
sql.Register("sqlite3", &SQLiteDriverMock{})
|
||||
}
|
||||
|
||||
type SQLiteDriverMock struct{}
|
||||
|
||||
var errorMsg = errors.New("Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work. This is a stub")
|
||||
|
||||
func (SQLiteDriverMock) Open(s string) (driver.Conn, error) {
|
||||
return nil, errorMsg
|
||||
}
|
||||
@@ -7928,10 +7928,6 @@ 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"
|
||||
|
||||
Reference in New Issue
Block a user