├── pkg ├── testdata │ ├── golden │ │ ├── test.json │ │ ├── no-query.json │ │ ├── empty-query.json │ │ ├── test-error.json │ │ ├── timeseries-unknown.json │ │ ├── timeseries-get.json │ │ ├── timeseries-tags.json │ │ ├── timeseries-tagsrec.json │ │ ├── table.json │ │ └── timeseries-keys.json │ ├── k8s-export.kind.json │ ├── k8s-export.spec.version.json │ ├── k8s-export.spec.versionPriority.json │ ├── k8s-export.name.json │ ├── k8s-export.spec.group.json │ ├── k8s-export.spec.groupPriorityMinimum.json │ └── k8s-export.apiVersion.json ├── main.go ├── plugin_test.go └── plugin.go ├── src ├── images │ ├── keys.png │ ├── table.png │ ├── tags.png │ ├── overview.png │ └── Consul_VerticalLogo_FullColor.svg ├── module.ts ├── types.ts ├── plugin.json ├── DataSource.ts ├── ConfigEditor.tsx └── QueryEditor.tsx ├── .prettierrc.js ├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── tsconfig.json ├── go.mod ├── .editorconfig ├── jest.config.js ├── CHANGELOG.md ├── Magefile.go ├── .gitignore ├── development.md ├── .golangci.yml ├── example ├── main_test.go ├── README.md ├── main.go ├── Consul_Kubernetes_Example.json └── data │ └── data.json ├── package.json ├── appveyor.yml ├── README.md ├── install.sh ├── LICENSE └── go.sum /pkg/testdata/golden/test.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /pkg/testdata/golden/no-query.json: -------------------------------------------------------------------------------- 1 | { 2 | "Responses": {} 3 | } -------------------------------------------------------------------------------- /pkg/testdata/golden/empty-query.json: -------------------------------------------------------------------------------- 1 | { 2 | "Responses": {} 3 | } -------------------------------------------------------------------------------- /src/images/keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbueringer/grafana-consul-datasource/HEAD/src/images/keys.png -------------------------------------------------------------------------------- /src/images/table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbueringer/grafana-consul-datasource/HEAD/src/images/table.png -------------------------------------------------------------------------------- /src/images/tags.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbueringer/grafana-consul-datasource/HEAD/src/images/tags.png -------------------------------------------------------------------------------- /src/images/overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sbueringer/grafana-consul-datasource/HEAD/src/images/overview.png -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | ...require("./node_modules/@grafana/toolkit/src/config/prettier.plugin.config.json"), 3 | }; -------------------------------------------------------------------------------- /pkg/testdata/golden/test-error.json: -------------------------------------------------------------------------------- 1 | { 2 | "results": [ 3 | { 4 | "error": "consulToken is no valid token" 5 | } 6 | ] 7 | } -------------------------------------------------------------------------------- /pkg/testdata/golden/timeseries-unknown.json: -------------------------------------------------------------------------------- 1 | { 2 | "Responses": { 3 | "xyz": { 4 | "Frames": null, 5 | "Error": {} 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Maintain dependencies for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "daily" 8 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/@grafana/toolkit/src/config/tsconfig.plugin.json", 3 | "include": ["src", "types"], 4 | "compilerOptions": { 5 | "rootDir": "./src", 6 | "baseUrl": "./src", 7 | "typeRoots": ["./node_modules/@types"] 8 | } 9 | } -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/grafana/simple-datasource-backend 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/grafana/grafana-plugin-sdk-go v0.65.0 7 | github.com/hashicorp/consul/api v1.7.0 8 | github.com/hashicorp/consul/sdk v0.6.0 9 | github.com/sergi/go-diff v1.1.0 10 | ) 11 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | max_line_length = 120 11 | 12 | [*.{js,ts,tsx,scss}] 13 | quote_type = single 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // This file is needed because it is used by vscode and other tools that 2 | // call `jest` directly. However, unless you are doing anything special 3 | // do not edit this file 4 | 5 | const standard = require('@grafana/toolkit/src/config/jest.plugin.config'); 6 | 7 | // This process will use the same config that `yarn test` is using 8 | module.exports = standard.jestConfig(); 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | # v0.2.1 - 2020-11-18 3 | 4 | * add screenshots 5 | * fix dependencies in plugin.json 6 | 7 | # v0.2.0 - 2020-11-11 8 | 9 | Highlights: 10 | * Some cleanup 11 | * Added tooltips again 12 | 13 | # v0.1.9 - 2020-11-11 14 | 15 | Complete rewrite of the plugin for Grafana 7.x. 16 | 17 | Highlights: 18 | * Anonymous Consul authentication (without token) 19 | * Plugin is now signed 20 | -------------------------------------------------------------------------------- /Magefile.go: -------------------------------------------------------------------------------- 1 | //+build mage 2 | 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | // mage:import 8 | build "github.com/grafana/grafana-plugin-sdk-go/build" 9 | ) 10 | 11 | // Hello prints a message (shows that you can define custom Mage targets). 12 | func Hello() { 13 | fmt.Println("hello plugin developer!") 14 | } 15 | 16 | // Default configures the default target. 17 | var Default = build.BuildAll 18 | -------------------------------------------------------------------------------- /src/module.ts: -------------------------------------------------------------------------------- 1 | import { DataSourcePlugin } from '@grafana/data'; 2 | import { DataSource } from './DataSource'; 3 | import { ConfigEditor } from './ConfigEditor'; 4 | import { QueryEditor } from './QueryEditor'; 5 | import { ConsulQuery, MyDataSourceOptions } from './types'; 6 | 7 | export const plugin = new DataSourcePlugin(DataSource) 8 | .setConfigEditor(ConfigEditor) 9 | .setQueryEditor(QueryEditor); 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | node_modules/ 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # Compiled binary addons (https://nodejs.org/api/addons.html) 23 | dist/ 24 | artifacts/ 25 | work/ 26 | ci/ 27 | e2e-results/ 28 | 29 | # Editor 30 | .idea 31 | -------------------------------------------------------------------------------- /development.md: -------------------------------------------------------------------------------- 1 | 2 | # Development 3 | 4 | Can be build locally via: 5 | 6 | ```bash 7 | yarn dev && mage -v 8 | ``` 9 | 10 | Release build can be executed locally via: 11 | 12 | ```bash 13 | mage -v 14 | ./node_modules/.bin/grafana-toolkit plugin:ci-build 15 | ./node_modules/.bin/grafana-toolkit plugin:ci-build --finish 16 | ./node_modules/.bin/grafana-toolkit plugin:ci-package 17 | ls -la ./ci 18 | ``` 19 | 20 | Github build can be run locally via 21 | 22 | ```bash 23 | act -s GRAFANA_API_KEY=$GRAFANA_API_KEY 24 | ``` 25 | 26 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | deadline: 10m 3 | 4 | concurrency: 4 5 | 6 | # skip-dirs: 7 | # - vendor/ 8 | 9 | # skip-files: 10 | 11 | linters: 12 | disable-all: true 13 | fast: false 14 | enable: 15 | - goimports 16 | - golint 17 | - govet 18 | - gofmt 19 | - structcheck 20 | - staticcheck 21 | - varcheck 22 | - interfacer 23 | - unconvert 24 | - ineffassign 25 | - goconst 26 | - misspell 27 | - nakedret 28 | - deadcode 29 | 30 | issues: 31 | max-issues-per-linter: 100 32 | max-same-issues: 50 33 | -------------------------------------------------------------------------------- /pkg/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | 6 | "github.com/grafana/grafana-plugin-sdk-go/backend/datasource" 7 | "github.com/grafana/grafana-plugin-sdk-go/backend/log" 8 | ) 9 | 10 | func main() { 11 | // Start listening to requests send from Grafana. This call is blocking so 12 | // it wont finish until Grafana shutsdown the process or the plugin choose 13 | // to exit close down by itself 14 | err := datasource.Serve(newDatasource()) 15 | 16 | // Log any error if we could start the plugin. 17 | if err != nil { 18 | log.DefaultLogger.Error(err.Error()) 19 | os.Exit(1) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { DataQuery, DataSourceJsonData } from '@grafana/data'; 2 | 3 | export interface ConsulQuery extends DataQuery { 4 | target: string; 5 | format?: string; 6 | type?: string; 7 | legendFormat?: string; 8 | columns?: string; 9 | } 10 | 11 | /** 12 | * These are options configured for each DataSource instance 13 | */ 14 | export interface MyDataSourceOptions extends DataSourceJsonData { 15 | consulAddr?: string; 16 | } 17 | 18 | /** 19 | * Value that is used in the backend, but never sent over HTTP to the frontend 20 | */ 21 | export interface MySecureJsonData { 22 | consulToken?: string; 23 | } 24 | -------------------------------------------------------------------------------- /example/main_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | 7 | "github.com/hashicorp/consul/api" 8 | ) 9 | 10 | func TestAnonymous(t *testing.T) { 11 | 12 | client, err := newConsul("http://localhost:8500", "") 13 | if err != nil { 14 | panic(err) 15 | } 16 | 17 | kv, _, err := client.KV().Get("registry/apiregistration.k8s.io/apiservices/v1.apps/apiVersion", &api.QueryOptions{}) 18 | if err != nil { 19 | panic(err) 20 | } 21 | fmt.Printf("%v", kv) 22 | 23 | status := client.Status() 24 | fmt.Printf("%v", status) 25 | 26 | leader, err := client.Status().Leader() 27 | if err != nil { 28 | panic(err) 29 | } 30 | fmt.Printf("%s", leader) 31 | } 32 | -------------------------------------------------------------------------------- /pkg/testdata/golden/timeseries-get.json: -------------------------------------------------------------------------------- 1 | { 2 | "Responses": { 3 | "abc": { 4 | "Frames": [ 5 | { 6 | "Name": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/spec/groupPriorityMinimum", 7 | "Fields": [ 8 | { 9 | "Name": "time", 10 | "Labels": null, 11 | "Config": null 12 | }, 13 | { 14 | "Name": "values", 15 | "Labels": null, 16 | "Config": null 17 | } 18 | ], 19 | "RefID": "", 20 | "Meta": null 21 | } 22 | ], 23 | "Error": null 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sbueringer-consul-3", 3 | "version": "1.0.0", 4 | "description": "", 5 | "scripts": { 6 | "build": "grafana-toolkit plugin:build", 7 | "test": "grafana-toolkit plugin:test", 8 | "dev": "grafana-toolkit plugin:dev", 9 | "watch": "grafana-toolkit plugin:dev --watch" 10 | }, 11 | "author": "Stefan Bueringer", 12 | "license": "Apache-2.0", 13 | "devDependencies": { 14 | "@grafana/data": "latest", 15 | "@grafana/toolkit": "latest", 16 | "@grafana/runtime": "latest", 17 | "@grafana/ui": "latest", 18 | "@types/lodash": "latest" 19 | }, 20 | "engines": { 21 | "node": ">=12 <13" 22 | }, 23 | "resolutions": { 24 | "rxjs": "6.6.3" 25 | } 26 | } -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # Test against the latest version of this Node.js version 2 | environment: 3 | nodejs_version: "10" 4 | 5 | # Local NPM Modules 6 | cache: 7 | - node_modules 8 | 9 | # Install scripts. (runs after repo cloning) 10 | install: 11 | # Get the latest stable version of Node.js or io.js 12 | - ps: Install-Product node $env:nodejs_version 13 | # install modules 14 | - npm install -g yarn --quiet 15 | - yarn install --pure-lockfile 16 | 17 | # Post-install test scripts. 18 | test_script: 19 | # Output useful info for debugging. 20 | - node --version 21 | - npm --version 22 | 23 | # Run the build 24 | build_script: 25 | - yarn dev # This will also run prettier! 26 | - yarn build # make sure both scripts work 27 | -------------------------------------------------------------------------------- /pkg/testdata/golden/timeseries-tags.json: -------------------------------------------------------------------------------- 1 | { 2 | "Responses": { 3 | "xyz": { 4 | "Frames": [ 5 | { 6 | "Name": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/", 7 | "Fields": [ 8 | { 9 | "Name": "time", 10 | "Labels": null, 11 | "Config": null 12 | }, 13 | { 14 | "Name": "values", 15 | "Labels": { 16 | "apiVersion": "apiregistration.k8s.io/v1beta1", 17 | "kind": "APIService", 18 | "name": "v1.authentication.k8s.io" 19 | }, 20 | "Config": null 21 | } 22 | ], 23 | "RefID": "", 24 | "Meta": null 25 | } 26 | ], 27 | "Error": null 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /pkg/testdata/golden/timeseries-tagsrec.json: -------------------------------------------------------------------------------- 1 | { 2 | "Responses": { 3 | "xyz": { 4 | "Frames": [ 5 | { 6 | "Name": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/", 7 | "Fields": [ 8 | { 9 | "Name": "time", 10 | "Labels": null, 11 | "Config": null 12 | }, 13 | { 14 | "Name": "values", 15 | "Labels": { 16 | "apiVersion": "apiregistration.k8s.io/v1beta1", 17 | "kind": "APIService", 18 | "name": "v1.autoscaling", 19 | "spec.group": "autoscaling", 20 | "spec.groupPriorityMinimum": "17500", 21 | "spec.version": "v1", 22 | "spec.versionPriority": "15" 23 | }, 24 | "Config": null 25 | } 26 | ], 27 | "RefID": "", 28 | "Meta": null 29 | } 30 | ], 31 | "Error": null 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /pkg/testdata/golden/table.json: -------------------------------------------------------------------------------- 1 | { 2 | "Responses": { 3 | "xyz": { 4 | "Frames": [ 5 | { 6 | "Name": "table", 7 | "Fields": [ 8 | { 9 | "Name": "name", 10 | "Labels": null, 11 | "Config": null 12 | }, 13 | { 14 | "Name": "kind", 15 | "Labels": null, 16 | "Config": null 17 | }, 18 | { 19 | "Name": "apiVersion", 20 | "Labels": null, 21 | "Config": null 22 | }, 23 | { 24 | "Name": "group", 25 | "Labels": null, 26 | "Config": null 27 | }, 28 | { 29 | "Name": "groupPriorityMinimum", 30 | "Labels": null, 31 | "Config": null 32 | }, 33 | { 34 | "Name": "version", 35 | "Labels": null, 36 | "Config": null 37 | }, 38 | { 39 | "Name": "versionPriority", 40 | "Labels": null, 41 | "Config": null 42 | } 43 | ], 44 | "RefID": "", 45 | "Meta": null 46 | } 47 | ], 48 | "Error": null 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /src/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Consul", 3 | "id": "sbueringer-consul-datasource", 4 | "type": "datasource", 5 | 6 | "metrics": true, 7 | "backend": true, 8 | "executable": "gpx_Consul", 9 | "info": { 10 | "description": "Consul datasource plugin to integrate Consul key value data with Grafana.", 11 | "author": { 12 | "name": "Stefan Bueringer", 13 | "url": "https://github.com/sbueringer" 14 | }, 15 | "keywords": [ 16 | "consul" 17 | ], 18 | "logos": { 19 | "small": "images/Consul_VerticalLogo_FullColor.svg", 20 | "large": "images/Consul_VerticalLogo_FullColor.svg" 21 | }, 22 | "links": [ 23 | {"name": "GitHub", "url": "https://github.com/sbueringer/grafana-consul-datasource"}, 24 | {"name": "Apache License 2.0", "url": "https://github.com/sbueringer/grafana-consul-datasource/blob/master/LICENSE"} 25 | ], 26 | "screenshots": [ 27 | {"name": "Variables", "path": "images/keys.png"}, 28 | {"name": "Overview", "path": "images/overview.png"}, 29 | {"name": "Table", "path": "images/table.png"}, 30 | {"name": "Tags", "path": "images/tags.png"} 31 | ], 32 | "version": "%VERSION%", 33 | "updated": "%TODAY%" 34 | }, 35 | "dependencies": { 36 | "grafanaDependency": ">=7.3.x", 37 | "plugins": [] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Example 3 | 4 | ## Start Consul 5 | 6 | ```` 7 | git clone https://github.com/sbueringer/grafana-consul-datasource.git 8 | cd grafana-consul-datasource/example 9 | go run main.go 10 | ```` 11 | 12 | ## Configure the Consul datasource 13 | 14 | 1. Open Grafana in your browser and open the side menu by clicking the Grafana icon in the top header. 15 | ```bash 16 | docker run --rm -it -p 3000:3000 --name=grafana --net=host \ 17 | -e "GF_INSTALL_PLUGINS=https://github.com/sbueringer/grafana-consul-datasource/releases/download/v0.1.9/sbueringer-consul-datasource-0.1.9.zip;sbueringer-consul-datasource" grafana/grafana 18 | ``` 19 | 1. In the side menu in the `Configuration` section you should find a link named `Data Sources`. 20 | 1. Click the `Add data source` button in the top header. 21 | 1. Select `Consul`. 22 | 1. Fill in the: 23 | 1. name: `Consul` 24 | 2. Consul address: `http://localhost:8500` 25 | 3. Consul token can be left empty: `` 26 | 1. Click the `Save & Test` button 27 | 28 | # Import the example dashboard 29 | 30 | 1. In the side menu in the `+` section you should find a link named `Import`. 31 | 1. Click the `Upload .json File` button and select the dashboard from `example/Consul_Kubernetes_Example.json`. 32 | 1. Select `Consul` as datasource and click `Import`. 33 | 34 | *For further explanations see [README.md](https://github.com/sbueringer/grafana-consul-datasource/).* 35 | -------------------------------------------------------------------------------- /example/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | "os/signal" 9 | "path/filepath" 10 | "sync" 11 | "testing" 12 | 13 | "github.com/hashicorp/consul/api" 14 | "github.com/hashicorp/consul/sdk/testutil" 15 | ) 16 | 17 | func main() { 18 | fmt.Println("Starting Consul") 19 | srv := startServer() 20 | defer srv.Stop() 21 | fmt.Printf("Consul is now listening on: %s\n", srv.HTTPAddr) 22 | 23 | var wait sync.WaitGroup 24 | wait.Add(1) 25 | 26 | sigChan := make(chan os.Signal, 1) 27 | signal.Notify(sigChan, os.Interrupt) 28 | 29 | go func() { 30 | <-sigChan 31 | fmt.Println("Stopping Consul") 32 | wait.Done() 33 | }() 34 | 35 | fmt.Println("Server can be stopped with CTRL-c") 36 | wait.Wait() 37 | fmt.Println("Consul stopped") 38 | } 39 | 40 | func startServer() *testutil.TestServer { 41 | srv, err := testutil.NewTestServerConfigT(&testing.T{}, func(c *testutil.TestServerConfig) { 42 | //c.Stdout = ioutil.Discard 43 | //c.Stderr = ioutil.Discard 44 | c.Ports = &testutil.TestPortConfig{ 45 | HTTP: 8500, 46 | } 47 | c.Datacenter = "default" 48 | c.LogLevel = "debug" 49 | }) 50 | if err != nil { 51 | panic(err) 52 | } 53 | 54 | fmt.Println("Importing example data to Consul") 55 | 56 | consul, err := newConsul(srv.HTTPAddr, srv.Config.ACLMasterToken) 57 | if err != nil { 58 | panic(fmt.Errorf("could not create consul client: %v", err)) 59 | } 60 | 61 | files, err := filepath.Glob("data/data.json") 62 | if err != nil { 63 | panic(fmt.Errorf("error getting import json files")) 64 | } 65 | 66 | if len(files) == 0 { 67 | files, err = filepath.Glob("example/data/data.json") 68 | if err != nil { 69 | panic(fmt.Errorf("error getting import json files")) 70 | } 71 | } 72 | 73 | for _, file := range files { 74 | fmt.Printf("Importing: %s\n", file) 75 | 76 | data, err := ioutil.ReadFile(file) 77 | if err != nil { 78 | panic(fmt.Errorf("error reading import json file %s: %v", file, err)) 79 | } 80 | var entries []*entry 81 | if err := json.Unmarshal((data), &entries); err != nil { 82 | panic(fmt.Errorf("cannot unmarshal data: %s", err)) 83 | } 84 | 85 | for _, entry := range entries { 86 | pair := &api.KVPair{ 87 | Key: entry.Key, 88 | Flags: entry.Flags, 89 | Value: []byte(entry.Value), 90 | } 91 | if _, err := consul.KV().Put(pair, nil); err != nil { 92 | panic(fmt.Errorf("error! Failed writing data for key %s: %s", pair.Key, err)) 93 | } 94 | } 95 | fmt.Printf("Imported: %s\n", file) 96 | } 97 | 98 | return srv 99 | } 100 | 101 | type entry struct { 102 | Key string `json:"key"` 103 | Flags uint64 `json:"flags"` 104 | Value string `json:"value"` 105 | } 106 | 107 | func newConsul(consulAddr, consulToken string) (*api.Client, error) { 108 | conf := api.DefaultConfig() 109 | conf.Address = consulAddr 110 | conf.Token = consulToken 111 | conf.TLSConfig.InsecureSkipVerify = true 112 | 113 | client, err := api.NewClient(conf) 114 | if err != nil { 115 | return nil, fmt.Errorf("error creating consul client: %v", err) 116 | } 117 | 118 | return client, nil 119 | } 120 | -------------------------------------------------------------------------------- /src/DataSource.ts: -------------------------------------------------------------------------------- 1 | import { DataSourceWithBackend, getBackendSrv, getTemplateSrv, toDataQueryResponse } from '@grafana/runtime'; 2 | import { MyDataSourceOptions, ConsulQuery } from './types'; 3 | import { 4 | DataQueryRequest, 5 | DataQueryResponse, 6 | DataSourceInstanceSettings, 7 | LoadingState, 8 | MetricFindValue, 9 | } from '@grafana/data'; 10 | 11 | import { Observable } from 'rxjs'; 12 | import { map } from 'rxjs/operators'; 13 | import _ from 'lodash'; 14 | import { DataQueryResponseData } from '@grafana/data/types/datasource'; 15 | 16 | export class DataSource extends DataSourceWithBackend { 17 | constructor(instanceSettings: DataSourceInstanceSettings) { 18 | super(instanceSettings); 19 | } 20 | 21 | query(options: DataQueryRequest): Observable { 22 | for (const target of options.targets) { 23 | target.target = getTemplateSrv().replace(target.target, options.scopedVars); 24 | } 25 | 26 | // store the targets in activeTargets so we can 27 | // access the legendFormat later on via the refId 28 | let activeTargets: { [key: string]: any } = {}; 29 | for (const target of options.targets) { 30 | if (target.hide) { 31 | continue; 32 | } 33 | activeTargets[target.refId] = target; 34 | } 35 | 36 | return super.query(options).pipe( 37 | map((rsp: DataQueryResponse) => { 38 | const finalRsp: DataQueryResponse = { data: [], state: LoadingState.Done }; 39 | 40 | _.each(rsp.data, (data: any) => { 41 | const legendFormat = activeTargets[data.refId].legendFormat; 42 | 43 | // evaluate legendFormat if it is set 44 | if (!_.isEmpty(legendFormat)) { 45 | data.fields[1].name = this.renderTemplate(legendFormat, data.fields[1].labels); 46 | data.fields[1].labels = []; 47 | finalRsp.data.push(data); 48 | } else { 49 | finalRsp.data.push(data); 50 | } 51 | }); 52 | return finalRsp; 53 | }) 54 | ); 55 | } 56 | 57 | renderTemplate(aliasPattern: string, aliasData: string) { 58 | const aliasRegex = /{{\s*(.+?)\s*}}/g; 59 | return aliasPattern.replace(aliasRegex, function(match, g1) { 60 | if (aliasData[g1]) { 61 | return aliasData[g1]; 62 | } 63 | return g1; 64 | }); 65 | } 66 | 67 | metricFindQuery(query: string): Promise { 68 | return getBackendSrv() 69 | .fetch({ 70 | url: '/api/tsdb/query', 71 | method: 'POST', 72 | data: { 73 | queries: [ 74 | { 75 | target: query, 76 | format: 'timeseries', 77 | type: 'keys', 78 | refId: 'keys', 79 | datasourceId: this.id, 80 | }, 81 | ], 82 | }, 83 | }) 84 | .toPromise() 85 | .then((result: any) => { 86 | let resp: DataQueryResponse = toDataQueryResponse(result); 87 | 88 | let values: MetricFindValue[] = []; 89 | resp.data.forEach((data: DataQueryResponseData) => { 90 | values.push({ text: data.name, expandable: false }); 91 | }); 92 | 93 | return values; 94 | }); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/ConfigEditor.tsx: -------------------------------------------------------------------------------- 1 | import React, { ChangeEvent, PureComponent } from 'react'; 2 | import { LegacyForms } from '@grafana/ui'; 3 | import { DataSourcePluginOptionsEditorProps } from '@grafana/data'; 4 | import { MyDataSourceOptions, MySecureJsonData } from './types'; 5 | 6 | const { SecretFormField, FormField } = LegacyForms; 7 | 8 | interface Props extends DataSourcePluginOptionsEditorProps {} 9 | 10 | interface State {} 11 | 12 | export class ConfigEditor extends PureComponent { 13 | onConsulAddrChange = (event: ChangeEvent) => { 14 | const { onOptionsChange, options } = this.props; 15 | const jsonData = { 16 | ...options.jsonData, 17 | consulAddr: event.target.value, 18 | }; 19 | onOptionsChange({ ...options, jsonData }); 20 | }; 21 | 22 | // Secure field (only sent to the backend) 23 | onConsulTakenChange = (event: ChangeEvent) => { 24 | const { onOptionsChange, options } = this.props; 25 | onOptionsChange({ 26 | ...options, 27 | secureJsonData: { 28 | consulToken: event.target.value, 29 | }, 30 | }); 31 | }; 32 | 33 | onResetConsulToken = () => { 34 | const { onOptionsChange, options } = this.props; 35 | onOptionsChange({ 36 | ...options, 37 | secureJsonFields: { 38 | ...options.secureJsonFields, 39 | consulToken: false, 40 | }, 41 | secureJsonData: { 42 | ...options.secureJsonData, 43 | consulToken: '', 44 | }, 45 | }); 46 | }; 47 | 48 | render() { 49 | const { options } = this.props; 50 | const { jsonData, secureJsonFields } = options; 51 | const secureJsonData = (options.secureJsonData || {}) as MySecureJsonData; 52 | 53 | return ( 54 |
55 |
56 | 65 |
66 | 67 |
68 |
69 | 81 |
82 |
83 |
84 | ); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⚠️ This project has been archived ⚠️ 2 | 3 | 4 | # Grafana datasource for Consul 5 | 6 | [![Travis](https://img.shields.io/travis/sbueringer/grafana-consul-datasource.svg)](https://travis-ci.org/sbueringer/grafana-consul-datasource)[![Codecov](https://img.shields.io/codecov/c/github/sbueringer/grafana-consul-datasource.svg)](https://codecov.io/gh/sbueringer/grafana-consul-datasource)[![CodeFactor](https://www.codefactor.io/repository/github/sbueringer/grafana-consul-datasource/badge)](https://www.codefactor.io/repository/github/sbueringer/grafana-consul-datasource)[![GoReportCard](https://goreportcard.com/badge/github.com/sbueringer/grafana-consul-datasource?style=plastic)](https://goreportcard.com/report/github.com/sbueringer/grafana-consul-datasource)[![GitHub release](https://img.shields.io/github/release/sbueringer/grafana-consul-datasource.svg)](https://github.com/sbueringer/grafana-consul-datasource/releases) 7 | 8 | [![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/sbueringer/grafana-consul-datasource/issues) 9 | 10 | This datasource lets you integrate key value data from Consul in Grafana dashboards. 11 | 12 | ![Overview](https://github.com/sbueringer/grafana-consul-datasource/raw/master/src/images/overview.png) 13 | 14 | # Requirements 15 | 16 | * Grafana version 7.3.x or above are supported 17 | * All recent Consul versions should work 18 | 19 | # Usage 20 | 21 | The data can be used in **table** and **single-stat** panels. The following explanations are based on the example available in the [example folder](https://github.com/sbueringer/grafana-consul-datasource/tree/master/example). 22 | 23 | ## Adding the datasource 24 | 25 | 1. In the side menu in the `Configuration` section you should find a link named `Data Sources`. 26 | 1. Click the `Add data source` button in the top header. 27 | 1. Select `Consul`. 28 | 1. Fill in the datasource name, the Consul address and the Consul token (or leave it empty) 29 | 1. Click the `Save & Test` button 30 | 31 | ## Features 32 | 33 | * Consul keys can be used as Dashboard variable values 34 | * Numeric Consul keys can be retrieved directly and displayed in Singlestat panels 35 | * Consul key/value pairs can be retrieved via Timeseries tags and displayed in Singlestat panels 36 | * Consul key/value pairs can be displayed in Table panels. 37 | 38 | ## Examples 39 | 40 | ### Variables 41 | 42 | ![Variables](https://github.com/sbueringer/grafana-consul-datasource/raw/master/src/images/keys.png) 43 | 44 | This example shows how keys can be queried to use them as variables. This query retrieves all direct subkeys of `registry/apiregistration.k8s.io/apiservices/`. The subkeys are then matched via the regex and can then be used as variable values. 45 | 46 | ### Singlestat Panel 47 | 48 | ![Tags](https://github.com/sbueringer/grafana-consul-datasource/raw/master/src/images/tags.png) 49 | 50 | This example shows how subkeys can be retrieved as tags. These tags can then be displayed in the Single Stat panel by defining a legend format. *Note*: This only works if `Value / Stat` in the `Option` tab is set to `Name`. 51 | 52 | ### Table Panel 53 | 54 | ![Table](https://github.com/sbueringer/grafana-consul-datasource/raw/master/src/images/table.png) 55 | 56 | The final examples shows how key/value pairs can be displayed in tables. Every matching key of the query results in one row. Columns can then be retrieved relative from this key. 57 | -------------------------------------------------------------------------------- /src/images/Consul_VerticalLogo_FullColor.svg: -------------------------------------------------------------------------------- 1 | Asset 1 -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | 2 | name: ci 3 | 4 | on: 5 | push: 6 | tags: 7 | - 'v*.*.*' 8 | 9 | env: 10 | CONSUL_VERSION: '1.8.4' 11 | GOLANGCI_LINT_VERSION: '1.32.2' 12 | MAGE_VERSION: '1.10.0' 13 | NODE_VERSION: '12.x' 14 | YARN_VERSION: '1.21.1' 15 | 16 | jobs: 17 | test: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v3.6.0 22 | 23 | - name: Get the version & set it in package.json 24 | id: get_version 25 | run: | 26 | VERSION=${GITHUB_REF/refs\/tags\/v/} 27 | echo ::set-output name=VERSION::${VERSION} 28 | sed -i "s/1.0.0/${VERSION}/g" package.json 29 | 30 | - name: Use Node.js ${{ env.NODE_VERSION }} 31 | uses: actions/setup-node@v3.8.1 32 | with: 33 | node-version: ${{ env.NODE_VERSION }} 34 | 35 | - name: Set up Go 36 | uses: actions/setup-go@v4.1.0 37 | with: 38 | go-version: 1.15 39 | 40 | - name: Install Consul 41 | run: | 42 | # Install some binaries when not running locally 43 | if ! command -v sudo &> /dev/null 44 | then 45 | apt update 46 | # procps required to execute syctl to find free ports for Consul 47 | apt install zip unzip procps -y 48 | fi 49 | 50 | mkdir -p $GITHUB_WORKSPACE/bin 51 | curl -sLo consul.zip https://releases.hashicorp.com/consul/${CONSUL_VERSION}/consul_${CONSUL_VERSION}_linux_amd64.zip 52 | unzip consul.zip 53 | rm -rf consul.zip 54 | mv consul $GITHUB_WORKSPACE/bin 55 | echo "$GITHUB_WORKSPACE/bin" >> $GITHUB_PATH 56 | 57 | - name: Install Mage 58 | run: | 59 | curl -sLo mage.tar.gz https://github.com/magefile/mage/releases/download/v1.10.0/mage_1.10.0_Linux-64bit.tar.gz 60 | tar -xvf mage.tar.gz 61 | rm -f mage.tar.gz LICENSE 62 | mv mage $GITHUB_WORKSPACE/bin 63 | 64 | - name: Install golangci-lint 65 | run: | 66 | curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v${{ env.GOLANGCI_LINT_VERSION }} 67 | 68 | - name: Build and test frontend 69 | run: | 70 | yarn install 71 | ./node_modules/.bin/grafana-toolkit plugin:ci-build 72 | 73 | - name: Build and test backend 74 | run: | 75 | mage -v buildAll 76 | export CGO_ENABLED=0 77 | mage -v lint 78 | mage -v coverage 79 | 80 | - name: Move results to ci folder and package distro 81 | env: 82 | GRAFANA_API_KEY: ${{ secrets.GRAFANA_API_KEY }} 83 | run: | 84 | ./node_modules/.bin/grafana-toolkit plugin:ci-build --finish 85 | ./node_modules/.bin/grafana-toolkit plugin:ci-package 86 | 87 | ls -la ./ci/jobs/package 88 | ls -la ./ci/packages 89 | ls -la ./ci/dist 90 | ls -la ./ci/grafana-test-env 91 | 92 | - name: Create release 93 | id: create_release 94 | uses: actions/create-release@v1.1.4 95 | env: 96 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token 97 | with: 98 | tag_name: ${{ github.ref }} 99 | release_name: ${{ github.ref }} 100 | body: | 101 | TODO: change me 102 | draft: true 103 | prerelease: false 104 | 105 | - name: Upload plugin to release 106 | id: upload-release-asset 107 | uses: actions/upload-release-asset@v1.0.2 108 | env: 109 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 110 | with: 111 | upload_url: ${{ steps.create_release.outputs.upload_url }} 112 | asset_path: ./ci/packages/sbueringer-consul-datasource-${{ steps.get_version.outputs.VERSION }}.zip 113 | asset_name: sbueringer-consul-datasource-${{ steps.get_version.outputs.VERSION }}.zip 114 | asset_content_type: application/zip 115 | -------------------------------------------------------------------------------- /pkg/testdata/k8s-export.kind.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "key": "registry/apiregistration.k8s.io/apiservices/v1./kind", 4 | "flags": 0, 5 | "value": "APIService" 6 | }, 7 | { 8 | "key": "registry/apiregistration.k8s.io/apiservices/v1.apps/kind", 9 | "flags": 0, 10 | "value": "APIService" 11 | }, 12 | { 13 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/kind", 14 | "flags": 0, 15 | "value": "APIService" 16 | }, 17 | { 18 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io/kind", 19 | "flags": 0, 20 | "value": "APIService" 21 | }, 22 | { 23 | "key": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/kind", 24 | "flags": 0, 25 | "value": "APIService" 26 | }, 27 | { 28 | "key": "registry/apiregistration.k8s.io/apiservices/v1.batch/kind", 29 | "flags": 0, 30 | "value": "APIService" 31 | }, 32 | { 33 | "key": "registry/apiregistration.k8s.io/apiservices/v1.crd.projectcalico.org/kind", 34 | "flags": 0, 35 | "value": "APIService" 36 | }, 37 | { 38 | "key": "registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io/kind", 39 | "flags": 0, 40 | "value": "APIService" 41 | }, 42 | { 43 | "key": "registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io/kind", 44 | "flags": 0, 45 | "value": "APIService" 46 | }, 47 | { 48 | "key": "registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io/kind", 49 | "flags": 0, 50 | "value": "APIService" 51 | }, 52 | { 53 | "key": "registry/apiregistration.k8s.io/apiservices/v1alpha1.scheduling.k8s.io/kind", 54 | "flags": 0, 55 | "value": "APIService" 56 | }, 57 | { 58 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io/kind", 59 | "flags": 0, 60 | "value": "APIService" 61 | }, 62 | { 63 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io/kind", 64 | "flags": 0, 65 | "value": "APIService" 66 | }, 67 | { 68 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apps/kind", 69 | "flags": 0, 70 | "value": "APIService" 71 | }, 72 | { 73 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io/kind", 74 | "flags": 0, 75 | "value": "APIService" 76 | }, 77 | { 78 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io/kind", 79 | "flags": 0, 80 | "value": "APIService" 81 | }, 82 | { 83 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.batch/kind", 84 | "flags": 0, 85 | "value": "APIService" 86 | }, 87 | { 88 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io/kind", 89 | "flags": 0, 90 | "value": "APIService" 91 | }, 92 | { 93 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io/kind", 94 | "flags": 0, 95 | "value": "APIService" 96 | }, 97 | { 98 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.extensions/kind", 99 | "flags": 0, 100 | "value": "APIService" 101 | }, 102 | { 103 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.policy/kind", 104 | "flags": 0, 105 | "value": "APIService" 106 | }, 107 | { 108 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/kind", 109 | "flags": 0, 110 | "value": "APIService" 111 | }, 112 | { 113 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io/kind", 114 | "flags": 0, 115 | "value": "APIService" 116 | }, 117 | { 118 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta2.apps/kind", 119 | "flags": 0, 120 | "value": "APIService" 121 | }, 122 | { 123 | "key": "registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling/kind", 124 | "flags": 0, 125 | "value": "APIService" 126 | } 127 | ] 128 | -------------------------------------------------------------------------------- /pkg/testdata/k8s-export.spec.version.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "key": "registry/apiregistration.k8s.io/apiservices/v1./spec/version", 4 | "flags": 0, 5 | "value": "v1" 6 | }, 7 | { 8 | "key": "registry/apiregistration.k8s.io/apiservices/v1.apps/spec/version", 9 | "flags": 0, 10 | "value": "v1" 11 | }, 12 | { 13 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/spec/version", 14 | "flags": 0, 15 | "value": "v1" 16 | }, 17 | { 18 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io/spec/version", 19 | "flags": 0, 20 | "value": "v1" 21 | }, 22 | { 23 | "key": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/spec/version", 24 | "flags": 0, 25 | "value": "v1" 26 | }, 27 | { 28 | "key": "registry/apiregistration.k8s.io/apiservices/v1.batch/spec/version", 29 | "flags": 0, 30 | "value": "v1" 31 | }, 32 | { 33 | "key": "registry/apiregistration.k8s.io/apiservices/v1.crd.projectcalico.org/spec/version", 34 | "flags": 0, 35 | "value": "v1" 36 | }, 37 | { 38 | "key": "registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io/spec/version", 39 | "flags": 0, 40 | "value": "v1" 41 | }, 42 | { 43 | "key": "registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io/spec/version", 44 | "flags": 0, 45 | "value": "v1" 46 | }, 47 | { 48 | "key": "registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io/spec/version", 49 | "flags": 0, 50 | "value": "v1" 51 | }, 52 | { 53 | "key": "registry/apiregistration.k8s.io/apiservices/v1alpha1.scheduling.k8s.io/spec/version", 54 | "flags": 0, 55 | "value": "v1alpha1" 56 | }, 57 | { 58 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io/spec/version", 59 | "flags": 0, 60 | "value": "v1beta1" 61 | }, 62 | { 63 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io/spec/version", 64 | "flags": 0, 65 | "value": "v1beta1" 66 | }, 67 | { 68 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apps/spec/version", 69 | "flags": 0, 70 | "value": "v1beta1" 71 | }, 72 | { 73 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io/spec/version", 74 | "flags": 0, 75 | "value": "v1beta1" 76 | }, 77 | { 78 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io/spec/version", 79 | "flags": 0, 80 | "value": "v1beta1" 81 | }, 82 | { 83 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.batch/spec/version", 84 | "flags": 0, 85 | "value": "v1beta1" 86 | }, 87 | { 88 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io/spec/version", 89 | "flags": 0, 90 | "value": "v1beta1" 91 | }, 92 | { 93 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io/spec/version", 94 | "flags": 0, 95 | "value": "v1beta1" 96 | }, 97 | { 98 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.extensions/spec/version", 99 | "flags": 0, 100 | "value": "v1beta1" 101 | }, 102 | { 103 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.policy/spec/version", 104 | "flags": 0, 105 | "value": "v1beta1" 106 | }, 107 | { 108 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/spec/version", 109 | "flags": 0, 110 | "value": "v1beta1" 111 | }, 112 | { 113 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io/spec/version", 114 | "flags": 0, 115 | "value": "v1beta1" 116 | }, 117 | { 118 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta2.apps/spec/version", 119 | "flags": 0, 120 | "value": "v1beta2" 121 | }, 122 | { 123 | "key": "registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling/spec/version", 124 | "flags": 0, 125 | "value": "v2beta1" 126 | } 127 | ] 128 | -------------------------------------------------------------------------------- /pkg/testdata/k8s-export.spec.versionPriority.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "key": "registry/apiregistration.k8s.io/apiservices/v1./spec/versionPriority", 4 | "flags": 0, 5 | "value": "1" 6 | }, 7 | { 8 | "key": "registry/apiregistration.k8s.io/apiservices/v1.apps/spec/versionPriority", 9 | "flags": 0, 10 | "value": "15" 11 | }, 12 | { 13 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/spec/versionPriority", 14 | "flags": 0, 15 | "value": "15" 16 | }, 17 | { 18 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io/spec/versionPriority", 19 | "flags": 0, 20 | "value": "15" 21 | }, 22 | { 23 | "key": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/spec/versionPriority", 24 | "flags": 0, 25 | "value": "15" 26 | }, 27 | { 28 | "key": "registry/apiregistration.k8s.io/apiservices/v1.batch/spec/versionPriority", 29 | "flags": 0, 30 | "value": "15" 31 | }, 32 | { 33 | "key": "registry/apiregistration.k8s.io/apiservices/v1.crd.projectcalico.org/spec/versionPriority", 34 | "flags": 0, 35 | "value": "100" 36 | }, 37 | { 38 | "key": "registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io/spec/versionPriority", 39 | "flags": 0, 40 | "value": "15" 41 | }, 42 | { 43 | "key": "registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io/spec/versionPriority", 44 | "flags": 0, 45 | "value": "15" 46 | }, 47 | { 48 | "key": "registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io/spec/versionPriority", 49 | "flags": 0, 50 | "value": "15" 51 | }, 52 | { 53 | "key": "registry/apiregistration.k8s.io/apiservices/v1alpha1.scheduling.k8s.io/spec/versionPriority", 54 | "flags": 0, 55 | "value": "9" 56 | }, 57 | { 58 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io/spec/versionPriority", 59 | "flags": 0, 60 | "value": "12" 61 | }, 62 | { 63 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io/spec/versionPriority", 64 | "flags": 0, 65 | "value": "9" 66 | }, 67 | { 68 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apps/spec/versionPriority", 69 | "flags": 0, 70 | "value": "1" 71 | }, 72 | { 73 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io/spec/versionPriority", 74 | "flags": 0, 75 | "value": "9" 76 | }, 77 | { 78 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io/spec/versionPriority", 79 | "flags": 0, 80 | "value": "9" 81 | }, 82 | { 83 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.batch/spec/versionPriority", 84 | "flags": 0, 85 | "value": "9" 86 | }, 87 | { 88 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io/spec/versionPriority", 89 | "flags": 0, 90 | "value": "9" 91 | }, 92 | { 93 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io/spec/versionPriority", 94 | "flags": 0, 95 | "value": "5" 96 | }, 97 | { 98 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.extensions/spec/versionPriority", 99 | "flags": 0, 100 | "value": "1" 101 | }, 102 | { 103 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.policy/spec/versionPriority", 104 | "flags": 0, 105 | "value": "9" 106 | }, 107 | { 108 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/spec/versionPriority", 109 | "flags": 0, 110 | "value": "12" 111 | }, 112 | { 113 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io/spec/versionPriority", 114 | "flags": 0, 115 | "value": "9" 116 | }, 117 | { 118 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta2.apps/spec/versionPriority", 119 | "flags": 0, 120 | "value": "9" 121 | }, 122 | { 123 | "key": "registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling/spec/versionPriority", 124 | "flags": 0, 125 | "value": "9" 126 | } 127 | ] 128 | -------------------------------------------------------------------------------- /pkg/testdata/k8s-export.name.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "key": "registry/apiregistration.k8s.io/apiservices/v1./name", 4 | "flags": 0, 5 | "value": "v1." 6 | }, 7 | { 8 | "key": "registry/apiregistration.k8s.io/apiservices/v1.apps/name", 9 | "flags": 0, 10 | "value": "v1.apps" 11 | }, 12 | { 13 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/name", 14 | "flags": 0, 15 | "value": "v1.authentication.k8s.io" 16 | }, 17 | { 18 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io/name", 19 | "flags": 0, 20 | "value": "v1.authorization.k8s.io" 21 | }, 22 | { 23 | "key": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/name", 24 | "flags": 0, 25 | "value": "v1.autoscaling" 26 | }, 27 | { 28 | "key": "registry/apiregistration.k8s.io/apiservices/v1.batch/name", 29 | "flags": 0, 30 | "value": "v1.batch" 31 | }, 32 | { 33 | "key": "registry/apiregistration.k8s.io/apiservices/v1.crd.projectcalico.org/name", 34 | "flags": 0, 35 | "value": "v1.crd.projectcalico.org" 36 | }, 37 | { 38 | "key": "registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io/name", 39 | "flags": 0, 40 | "value": "v1.networking.k8s.io" 41 | }, 42 | { 43 | "key": "registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io/name", 44 | "flags": 0, 45 | "value": "v1.rbac.authorization.k8s.io" 46 | }, 47 | { 48 | "key": "registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io/name", 49 | "flags": 0, 50 | "value": "v1.storage.k8s.io" 51 | }, 52 | { 53 | "key": "registry/apiregistration.k8s.io/apiservices/v1alpha1.scheduling.k8s.io/name", 54 | "flags": 0, 55 | "value": "v1alpha1.scheduling.k8s.io" 56 | }, 57 | { 58 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io/name", 59 | "flags": 0, 60 | "value": "v1beta1.admissionregistration.k8s.io" 61 | }, 62 | { 63 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io/name", 64 | "flags": 0, 65 | "value": "v1beta1.apiextensions.k8s.io" 66 | }, 67 | { 68 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apps/name", 69 | "flags": 0, 70 | "value": "v1beta1.apps" 71 | }, 72 | { 73 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io/name", 74 | "flags": 0, 75 | "value": "v1beta1.authentication.k8s.io" 76 | }, 77 | { 78 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io/name", 79 | "flags": 0, 80 | "value": "v1beta1.authorization.k8s.io" 81 | }, 82 | { 83 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.batch/name", 84 | "flags": 0, 85 | "value": "v1beta1.batch" 86 | }, 87 | { 88 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io/name", 89 | "flags": 0, 90 | "value": "v1beta1.certificates.k8s.io" 91 | }, 92 | { 93 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io/name", 94 | "flags": 0, 95 | "value": "v1beta1.events.k8s.io" 96 | }, 97 | { 98 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.extensions/name", 99 | "flags": 0, 100 | "value": "v1beta1.extensions" 101 | }, 102 | { 103 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.policy/name", 104 | "flags": 0, 105 | "value": "v1beta1.policy" 106 | }, 107 | { 108 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/name", 109 | "flags": 0, 110 | "value": "v1beta1.rbac.authorization.k8s.io" 111 | }, 112 | { 113 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io/name", 114 | "flags": 0, 115 | "value": "v1beta1.storage.k8s.io" 116 | }, 117 | { 118 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta2.apps/name", 119 | "flags": 0, 120 | "value": "v1beta2.apps" 121 | }, 122 | { 123 | "key": "registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling/name", 124 | "flags": 0, 125 | "value": "v2beta1.autoscaling" 126 | } 127 | ] 128 | -------------------------------------------------------------------------------- /pkg/testdata/k8s-export.spec.group.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "key": "registry/apiregistration.k8s.io/apiservices/v1./spec/group", 4 | "flags": 0, 5 | "value": null 6 | }, 7 | { 8 | "key": "registry/apiregistration.k8s.io/apiservices/v1.apps/spec/group", 9 | "flags": 0, 10 | "value": "apps" 11 | }, 12 | { 13 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/spec/group", 14 | "flags": 0, 15 | "value": "authentication.k8s.io" 16 | }, 17 | { 18 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io/spec/group", 19 | "flags": 0, 20 | "value": "authorization.k8s.io" 21 | }, 22 | { 23 | "key": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/spec/group", 24 | "flags": 0, 25 | "value": "autoscaling" 26 | }, 27 | { 28 | "key": "registry/apiregistration.k8s.io/apiservices/v1.batch/spec/group", 29 | "flags": 0, 30 | "value": "batch" 31 | }, 32 | { 33 | "key": "registry/apiregistration.k8s.io/apiservices/v1.crd.projectcalico.org/spec/group", 34 | "flags": 0, 35 | "value": "crd.projectcalico.org" 36 | }, 37 | { 38 | "key": "registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io/spec/group", 39 | "flags": 0, 40 | "value": "networking.k8s.io" 41 | }, 42 | { 43 | "key": "registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io/spec/group", 44 | "flags": 0, 45 | "value": "rbac.authorization.k8s.io" 46 | }, 47 | { 48 | "key": "registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io/spec/group", 49 | "flags": 0, 50 | "value": "storage.k8s.io" 51 | }, 52 | { 53 | "key": "registry/apiregistration.k8s.io/apiservices/v1alpha1.scheduling.k8s.io/spec/group", 54 | "flags": 0, 55 | "value": "scheduling.k8s.io" 56 | }, 57 | { 58 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io/spec/group", 59 | "flags": 0, 60 | "value": "admissionregistration.k8s.io" 61 | }, 62 | { 63 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io/spec/group", 64 | "flags": 0, 65 | "value": "apiextensions.k8s.io" 66 | }, 67 | { 68 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apps/spec/group", 69 | "flags": 0, 70 | "value": "apps" 71 | }, 72 | { 73 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io/spec/group", 74 | "flags": 0, 75 | "value": "authentication.k8s.io" 76 | }, 77 | { 78 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io/spec/group", 79 | "flags": 0, 80 | "value": "authorization.k8s.io" 81 | }, 82 | { 83 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.batch/spec/group", 84 | "flags": 0, 85 | "value": "batch" 86 | }, 87 | { 88 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io/spec/group", 89 | "flags": 0, 90 | "value": "certificates.k8s.io" 91 | }, 92 | { 93 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io/spec/group", 94 | "flags": 0, 95 | "value": "events.k8s.io" 96 | }, 97 | { 98 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.extensions/spec/group", 99 | "flags": 0, 100 | "value": "extensions" 101 | }, 102 | { 103 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.policy/spec/group", 104 | "flags": 0, 105 | "value": "policy" 106 | }, 107 | { 108 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/spec/group", 109 | "flags": 0, 110 | "value": "rbac.authorization.k8s.io" 111 | }, 112 | { 113 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io/spec/group", 114 | "flags": 0, 115 | "value": "storage.k8s.io" 116 | }, 117 | { 118 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta2.apps/spec/group", 119 | "flags": 0, 120 | "value": "apps" 121 | }, 122 | { 123 | "key": "registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling/spec/group", 124 | "flags": 0, 125 | "value": "autoscaling" 126 | } 127 | ] 128 | -------------------------------------------------------------------------------- /pkg/testdata/k8s-export.spec.groupPriorityMinimum.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "key": "registry/apiregistration.k8s.io/apiservices/v1./spec/groupPriorityMinimum", 4 | "flags": 0, 5 | "value": "18000" 6 | }, 7 | { 8 | "key": "registry/apiregistration.k8s.io/apiservices/v1.apps/spec/groupPriorityMinimum", 9 | "flags": 0, 10 | "value": "17800" 11 | }, 12 | { 13 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/spec/groupPriorityMinimum", 14 | "flags": 0, 15 | "value": "17700" 16 | }, 17 | { 18 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io/spec/groupPriorityMinimum", 19 | "flags": 0, 20 | "value": "17600" 21 | }, 22 | { 23 | "key": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/spec/groupPriorityMinimum", 24 | "flags": 0, 25 | "value": "17500" 26 | }, 27 | { 28 | "key": "registry/apiregistration.k8s.io/apiservices/v1.batch/spec/groupPriorityMinimum", 29 | "flags": 0, 30 | "value": "17400" 31 | }, 32 | { 33 | "key": "registry/apiregistration.k8s.io/apiservices/v1.crd.projectcalico.org/spec/groupPriorityMinimum", 34 | "flags": 0, 35 | "value": "1000" 36 | }, 37 | { 38 | "key": "registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io/spec/groupPriorityMinimum", 39 | "flags": 0, 40 | "value": "17200" 41 | }, 42 | { 43 | "key": "registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io/spec/groupPriorityMinimum", 44 | "flags": 0, 45 | "value": "17000" 46 | }, 47 | { 48 | "key": "registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io/spec/groupPriorityMinimum", 49 | "flags": 0, 50 | "value": "16800" 51 | }, 52 | { 53 | "key": "registry/apiregistration.k8s.io/apiservices/v1alpha1.scheduling.k8s.io/spec/groupPriorityMinimum", 54 | "flags": 0, 55 | "value": "16600" 56 | }, 57 | { 58 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io/spec/groupPriorityMinimum", 59 | "flags": 0, 60 | "value": "16700" 61 | }, 62 | { 63 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io/spec/groupPriorityMinimum", 64 | "flags": 0, 65 | "value": "16700" 66 | }, 67 | { 68 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apps/spec/groupPriorityMinimum", 69 | "flags": 0, 70 | "value": "17800" 71 | }, 72 | { 73 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io/spec/groupPriorityMinimum", 74 | "flags": 0, 75 | "value": "17700" 76 | }, 77 | { 78 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io/spec/groupPriorityMinimum", 79 | "flags": 0, 80 | "value": "17600" 81 | }, 82 | { 83 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.batch/spec/groupPriorityMinimum", 84 | "flags": 0, 85 | "value": "17400" 86 | }, 87 | { 88 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io/spec/groupPriorityMinimum", 89 | "flags": 0, 90 | "value": "17300" 91 | }, 92 | { 93 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io/spec/groupPriorityMinimum", 94 | "flags": 0, 95 | "value": "17750" 96 | }, 97 | { 98 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.extensions/spec/groupPriorityMinimum", 99 | "flags": 0, 100 | "value": "17900" 101 | }, 102 | { 103 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.policy/spec/groupPriorityMinimum", 104 | "flags": 0, 105 | "value": "17100" 106 | }, 107 | { 108 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/spec/groupPriorityMinimum", 109 | "flags": 0, 110 | "value": "17000" 111 | }, 112 | { 113 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io/spec/groupPriorityMinimum", 114 | "flags": 0, 115 | "value": "16800" 116 | }, 117 | { 118 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta2.apps/spec/groupPriorityMinimum", 119 | "flags": 0, 120 | "value": "17800" 121 | }, 122 | { 123 | "key": "registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling/spec/groupPriorityMinimum", 124 | "flags": 0, 125 | "value": "17500" 126 | } 127 | ] 128 | -------------------------------------------------------------------------------- /pkg/testdata/k8s-export.apiVersion.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "key": "registry/apiregistration.k8s.io/apiservices/v1./apiVersion", 4 | "flags": 0, 5 | "value": "apiregistration.k8s.io/v1beta1" 6 | }, 7 | { 8 | "key": "registry/apiregistration.k8s.io/apiservices/v1.apps/apiVersion", 9 | "flags": 0, 10 | "value": "apiregistration.k8s.io/v1beta1" 11 | }, 12 | { 13 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/apiVersion", 14 | "flags": 0, 15 | "value": "apiregistration.k8s.io/v1beta1" 16 | }, 17 | { 18 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io/apiVersion", 19 | "flags": 0, 20 | "value": "apiregistration.k8s.io/v1beta1" 21 | }, 22 | { 23 | "key": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/apiVersion", 24 | "flags": 0, 25 | "value": "apiregistration.k8s.io/v1beta1" 26 | }, 27 | { 28 | "key": "registry/apiregistration.k8s.io/apiservices/v1.batch/apiVersion", 29 | "flags": 0, 30 | "value": "apiregistration.k8s.io/v1beta1" 31 | }, 32 | { 33 | "key": "registry/apiregistration.k8s.io/apiservices/v1.crd.projectcalico.org/apiVersion", 34 | "flags": 0, 35 | "value": "apiregistration.k8s.io/v1beta1" 36 | }, 37 | { 38 | "key": "registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io/apiVersion", 39 | "flags": 0, 40 | "value": "apiregistration.k8s.io/v1beta1" 41 | }, 42 | { 43 | "key": "registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io/apiVersion", 44 | "flags": 0, 45 | "value": "apiregistration.k8s.io/v1beta1" 46 | }, 47 | { 48 | "key": "registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io/apiVersion", 49 | "flags": 0, 50 | "value": "apiregistration.k8s.io/v1beta1" 51 | }, 52 | { 53 | "key": "registry/apiregistration.k8s.io/apiservices/v1alpha1.scheduling.k8s.io/apiVersion", 54 | "flags": 0, 55 | "value": "apiregistration.k8s.io/v1beta1" 56 | }, 57 | { 58 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io/apiVersion", 59 | "flags": 0, 60 | "value": "apiregistration.k8s.io/v1beta1" 61 | }, 62 | { 63 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io/apiVersion", 64 | "flags": 0, 65 | "value": "apiregistration.k8s.io/v1beta1" 66 | }, 67 | { 68 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apps/apiVersion", 69 | "flags": 0, 70 | "value": "apiregistration.k8s.io/v1beta1" 71 | }, 72 | { 73 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io/apiVersion", 74 | "flags": 0, 75 | "value": "apiregistration.k8s.io/v1beta1" 76 | }, 77 | { 78 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io/apiVersion", 79 | "flags": 0, 80 | "value": "apiregistration.k8s.io/v1beta1" 81 | }, 82 | { 83 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.batch/apiVersion", 84 | "flags": 0, 85 | "value": "apiregistration.k8s.io/v1beta1" 86 | }, 87 | { 88 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io/apiVersion", 89 | "flags": 0, 90 | "value": "apiregistration.k8s.io/v1beta1" 91 | }, 92 | { 93 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io/apiVersion", 94 | "flags": 0, 95 | "value": "apiregistration.k8s.io/v1beta1" 96 | }, 97 | { 98 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.extensions/apiVersion", 99 | "flags": 0, 100 | "value": "apiregistration.k8s.io/v1beta1" 101 | }, 102 | { 103 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.policy/apiVersion", 104 | "flags": 0, 105 | "value": "apiregistration.k8s.io/v1beta1" 106 | }, 107 | { 108 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/apiVersion", 109 | "flags": 0, 110 | "value": "apiregistration.k8s.io/v1beta1" 111 | }, 112 | { 113 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io/apiVersion", 114 | "flags": 0, 115 | "value": "apiregistration.k8s.io/v1beta1" 116 | }, 117 | { 118 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta2.apps/apiVersion", 119 | "flags": 0, 120 | "value": "apiregistration.k8s.io/v1beta1" 121 | }, 122 | { 123 | "key": "registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling/apiVersion", 124 | "flags": 0, 125 | "value": "apiregistration.k8s.io/v1beta1" 126 | } 127 | ] 128 | -------------------------------------------------------------------------------- /src/QueryEditor.tsx: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import { InlineFormLabel, Select } from '@grafana/ui'; 3 | import { QueryEditorProps, SelectableValue } from '@grafana/data'; 4 | import { DataSource } from './DataSource'; 5 | import { ConsulQuery, MyDataSourceOptions } from './types'; 6 | 7 | type Props = QueryEditorProps; 8 | 9 | const FORMAT_OPTIONS: Array> = [ 10 | { label: 'Time series', value: 'timeseries' }, 11 | { label: 'Table', value: 'table' }, 12 | ]; 13 | 14 | const TYPE_OPTIONS: Array> = [ 15 | { label: 'get value', value: 'get' }, 16 | { label: 'get direct subkeys', value: 'keys' }, 17 | { label: 'get subkeys as tags', value: 'tags' }, 18 | { label: 'get subkeys recursive as tags', value: 'tagsrec' }, 19 | ]; 20 | 21 | interface State { 22 | target: string; 23 | formatOption: SelectableValue; 24 | typeOption: SelectableValue; 25 | legendFormat?: string; 26 | columns?: string; 27 | } 28 | 29 | export class QueryEditor extends PureComponent { 30 | // Query target to be modified and used for queries 31 | query: ConsulQuery; 32 | 33 | constructor(props: Props) { 34 | super(props); 35 | const defaultQuery: Partial = { 36 | target: '', 37 | format: 'timeseries', 38 | type: 'get', 39 | legendFormat: '', 40 | columns: '', 41 | }; 42 | const query = Object.assign({}, defaultQuery, props.query); 43 | this.query = query; 44 | // Query target properties that are fully controlled inputs 45 | this.state = { 46 | target: query.target, 47 | // Fully controlled text inputs 48 | legendFormat: query.legendFormat, 49 | // Select options 50 | formatOption: FORMAT_OPTIONS.find(option => option.value === query.format) || FORMAT_OPTIONS[0], 51 | // Select options 52 | typeOption: TYPE_OPTIONS.find(option => option.value === query.type) || TYPE_OPTIONS[0], 53 | 54 | columns: query.columns, 55 | }; 56 | } 57 | 58 | onTargetChanged = (e: React.SyntheticEvent) => { 59 | const target = e.currentTarget.value; 60 | this.query.target = target; 61 | this.setState({ target: target }, this.onRunQuery); 62 | }; 63 | 64 | onFormatChange = (option: SelectableValue) => { 65 | this.query.format = option.value; 66 | this.setState({ formatOption: option }, this.onRunQuery); 67 | }; 68 | 69 | onTypeChange = (option: SelectableValue) => { 70 | this.query.type = option.value; 71 | this.setState({ typeOption: option }, this.onRunQuery); 72 | }; 73 | 74 | onLegendChange = (e: React.SyntheticEvent) => { 75 | const legendFormat = e.currentTarget.value; 76 | this.query.legendFormat = legendFormat; 77 | this.setState({ legendFormat }, this.onRunQuery); 78 | }; 79 | 80 | onColumnsChange = (e: React.SyntheticEvent) => { 81 | const columns = e.currentTarget.value; 82 | this.query.columns = columns; 83 | this.setState({ columns }, this.onRunQuery); 84 | }; 85 | 86 | onRunQuery = () => { 87 | const { query } = this; 88 | this.props.onChange(query); 89 | this.props.onRunQuery(); 90 | }; 91 | 92 | render() { 93 | const { target, formatOption, typeOption, legendFormat, columns } = this.state; 94 | 95 | return ( 96 |
97 |
98 | 106 |
107 | 108 |
109 |
Format
110 | 128 |
129 | ) : null} 130 | 131 | {formatOption.value === 'timeseries' ? ( 132 |
133 | 138 | Legend 139 | 140 | 148 |
149 | ) : null} 150 | 151 | {formatOption.value === 'table' ? ( 152 |
153 | 154 | Columns 155 | 156 | 164 |
165 | ) : null} 166 |
167 | 168 | ); 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /pkg/plugin_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "fmt" 8 | "io/ioutil" 9 | "os" 10 | "path" 11 | "path/filepath" 12 | "strings" 13 | "testing" 14 | 15 | "github.com/hashicorp/consul/api" 16 | "github.com/hashicorp/consul/sdk/testutil" 17 | "github.com/sergi/go-diff/diffmatchpatch" 18 | ) 19 | 20 | func TestQuery(t *testing.T) { 21 | 22 | var tests = []struct { 23 | name string 24 | queries map[string]queryModel 25 | golden string 26 | }{ 27 | { 28 | name: "empty query", 29 | queries: map[string]queryModel{}, 30 | golden: "empty-query.json", 31 | }, 32 | { 33 | name: "nil query", 34 | queries: nil, 35 | golden: "no-query.json", 36 | }, 37 | { 38 | name: "timeseries get", 39 | queries: map[string]queryModel{ 40 | "abc": { 41 | Format: "timeseries", 42 | Type: "get", 43 | Target: "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/spec/groupPriorityMinimum", 44 | }, 45 | }, 46 | golden: "timeseries-get.json", 47 | }, 48 | { 49 | name: "timeseries get with trailing slash", 50 | queries: map[string]queryModel{ 51 | "abc": { 52 | Format: "timeseries", 53 | Type: "get", 54 | Target: "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/spec/groupPriorityMinimum/", 55 | }, 56 | }, 57 | golden: "timeseries-get.json", 58 | }, 59 | { 60 | name: "timeseries keys", 61 | queries: map[string]queryModel{ 62 | "def": { 63 | Format: "timeseries", 64 | Type: "keys", 65 | Target: "registry/apiregistration.k8s.io/apiservices", 66 | }, 67 | }, 68 | golden: "timeseries-keys.json", 69 | }, 70 | { 71 | name: "timeseries keys with trailing slash", 72 | queries: map[string]queryModel{ 73 | "def": { 74 | Format: "timeseries", 75 | Type: "keys", 76 | Target: "registry/apiregistration.k8s.io/apiservices/", 77 | }, 78 | }, 79 | golden: "timeseries-keys.json", 80 | }, 81 | { 82 | name: "timeseries tags", 83 | queries: map[string]queryModel{ 84 | "xyz": { 85 | Format: "timeseries", 86 | Type: "tags", 87 | Target: "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io", 88 | }, 89 | }, 90 | golden: "timeseries-tags.json", 91 | }, 92 | { 93 | name: "timeseries tags with trailing slash", 94 | queries: map[string]queryModel{ 95 | "xyz": { 96 | Format: "timeseries", 97 | Type: "tags", 98 | Target: "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/", 99 | }, 100 | }, 101 | golden: "timeseries-tags.json", 102 | }, 103 | { 104 | name: "timeseries tagsrec", 105 | queries: map[string]queryModel{ 106 | "xyz": { 107 | Format: "timeseries", 108 | Type: "tagsrec", 109 | Target: "registry/apiregistration.k8s.io/apiservices/v1.autoscaling", 110 | }, 111 | }, 112 | golden: "timeseries-tagsrec.json", 113 | }, 114 | { 115 | name: "timeseries tagsrec with trailing slash", 116 | queries: map[string]queryModel{ 117 | "xyz": { 118 | Format: "timeseries", 119 | Type: "tagsrec", 120 | Target: "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/", 121 | }, 122 | }, 123 | golden: "timeseries-tagsrec.json", 124 | }, 125 | { 126 | name: "timeseries type unknown", 127 | queries: map[string]queryModel{ 128 | "xyz": { 129 | Format: "timeseries", 130 | Type: "unknown", 131 | Target: "registry", 132 | }, 133 | }, 134 | golden: "timeseries-unknown.json", 135 | }, 136 | { 137 | name: "table", 138 | queries: map[string]queryModel{ 139 | "xyz": { 140 | Format: "table", 141 | Target: "registry/apiregistration.k8s.io/apiservices/*/name", 142 | Columns: "../name,../kind,../apiVersion,../spec/group,../spec/groupPriorityMinimum,../spec/version,../spec/versionPriority", 143 | }, 144 | }, 145 | golden: "table.json", 146 | }, 147 | } 148 | 149 | srv, consul := setupTestServer(t) 150 | defer srv.Stop() 151 | 152 | for _, tt := range tests { 153 | t.Run(tt.name, func(t *testing.T) { 154 | response := query(context.TODO(), consul, tt.queries) 155 | 156 | text, _ := json.MarshalIndent(response, "", " ") 157 | 158 | goldenFile := path.Join("testdata/golden", tt.golden) 159 | writeGolden := false 160 | if writeGolden { 161 | ioutil.WriteFile(path.Join(goldenFile), text, os.ModePerm) 162 | } 163 | 164 | // errors and values are not printed, because they are unexported fields 165 | golden, err := ioutil.ReadFile(goldenFile) 166 | if err != nil { 167 | t.Fatalf("could not read golden file %s: %v", goldenFile, err) 168 | } 169 | 170 | dmp := diffmatchpatch.New() 171 | 172 | diffs := dmp.DiffMain(string(golden), string(text), false) 173 | 174 | if !(len(diffs) == 1 && diffs[0].Type == diffmatchpatch.DiffEqual) { 175 | t.Errorf("result for query %+v was not as expected\n", tt.queries) 176 | t.Logf("diff to golden %s:\n%s", tt.golden, diffPrettyText(diffs)) 177 | } 178 | }) 179 | } 180 | } 181 | 182 | func diffPrettyText(diffs []diffmatchpatch.Diff) string { 183 | var buff bytes.Buffer 184 | for _, diff := range diffs { 185 | text := diff.Text 186 | 187 | switch diff.Type { 188 | case diffmatchpatch.DiffInsert: 189 | _, _ = buff.WriteString("\x1b[32m") 190 | text = strings.Replace(text, "\n", "\n\x1b[32m", -1) 191 | _, _ = buff.WriteString(text) 192 | _, _ = buff.WriteString("\x1b[0m") 193 | case diffmatchpatch.DiffDelete: 194 | _, _ = buff.WriteString("\x1b[31m") 195 | text = strings.Replace(text, "\n", "\n\x1b[31m", -1) 196 | _, _ = buff.WriteString(text) 197 | _, _ = buff.WriteString("\x1b[0m") 198 | case diffmatchpatch.DiffEqual: 199 | newLineCount := strings.Count(text, "\n") 200 | if newLineCount > 3 { 201 | firstNewLine := strings.Index(text, "\n") 202 | secondNewLine := firstNewLine + strings.Index(text[firstNewLine+1:], "\n") 203 | secondLastNewLine := strings.LastIndex(text[:strings.LastIndex(text, "\n")], "\n") 204 | firstText := text[:secondNewLine+1] 205 | lastText := text[secondLastNewLine:] 206 | text = firstText + "\n..." + lastText 207 | } 208 | _, _ = buff.WriteString(text) 209 | } 210 | } 211 | 212 | return buff.String() 213 | } 214 | 215 | func setupTestServer(t *testing.T) (*testutil.TestServer, *api.Client) { 216 | srv, err := testutil.NewTestServerConfigT(&testing.T{}, func(c *testutil.TestServerConfig) { 217 | //c.Stdout = ioutil.Discard 218 | //c.Stderr = ioutil.Discard 219 | c.Ports = &testutil.TestPortConfig{ 220 | HTTP: 8500, 221 | } 222 | 223 | c.Datacenter = "default" 224 | c.LogLevel = "debug" 225 | }) 226 | if err != nil { 227 | t.Fatal(err) 228 | } 229 | 230 | fmt.Println("Importing example data to Consul") 231 | 232 | consul, err := newConsul(srv.HTTPAddr, srv.Config.ACLMasterToken) 233 | if err != nil { 234 | t.Fatalf("could not create consul client: %v", err) 235 | } 236 | 237 | files, err := filepath.Glob("testdata/*.json") 238 | if err != nil { 239 | t.Fatalf("error getting import json files") 240 | } 241 | 242 | for _, file := range files { 243 | fmt.Printf("Importing: %s\n", file) 244 | 245 | data, err := ioutil.ReadFile(file) 246 | if err != nil { 247 | t.Fatalf("error reading import json file %s: %v", file, err) 248 | } 249 | var entries []*Entry 250 | if err := json.Unmarshal(data, &entries); err != nil { 251 | t.Fatalf("Cannot unmarshal data: %s", err) 252 | } 253 | 254 | for _, entry := range entries { 255 | pair := &api.KVPair{ 256 | Key: entry.Key, 257 | Flags: entry.Flags, 258 | Value: []byte(entry.Value), 259 | } 260 | if _, err := consul.KV().Put(pair, nil); err != nil { 261 | t.Fatalf("Error! Failed writing data for key %s: %s", pair.Key, err) 262 | } 263 | } 264 | fmt.Printf("Imported: %s\n", file) 265 | } 266 | 267 | return srv, consul 268 | } 269 | 270 | type Entry struct { 271 | Key string `json:"key"` 272 | Flags uint64 `json:"flags"` 273 | Value string `json:"value"` 274 | } 275 | 276 | func newConsul(consulAddr, consulToken string) (*api.Client, error) { 277 | conf := api.DefaultConfig() 278 | conf.Address = consulAddr 279 | conf.Token = consulToken 280 | conf.TLSConfig.InsecureSkipVerify = true 281 | 282 | client, err := api.NewClient(conf) 283 | if err != nil { 284 | return nil, fmt.Errorf("error creating consul client: %v", err) 285 | } 286 | 287 | return client, nil 288 | } 289 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | # Code generated by godownloader on 2019-01-15T06:15:28Z. DO NOT EDIT. 4 | # 5 | 6 | usage() { 7 | this=$1 8 | cat </dev/null 138 | } 139 | echoerr() { 140 | echo "$@" 1>&2 141 | } 142 | log_prefix() { 143 | echo "$0" 144 | } 145 | _logp=6 146 | log_set_priority() { 147 | _logp="$1" 148 | } 149 | log_priority() { 150 | if test -z "$1"; then 151 | echo "$_logp" 152 | return 153 | fi 154 | [ "$1" -le "$_logp" ] 155 | } 156 | log_tag() { 157 | case $1 in 158 | 0) echo "emerg" ;; 159 | 1) echo "alert" ;; 160 | 2) echo "crit" ;; 161 | 3) echo "err" ;; 162 | 4) echo "warning" ;; 163 | 5) echo "notice" ;; 164 | 6) echo "info" ;; 165 | 7) echo "debug" ;; 166 | *) echo "$1" ;; 167 | esac 168 | } 169 | log_debug() { 170 | log_priority 7 || return 0 171 | echoerr "$(log_prefix)" "$(log_tag 7)" "$@" 172 | } 173 | log_info() { 174 | log_priority 6 || return 0 175 | echoerr "$(log_prefix)" "$(log_tag 6)" "$@" 176 | } 177 | log_err() { 178 | log_priority 3 || return 0 179 | echoerr "$(log_prefix)" "$(log_tag 3)" "$@" 180 | } 181 | log_crit() { 182 | log_priority 2 || return 0 183 | echoerr "$(log_prefix)" "$(log_tag 2)" "$@" 184 | } 185 | uname_os() { 186 | os=$(uname -s | tr '[:upper:]' '[:lower:]') 187 | case "$os" in 188 | msys_nt) os="windows" ;; 189 | esac 190 | echo "$os" 191 | } 192 | uname_arch() { 193 | arch=$(uname -m) 194 | case $arch in 195 | x86_64) arch="amd64" ;; 196 | x86) arch="386" ;; 197 | i686) arch="386" ;; 198 | i386) arch="386" ;; 199 | aarch64) arch="arm64" ;; 200 | armv5*) arch="armv5" ;; 201 | armv6*) arch="armv6" ;; 202 | armv7*) arch="armv7" ;; 203 | esac 204 | echo ${arch} 205 | } 206 | uname_os_check() { 207 | os=$(uname_os) 208 | case "$os" in 209 | darwin) return 0 ;; 210 | dragonfly) return 0 ;; 211 | freebsd) return 0 ;; 212 | linux) return 0 ;; 213 | android) return 0 ;; 214 | nacl) return 0 ;; 215 | netbsd) return 0 ;; 216 | openbsd) return 0 ;; 217 | plan9) return 0 ;; 218 | solaris) return 0 ;; 219 | windows) return 0 ;; 220 | esac 221 | log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib" 222 | return 1 223 | } 224 | uname_arch_check() { 225 | arch=$(uname_arch) 226 | case "$arch" in 227 | 386) return 0 ;; 228 | amd64) return 0 ;; 229 | arm64) return 0 ;; 230 | armv5) return 0 ;; 231 | armv6) return 0 ;; 232 | armv7) return 0 ;; 233 | ppc64) return 0 ;; 234 | ppc64le) return 0 ;; 235 | mips) return 0 ;; 236 | mipsle) return 0 ;; 237 | mips64) return 0 ;; 238 | mips64le) return 0 ;; 239 | s390x) return 0 ;; 240 | amd64p32) return 0 ;; 241 | esac 242 | log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib" 243 | return 1 244 | } 245 | untar() { 246 | tarball=$1 247 | case "${tarball}" in 248 | *.tar.gz | *.tgz) tar -xzf "${tarball}" ;; 249 | *.tar) tar -xf "${tarball}" ;; 250 | *.zip) unzip "${tarball}" ;; 251 | *) 252 | log_err "untar unknown archive format for ${tarball}" 253 | return 1 254 | ;; 255 | esac 256 | } 257 | mktmpdir() { 258 | test -z "$TMPDIR" && TMPDIR="$(mktemp -d)" 259 | mkdir -p "${TMPDIR}" 260 | echo "${TMPDIR}" 261 | } 262 | http_download_curl() { 263 | local_file=$1 264 | source_url=$2 265 | header=$3 266 | if [ -z "$header" ]; then 267 | code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url") 268 | else 269 | code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url") 270 | fi 271 | if [ "$code" != "200" ]; then 272 | log_debug "http_download_curl received HTTP status $code" 273 | return 1 274 | fi 275 | return 0 276 | } 277 | http_download_wget() { 278 | local_file=$1 279 | source_url=$2 280 | header=$3 281 | if [ -z "$header" ]; then 282 | wget -q -O "$local_file" "$source_url" 283 | else 284 | wget -q --header "$header" -O "$local_file" "$source_url" 285 | fi 286 | } 287 | http_download() { 288 | log_debug "http_download $2" 289 | if is_command curl; then 290 | http_download_curl "$@" 291 | return 292 | elif is_command wget; then 293 | http_download_wget "$@" 294 | return 295 | fi 296 | log_crit "http_download unable to find wget or curl" 297 | return 1 298 | } 299 | http_copy() { 300 | tmp=$(mktemp) 301 | http_download "${tmp}" "$1" "$2" || return 1 302 | body=$(cat "$tmp") 303 | rm -f "${tmp}" 304 | echo "$body" 305 | } 306 | github_release() { 307 | owner_repo=$1 308 | version=$2 309 | test -z "$version" && version="latest" 310 | giturl="https://github.com/${owner_repo}/releases/${version}" 311 | json=$(http_copy "$giturl" "Accept:application/json") 312 | test -z "$json" && return 1 313 | version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//') 314 | test -z "$version" && return 1 315 | echo "$version" 316 | } 317 | hash_sha256() { 318 | TARGET=${1:-/dev/stdin} 319 | if is_command gsha256sum; then 320 | hash=$(gsha256sum "$TARGET") || return 1 321 | echo "$hash" | cut -d ' ' -f 1 322 | elif is_command sha256sum; then 323 | hash=$(sha256sum "$TARGET") || return 1 324 | echo "$hash" | cut -d ' ' -f 1 325 | elif is_command shasum; then 326 | hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1 327 | echo "$hash" | cut -d ' ' -f 1 328 | elif is_command openssl; then 329 | hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1 330 | echo "$hash" | cut -d ' ' -f a 331 | else 332 | log_crit "hash_sha256 unable to find command to compute sha-256 hash" 333 | return 1 334 | fi 335 | } 336 | hash_sha256_verify() { 337 | TARGET=$1 338 | checksums=$2 339 | if [ -z "$checksums" ]; then 340 | log_err "hash_sha256_verify checksum file not specified in arg2" 341 | return 1 342 | fi 343 | BASENAME=${TARGET##*/} 344 | want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1) 345 | if [ -z "$want" ]; then 346 | log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'" 347 | return 1 348 | fi 349 | got=$(hash_sha256 "$TARGET") 350 | if [ "$want" != "$got" ]; then 351 | log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got" 352 | return 1 353 | fi 354 | } 355 | cat /dev/null < 0 { 290 | prefix = query.Target[:firstStar] 291 | } 292 | 293 | // Get keys with prefix 294 | log.DefaultLogger.Debug("queryTable: get keys below prefix", "prefix", prefix) 295 | keys, _, err := consul.KV().Keys(prefix, "", &api.QueryOptions{}) 296 | if err != nil { 297 | return backend.DataResponse{Error: fmt.Errorf("error gettings keys %s from consul: %v", prefix, err)} 298 | } 299 | 300 | // Filter keys that match the targetRegex 301 | // One matchingKey will be one line in the table 302 | var matchingKeys []string 303 | for _, key := range keys { 304 | if targetRegex.Match([]byte(key)) { 305 | matchingKeys = append(matchingKeys, key) 306 | } 307 | } 308 | 309 | columns := strings.Split(query.Columns, ",") 310 | 311 | fields := []*data.Field{} 312 | for rowIdx, key := range matchingKeys { 313 | for colIdx, col := range columns { 314 | 315 | // calculate key for column value 316 | colKey := calculateColumnKey(key, col) 317 | 318 | // get field from Consul 319 | field, value := getColumnValueForKey(ctx, consul, colKey) 320 | 321 | // If it's the first row ,append it to the fields array 322 | if rowIdx == 0 { 323 | log.DefaultLogger.Debug("queryTable: appending first row field", "value", value, "rowIdx", rowIdx, "colIdx", colIdx) 324 | fields = append(fields, field) 325 | continue 326 | } 327 | 328 | // Else, append it to the field of the current column 329 | log.DefaultLogger.Debug("queryTable: appending value to field", "value", value, "rowIdx", rowIdx, "colIdx", colIdx) 330 | fields[colIdx].Append(value) 331 | } 332 | } 333 | 334 | return backend.DataResponse{Frames: []*data.Frame{data.NewFrame("table", fields...)}} 335 | } 336 | 337 | func getColumnValueForKey(ctx context.Context, consul *api.Client, colKey string) (*data.Field, interface{}) { 338 | log.DefaultLogger.Debug("getColumnValueForKey", "key", colKey) 339 | 340 | kv, _, err := consul.KV().Get(colKey, (&api.QueryOptions{}).WithContext(ctx)) 341 | if err != nil || kv == nil { 342 | return data.NewField(path.Base(colKey), nil, []string{"Not Found"}), "Not Found" 343 | } 344 | 345 | // try to parse int 346 | intValue, err := strconv.ParseInt(string(kv.Value), 10, 64) 347 | if err != nil { 348 | return data.NewField(path.Base(colKey), nil, []string{string(kv.Value)}), string(kv.Value) 349 | } 350 | 351 | return data.NewField(path.Base(colKey), nil, []int64{intValue}), intValue 352 | } 353 | 354 | func calculateColumnKey(key string, col string) string { 355 | for strings.HasPrefix(col, "../") { 356 | lastSlash := strings.LastIndex(key, "/") 357 | key = key[:lastSlash] 358 | col = strings.TrimPrefix(col, "../") 359 | } 360 | return path.Join(key, col) 361 | } 362 | 363 | // CheckHealth handles health checks sent from Grafana to the plugin. 364 | // The main use case for these health checks is the test button on the 365 | // datasource configuration page which allows users to verify that 366 | // a datasource is working as expected. 367 | func (td *ConsulDataSource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) { 368 | log.DefaultLogger.Debug("CheckHealth", "request", req) 369 | 370 | consul, err := td.getConsulClient(req.PluginContext) 371 | if err != nil { 372 | return nil, err 373 | } 374 | 375 | if _, err := consul.Status().Leader(); err != nil { 376 | return &backend.CheckHealthResult{ 377 | Status: backend.HealthStatusError, 378 | Message: fmt.Sprintf("Consul health check failed: %v", err), 379 | }, nil 380 | } 381 | 382 | return &backend.CheckHealthResult{ 383 | Status: backend.HealthStatusOk, 384 | Message: "Consul data source is working", 385 | }, nil 386 | } 387 | 388 | type instanceSettings struct { 389 | consul *api.Client 390 | } 391 | 392 | type jsonData struct { 393 | ConsulAddr string 394 | } 395 | 396 | func newDataSourceInstance(setting backend.DataSourceInstanceSettings) (instancemgmt.Instance, error) { 397 | jData := jsonData{} 398 | 399 | if err := json.Unmarshal(setting.JSONData, &jData); err != nil { 400 | return nil, fmt.Errorf("error decoding jsonData: %v", err) 401 | } 402 | 403 | if jData.ConsulAddr == "" { 404 | log.DefaultLogger.Error("newDataSourceInstance", "ConsulAddr", jData.ConsulAddr, "err", "consulAddr should not be empty") 405 | return nil, fmt.Errorf("consulAddr should not be empty") 406 | } 407 | 408 | conf := api.DefaultConfig() 409 | conf.Address = jData.ConsulAddr 410 | conf.Token = setting.DecryptedSecureJSONData["consulToken"] 411 | conf.TLSConfig.InsecureSkipVerify = true 412 | 413 | client, err := api.NewClient(conf) 414 | if err != nil { 415 | return nil, fmt.Errorf("error creating consul client: %v", err) 416 | } 417 | return &instanceSettings{ 418 | consul: client, 419 | }, nil 420 | } 421 | 422 | func (s *instanceSettings) Dispose() { 423 | } 424 | -------------------------------------------------------------------------------- /example/Consul_Kubernetes_Example.json: -------------------------------------------------------------------------------- 1 | { 2 | "__inputs": [ 3 | { 4 | "name": "DS_CONSUL", 5 | "label": "Consul", 6 | "description": "", 7 | "type": "datasource", 8 | "pluginId": "sbueringer-consul-datasource", 9 | "pluginName": "Consul" 10 | } 11 | ], 12 | "__requires": [ 13 | { 14 | "type": "grafana", 15 | "id": "grafana", 16 | "name": "Grafana", 17 | "version": "7.3.0-beta2" 18 | }, 19 | { 20 | "type": "datasource", 21 | "id": "sbueringer-consul-datasource", 22 | "name": "Consul", 23 | "version": "1.0.0" 24 | }, 25 | { 26 | "type": "panel", 27 | "id": "singlestat", 28 | "name": "Singlestat", 29 | "version": "" 30 | }, 31 | { 32 | "type": "panel", 33 | "id": "table-old", 34 | "name": "Table (old)", 35 | "version": "" 36 | } 37 | ], 38 | "annotations": { 39 | "list": [ 40 | { 41 | "builtIn": 1, 42 | "datasource": "-- Grafana --", 43 | "enable": true, 44 | "hide": true, 45 | "iconColor": "rgba(0, 211, 255, 1)", 46 | "name": "Annotations & Alerts", 47 | "type": "dashboard" 48 | } 49 | ] 50 | }, 51 | "editable": true, 52 | "gnetId": null, 53 | "graphTooltip": 0, 54 | "id": null, 55 | "iteration": 1604848476990, 56 | "links": [], 57 | "panels": [ 58 | { 59 | "cacheTimeout": null, 60 | "colorBackground": false, 61 | "colorValue": false, 62 | "colors": [ 63 | "#299c46", 64 | "rgba(237, 129, 40, 0.89)", 65 | "#d44a3a" 66 | ], 67 | "datasource": "${DS_CONSUL}", 68 | "fieldConfig": { 69 | "defaults": { 70 | "custom": {} 71 | }, 72 | "overrides": [] 73 | }, 74 | "format": "none", 75 | "gauge": { 76 | "maxValue": 100, 77 | "minValue": 0, 78 | "show": false, 79 | "thresholdLabels": false, 80 | "thresholdMarkers": true 81 | }, 82 | "gridPos": { 83 | "h": 4, 84 | "w": 4, 85 | "x": 0, 86 | "y": 0 87 | }, 88 | "id": 2, 89 | "interval": null, 90 | "links": [], 91 | "mappingType": 1, 92 | "mappingTypes": [ 93 | { 94 | "name": "value to text", 95 | "value": 1 96 | }, 97 | { 98 | "name": "range to text", 99 | "value": 2 100 | } 101 | ], 102 | "maxDataPoints": 100, 103 | "nullPointMode": "connected", 104 | "nullText": null, 105 | "postfix": "", 106 | "postfixFontSize": "50%", 107 | "prefix": "", 108 | "prefixFontSize": "50%", 109 | "rangeMaps": [ 110 | { 111 | "from": "null", 112 | "text": "N/A", 113 | "to": "null" 114 | } 115 | ], 116 | "sparkline": { 117 | "fillColor": "rgba(31, 118, 189, 0.18)", 118 | "full": false, 119 | "lineColor": "rgb(31, 120, 193)", 120 | "show": false 121 | }, 122 | "tableColumn": "", 123 | "targets": [ 124 | { 125 | "columns": "", 126 | "format": "timeseries", 127 | "legendFormat": "{{ apiVersion }}", 128 | "queryText": "registry/apiregistration.k8s.io/apiservices/${apiGroup}/", 129 | "refId": "A", 130 | "target": "registry/apiregistration.k8s.io/apiservices/${apiGroup}/", 131 | "type": "tags" 132 | } 133 | ], 134 | "thresholds": "", 135 | "title": "apiVersion", 136 | "type": "singlestat", 137 | "valueFontSize": "50%", 138 | "valueMaps": [ 139 | { 140 | "op": "=", 141 | "text": "N/A", 142 | "value": "null" 143 | } 144 | ], 145 | "valueName": "name" 146 | }, 147 | { 148 | "cacheTimeout": null, 149 | "colorBackground": false, 150 | "colorValue": false, 151 | "colors": [ 152 | "#299c46", 153 | "rgba(237, 129, 40, 0.89)", 154 | "#d44a3a" 155 | ], 156 | "datasource": "${DS_CONSUL}", 157 | "fieldConfig": { 158 | "defaults": { 159 | "custom": {} 160 | }, 161 | "overrides": [] 162 | }, 163 | "format": "none", 164 | "gauge": { 165 | "maxValue": 100, 166 | "minValue": 0, 167 | "show": false, 168 | "thresholdLabels": false, 169 | "thresholdMarkers": true 170 | }, 171 | "gridPos": { 172 | "h": 4, 173 | "w": 5, 174 | "x": 4, 175 | "y": 0 176 | }, 177 | "id": 5, 178 | "interval": null, 179 | "links": [], 180 | "mappingType": 1, 181 | "mappingTypes": [ 182 | { 183 | "name": "value to text", 184 | "value": 1 185 | }, 186 | { 187 | "name": "range to text", 188 | "value": 2 189 | } 190 | ], 191 | "maxDataPoints": 100, 192 | "nullPointMode": "connected", 193 | "nullText": null, 194 | "postfix": "", 195 | "postfixFontSize": "50%", 196 | "prefix": "", 197 | "prefixFontSize": "50%", 198 | "rangeMaps": [ 199 | { 200 | "from": "null", 201 | "text": "N/A", 202 | "to": "null" 203 | } 204 | ], 205 | "sparkline": { 206 | "fillColor": "rgba(31, 118, 189, 0.18)", 207 | "full": false, 208 | "lineColor": "rgb(31, 120, 193)", 209 | "show": false 210 | }, 211 | "tableColumn": "", 212 | "targets": [ 213 | { 214 | "columns": "", 215 | "format": "timeseries", 216 | "legendFormat": "{{ name }}", 217 | "refId": "A", 218 | "target": "registry/apiregistration.k8s.io/apiservices/${apiGroup}/", 219 | "type": "tags" 220 | } 221 | ], 222 | "thresholds": "", 223 | "title": "Name", 224 | "type": "singlestat", 225 | "valueFontSize": "80%", 226 | "valueMaps": [ 227 | { 228 | "op": "=", 229 | "text": "N/A", 230 | "value": "null" 231 | } 232 | ], 233 | "valueName": "name" 234 | }, 235 | { 236 | "cacheTimeout": null, 237 | "colorBackground": false, 238 | "colorValue": false, 239 | "colors": [ 240 | "#299c46", 241 | "rgba(237, 129, 40, 0.89)", 242 | "#d44a3a" 243 | ], 244 | "datasource": "${DS_CONSUL}", 245 | "fieldConfig": { 246 | "defaults": { 247 | "custom": {} 248 | }, 249 | "overrides": [] 250 | }, 251 | "format": "none", 252 | "gauge": { 253 | "maxValue": 100, 254 | "minValue": 0, 255 | "show": false, 256 | "thresholdLabels": false, 257 | "thresholdMarkers": true 258 | }, 259 | "gridPos": { 260 | "h": 4, 261 | "w": 5, 262 | "x": 9, 263 | "y": 0 264 | }, 265 | "id": 8, 266 | "interval": null, 267 | "links": [], 268 | "mappingType": 1, 269 | "mappingTypes": [ 270 | { 271 | "name": "value to text", 272 | "value": 1 273 | }, 274 | { 275 | "name": "range to text", 276 | "value": 2 277 | } 278 | ], 279 | "maxDataPoints": 100, 280 | "nullPointMode": "connected", 281 | "nullText": null, 282 | "postfix": "", 283 | "postfixFontSize": "50%", 284 | "prefix": "", 285 | "prefixFontSize": "50%", 286 | "rangeMaps": [ 287 | { 288 | "from": "null", 289 | "text": "N/A", 290 | "to": "null" 291 | } 292 | ], 293 | "sparkline": { 294 | "fillColor": "rgba(31, 118, 189, 0.18)", 295 | "full": false, 296 | "lineColor": "rgb(31, 120, 193)", 297 | "show": false 298 | }, 299 | "tableColumn": "", 300 | "targets": [ 301 | { 302 | "columns": "", 303 | "format": "timeseries", 304 | "legendFormat": "", 305 | "queryText": "registry/apiregistration.k8s.io/apiservices/${apiGroup}/spec/versionPriority", 306 | "refId": "A", 307 | "target": "registry/apiregistration.k8s.io/apiservices/${apiGroup}/spec/versionPriority", 308 | "type": "get" 309 | } 310 | ], 311 | "thresholds": "", 312 | "title": "versionPriority", 313 | "type": "singlestat", 314 | "valueFontSize": "80%", 315 | "valueMaps": [ 316 | { 317 | "op": "=", 318 | "text": "N/A", 319 | "value": "null" 320 | } 321 | ], 322 | "valueName": "current" 323 | }, 324 | { 325 | "cacheTimeout": null, 326 | "colorBackground": false, 327 | "colorValue": false, 328 | "colors": [ 329 | "#299c46", 330 | "rgba(237, 129, 40, 0.89)", 331 | "#d44a3a" 332 | ], 333 | "datasource": "${DS_CONSUL}", 334 | "fieldConfig": { 335 | "defaults": { 336 | "custom": {} 337 | }, 338 | "overrides": [] 339 | }, 340 | "format": "none", 341 | "gauge": { 342 | "maxValue": 100, 343 | "minValue": 0, 344 | "show": false, 345 | "thresholdLabels": false, 346 | "thresholdMarkers": true 347 | }, 348 | "gridPos": { 349 | "h": 4, 350 | "w": 5, 351 | "x": 14, 352 | "y": 0 353 | }, 354 | "id": 6, 355 | "interval": null, 356 | "links": [], 357 | "mappingType": 1, 358 | "mappingTypes": [ 359 | { 360 | "name": "value to text", 361 | "value": 1 362 | }, 363 | { 364 | "name": "range to text", 365 | "value": 2 366 | } 367 | ], 368 | "maxDataPoints": 100, 369 | "nullPointMode": "connected", 370 | "nullText": null, 371 | "postfix": "", 372 | "postfixFontSize": "50%", 373 | "prefix": "", 374 | "prefixFontSize": "50%", 375 | "rangeMaps": [ 376 | { 377 | "from": "null", 378 | "text": "N/A", 379 | "to": "null" 380 | } 381 | ], 382 | "sparkline": { 383 | "fillColor": "rgba(31, 118, 189, 0.18)", 384 | "full": false, 385 | "lineColor": "rgb(31, 120, 193)", 386 | "show": false 387 | }, 388 | "tableColumn": "", 389 | "targets": [ 390 | { 391 | "columns": "", 392 | "format": "timeseries", 393 | "legendFormat": "{{ spec.version }} / {{ spec.versionPriority }}", 394 | "queryText": "registry/apiregistration.k8s.io/apiservices/${apiGroup}/", 395 | "refId": "A", 396 | "target": "registry/apiregistration.k8s.io/apiservices/${apiGroup}/", 397 | "type": "tagsrec" 398 | } 399 | ], 400 | "thresholds": "", 401 | "title": "version / versionPriority", 402 | "type": "singlestat", 403 | "valueFontSize": "80%", 404 | "valueMaps": [ 405 | { 406 | "op": "=", 407 | "text": "N/A", 408 | "value": "null" 409 | } 410 | ], 411 | "valueName": "name" 412 | }, 413 | { 414 | "cacheTimeout": null, 415 | "colorBackground": false, 416 | "colorValue": false, 417 | "colors": [ 418 | "#299c46", 419 | "rgba(237, 129, 40, 0.89)", 420 | "#d44a3a" 421 | ], 422 | "datasource": "${DS_CONSUL}", 423 | "fieldConfig": { 424 | "defaults": { 425 | "custom": {} 426 | }, 427 | "overrides": [] 428 | }, 429 | "format": "none", 430 | "gauge": { 431 | "maxValue": 100, 432 | "minValue": 0, 433 | "show": false, 434 | "thresholdLabels": false, 435 | "thresholdMarkers": true 436 | }, 437 | "gridPos": { 438 | "h": 4, 439 | "w": 5, 440 | "x": 19, 441 | "y": 0 442 | }, 443 | "id": 7, 444 | "interval": null, 445 | "links": [], 446 | "mappingType": 1, 447 | "mappingTypes": [ 448 | { 449 | "name": "value to text", 450 | "value": 1 451 | }, 452 | { 453 | "name": "range to text", 454 | "value": 2 455 | } 456 | ], 457 | "maxDataPoints": 100, 458 | "nullPointMode": "connected", 459 | "nullText": null, 460 | "postfix": "", 461 | "postfixFontSize": "50%", 462 | "prefix": "", 463 | "prefixFontSize": "50%", 464 | "rangeMaps": [ 465 | { 466 | "from": "null", 467 | "text": "N/A", 468 | "to": "null" 469 | } 470 | ], 471 | "sparkline": { 472 | "fillColor": "rgba(31, 118, 189, 0.18)", 473 | "full": false, 474 | "lineColor": "rgb(31, 120, 193)", 475 | "show": false 476 | }, 477 | "tableColumn": "", 478 | "targets": [ 479 | { 480 | "columns": "", 481 | "format": "timeseries", 482 | "legendFormat": "{{ spec.group }} / {{ spec.groupPriorityMinimum }}", 483 | "queryText": "registry/apiregistration.k8s.io/apiservices/${apiGroup}/", 484 | "refId": "A", 485 | "target": "registry/apiregistration.k8s.io/apiservices/${apiGroup}/", 486 | "type": "tagsrec" 487 | } 488 | ], 489 | "thresholds": "", 490 | "title": "group / groupPriorityMinimum", 491 | "type": "singlestat", 492 | "valueFontSize": "80%", 493 | "valueMaps": [ 494 | { 495 | "op": "=", 496 | "text": "N/A", 497 | "value": "null" 498 | } 499 | ], 500 | "valueName": "name" 501 | }, 502 | { 503 | "columns": [], 504 | "datasource": "${DS_CONSUL}", 505 | "fieldConfig": { 506 | "defaults": { 507 | "custom": {} 508 | }, 509 | "overrides": [] 510 | }, 511 | "fontSize": "100%", 512 | "gridPos": { 513 | "h": 10, 514 | "w": 23, 515 | "x": 0, 516 | "y": 4 517 | }, 518 | "id": 4, 519 | "links": [], 520 | "pageSize": null, 521 | "scroll": true, 522 | "showHeader": true, 523 | "sort": { 524 | "col": 0, 525 | "desc": true 526 | }, 527 | "styles": [ 528 | { 529 | "alias": "Time", 530 | "align": "auto", 531 | "dateFormat": "YYYY-MM-DD HH:mm:ss", 532 | "pattern": "Time", 533 | "type": "date" 534 | }, 535 | { 536 | "alias": "", 537 | "align": "auto", 538 | "colorMode": null, 539 | "colors": [ 540 | "rgba(245, 54, 54, 0.9)", 541 | "rgba(237, 129, 40, 0.89)", 542 | "rgba(50, 172, 45, 0.97)" 543 | ], 544 | "decimals": 2, 545 | "pattern": "/.*/", 546 | "thresholds": [], 547 | "type": "number", 548 | "unit": "short" 549 | } 550 | ], 551 | "targets": [ 552 | { 553 | "columns": "../apiVersion,../name,../spec/version,../spec/versionPriority,../spec/group,../spec/groupPriorityMinimum", 554 | "format": "table", 555 | "legendFormat": "", 556 | "refId": "A", 557 | "target": "registry/apiregistration.k8s.io/apiservices/*/name", 558 | "type": "get" 559 | } 560 | ], 561 | "title": "apiGroup Overview", 562 | "transform": "table", 563 | "type": "table-old" 564 | } 565 | ], 566 | "schemaVersion": 26, 567 | "style": "dark", 568 | "tags": [], 569 | "templating": { 570 | "list": [ 571 | { 572 | "allValue": null, 573 | "current": {}, 574 | "datasource": "${DS_CONSUL}", 575 | "definition": "registry/apiregistration.k8s.io/apiservices/", 576 | "error": null, 577 | "hide": 0, 578 | "includeAll": false, 579 | "label": null, 580 | "multi": false, 581 | "name": "apiGroup", 582 | "options": [], 583 | "query": "registry/apiregistration.k8s.io/apiservices/", 584 | "refresh": 1, 585 | "regex": "registry/apiregistration.k8s.io/apiservices/(.*)/", 586 | "skipUrlSync": false, 587 | "sort": 1, 588 | "tagValuesQuery": "", 589 | "tags": [], 590 | "tagsQuery": "", 591 | "type": "query", 592 | "useTags": false 593 | } 594 | ] 595 | }, 596 | "time": { 597 | "from": "now-6h", 598 | "to": "now" 599 | }, 600 | "timepicker": { 601 | "refresh_intervals": [ 602 | "5s", 603 | "10s", 604 | "30s", 605 | "1m", 606 | "5m", 607 | "15m", 608 | "30m", 609 | "1h", 610 | "2h", 611 | "1d" 612 | ], 613 | "time_options": [ 614 | "5m", 615 | "15m", 616 | "1h", 617 | "6h", 618 | "12h", 619 | "24h", 620 | "2d", 621 | "7d", 622 | "30d" 623 | ] 624 | }, 625 | "timezone": "", 626 | "title": "Consul Kubernetes Example", 627 | "uid": "YGwcTU2mz", 628 | "version": 7 629 | } 630 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 3 | github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 4 | github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= 5 | github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 6 | github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= 7 | github.com/apache/arrow/go/arrow v0.0.0-20200403134915-89ce1cadb678 h1:R72+9UXiP7TnpTAdznM1okjzyqb3bzopSA7HCP7p3gM= 8 | github.com/apache/arrow/go/arrow v0.0.0-20200403134915-89ce1cadb678/go.mod h1:QNYViu/X0HXDHw7m3KXzWSVXIbfUvJqBFe6Gj8/pYA0= 9 | github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= 10 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= 11 | github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= 12 | github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 13 | github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= 14 | github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= 15 | github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= 16 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 17 | github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= 18 | github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= 19 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 20 | github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= 21 | github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= 22 | github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= 23 | github.com/cheekybits/genny v1.0.0/go.mod h1:+tQajlRqAUrPI7DOSpB0XAqZYtQakVtB7wXkRAgjxjQ= 24 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 25 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 26 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 27 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 28 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 29 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 30 | github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= 31 | github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= 32 | github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= 33 | github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 34 | github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= 35 | github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= 36 | github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= 37 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 38 | github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= 39 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 40 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= 41 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 42 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 43 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 44 | github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 45 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 46 | github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk= 47 | github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= 48 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= 49 | github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= 50 | github.com/google/flatbuffers v1.11.0 h1:O7CEyB8Cb3/DmtxODGtLHcEvpr81Jm5qLg/hsHnxA2A= 51 | github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= 52 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 53 | github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= 54 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 55 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 56 | github.com/grafana/grafana-plugin-sdk-go v0.65.0 h1:l6cPKCFxf3AN3gd7Sprum2TuhcqsGI98Xa/1dDuin9E= 57 | github.com/grafana/grafana-plugin-sdk-go v0.65.0/go.mod h1:w855JyiC5PDP3naWUJP0h/vY8RlzlE4+4fodyoXph+4= 58 | github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg= 59 | github.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s= 60 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= 61 | github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= 62 | github.com/hashicorp/consul/api v1.7.0 h1:tGs8Oep67r8CcA2Ycmb/8BLBcJ70St44mF2X10a/qPg= 63 | github.com/hashicorp/consul/api v1.7.0/go.mod h1:1NSuaUUkFaJzMasbfq/11wKYWSR67Xn6r2DXKhuDNFg= 64 | github.com/hashicorp/consul/sdk v0.6.0 h1:FfhMEkwvQl57CildXJyGHnwGGM4HMODGyfjGwNM1Vdw= 65 | github.com/hashicorp/consul/sdk v0.6.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM= 66 | github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= 67 | github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= 68 | github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM= 69 | github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= 70 | github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd h1:rNuUHR+CvK1IS89MMtcF0EpcVMZtjKfPRp4MEmt/aTs= 71 | github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= 72 | github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM= 73 | github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= 74 | github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= 75 | github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= 76 | github.com/hashicorp/go-msgpack v0.5.3 h1:zKjpN5BK/P5lMYrLmBHdBULWbJ0XpYR+7NGzqkZzoD4= 77 | github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= 78 | github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= 79 | github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= 80 | github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= 81 | github.com/hashicorp/go-plugin v1.2.2 h1:mgDpq0PkoK5gck2w4ivaMpWRHv/matdOR4xmeScmf/w= 82 | github.com/hashicorp/go-plugin v1.2.2/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= 83 | github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc= 84 | github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= 85 | github.com/hashicorp/go-sockaddr v1.0.0 h1:GeH6tui99pF4NJgfnhp+L6+FfobzVW3Ah46sLo0ICXs= 86 | github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= 87 | github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= 88 | github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 89 | github.com/hashicorp/go-uuid v1.0.1 h1:fv1ep09latC32wFoVwnqcnKJGnMSdBanPczbHAYm1BE= 90 | github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= 91 | github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= 92 | github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= 93 | github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= 94 | github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= 95 | github.com/hashicorp/memberlist v0.2.2 h1:5+RffWKwqJ71YPu9mWsF7ZOscZmwfasdA8kbdC7AO2g= 96 | github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= 97 | github.com/hashicorp/serf v0.9.3 h1:AVF6JDQQens6nMHT9OGERBvK0f8rPrAGILnsKLr6lzM= 98 | github.com/hashicorp/serf v0.9.3/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= 99 | github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= 100 | github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ= 101 | github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= 102 | github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= 103 | github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= 104 | github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= 105 | github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= 106 | github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 107 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 108 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 109 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 110 | github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= 111 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 112 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 113 | github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= 114 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 115 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 116 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 117 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 118 | github.com/magefile/mage v1.9.0 h1:t3AU2wNwehMCW97vuqQLtw6puppWXHO+O2MHo5a50XE= 119 | github.com/magefile/mage v1.9.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= 120 | github.com/mattetti/filebuffer v1.0.0 h1:ixTvQ0JjBTwWbdpDZ98lLrydo7KRi8xNRIi5RFszsbY= 121 | github.com/mattetti/filebuffer v1.0.0/go.mod h1:X6nyAIge2JGVmuJt2MFCqmHrb/5IHiphfHtot0s5cnI= 122 | github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= 123 | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 124 | github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= 125 | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 126 | github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= 127 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 128 | github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= 129 | github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= 130 | github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= 131 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 132 | github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= 133 | github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= 134 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 135 | github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= 136 | github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= 137 | github.com/miekg/dns v1.1.26 h1:gPxPSwALAeHJSjarOs00QjVdV9QoBvc1D2ujQUr5BzU= 138 | github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= 139 | github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= 140 | github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= 141 | github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= 142 | github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg= 143 | github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 144 | github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0= 145 | github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= 146 | github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 147 | github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= 148 | github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= 149 | github.com/mitchellh/reflectwalk v1.0.1 h1:FVzMWA5RllMAKIdUSC8mdWo3XtwoecrH79BY70sEEpE= 150 | github.com/mitchellh/reflectwalk v1.0.1/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= 151 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 152 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 153 | github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 154 | github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= 155 | github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= 156 | github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= 157 | github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= 158 | github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= 159 | github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= 160 | github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 161 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= 162 | github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= 163 | github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 164 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 165 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 166 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 167 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 168 | github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= 169 | github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= 170 | github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= 171 | github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= 172 | github.com/prometheus/client_golang v1.3.0 h1:miYCvYqFXtl/J9FIy8eNpBfYthAEFg+Ys0XyUVEcDsc= 173 | github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= 174 | github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= 175 | github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 176 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 177 | github.com/prometheus/client_model v0.1.0 h1:ElTg5tNp4DqfV7UQjDqv2+RJlNzsDtvNAWccbItceIE= 178 | github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 179 | github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= 180 | github.com/prometheus/common v0.7.0 h1:L+1lyG48J1zAQXA3RBX/nG/B3gjlHq0zTt2tlbJLyCY= 181 | github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= 182 | github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= 183 | github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= 184 | github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= 185 | github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= 186 | github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= 187 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= 188 | github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= 189 | github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= 190 | github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= 191 | github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= 192 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 193 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 194 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 195 | github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 196 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 197 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 198 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 199 | github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= 200 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 201 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 202 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 203 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 204 | golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 205 | golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 206 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 207 | golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392 h1:ACG4HJsFiNMf47Y4PeRoebLNy/2lXT9EtprMuTFWt1M= 208 | golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= 209 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 210 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 211 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 212 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 213 | golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 214 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 215 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 216 | golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 217 | golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 218 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 219 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 220 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 221 | golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 222 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 223 | golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g= 224 | golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 225 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 226 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 227 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 228 | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 229 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 230 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= 231 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 232 | golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 233 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 234 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 235 | golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 236 | golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 237 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 238 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 239 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 240 | golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 241 | golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 242 | golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 243 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 244 | golang.org/x/sys v0.0.0-20191220142924-d4481acd189f h1:68K/z8GLUxV76xGSqwTWw2gyk/jwn79LUL43rES2g8o= 245 | golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 246 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 247 | golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 248 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8= 249 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 250 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 251 | golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= 252 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 253 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 254 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 255 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 256 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 257 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 258 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 259 | golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 260 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 261 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 262 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 263 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 264 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 265 | google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 266 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 267 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= 268 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 269 | google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= 270 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 271 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 272 | google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk= 273 | google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 274 | gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= 275 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 276 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= 277 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 278 | gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 279 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 280 | gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 281 | gopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c= 282 | gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 283 | gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= 284 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 285 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 286 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 287 | -------------------------------------------------------------------------------- /example/data/data.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "key": "registry/apiregistration.k8s.io/apiservices/v1./apiVersion", 4 | "flags": 0, 5 | "value": "apiregistration.k8s.io/v1beta1" 6 | }, 7 | { 8 | "key": "registry/apiregistration.k8s.io/apiservices/v1.apps/apiVersion", 9 | "flags": 0, 10 | "value": "apiregistration.k8s.io/v1beta1" 11 | }, 12 | { 13 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/apiVersion", 14 | "flags": 0, 15 | "value": "apiregistration.k8s.io/v1beta1" 16 | }, 17 | { 18 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io/apiVersion", 19 | "flags": 0, 20 | "value": "apiregistration.k8s.io/v1beta1" 21 | }, 22 | { 23 | "key": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/apiVersion", 24 | "flags": 0, 25 | "value": "apiregistration.k8s.io/v1beta1" 26 | }, 27 | { 28 | "key": "registry/apiregistration.k8s.io/apiservices/v1.batch/apiVersion", 29 | "flags": 0, 30 | "value": "apiregistration.k8s.io/v1beta1" 31 | }, 32 | { 33 | "key": "registry/apiregistration.k8s.io/apiservices/v1.crd.projectcalico.org/apiVersion", 34 | "flags": 0, 35 | "value": "apiregistration.k8s.io/v1beta1" 36 | }, 37 | { 38 | "key": "registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io/apiVersion", 39 | "flags": 0, 40 | "value": "apiregistration.k8s.io/v1beta1" 41 | }, 42 | { 43 | "key": "registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io/apiVersion", 44 | "flags": 0, 45 | "value": "apiregistration.k8s.io/v1beta1" 46 | }, 47 | { 48 | "key": "registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io/apiVersion", 49 | "flags": 0, 50 | "value": "apiregistration.k8s.io/v1beta1" 51 | }, 52 | { 53 | "key": "registry/apiregistration.k8s.io/apiservices/v1alpha1.scheduling.k8s.io/apiVersion", 54 | "flags": 0, 55 | "value": "apiregistration.k8s.io/v1beta1" 56 | }, 57 | { 58 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io/apiVersion", 59 | "flags": 0, 60 | "value": "apiregistration.k8s.io/v1beta1" 61 | }, 62 | { 63 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io/apiVersion", 64 | "flags": 0, 65 | "value": "apiregistration.k8s.io/v1beta1" 66 | }, 67 | { 68 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apps/apiVersion", 69 | "flags": 0, 70 | "value": "apiregistration.k8s.io/v1beta1" 71 | }, 72 | { 73 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io/apiVersion", 74 | "flags": 0, 75 | "value": "apiregistration.k8s.io/v1beta1" 76 | }, 77 | { 78 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io/apiVersion", 79 | "flags": 0, 80 | "value": "apiregistration.k8s.io/v1beta1" 81 | }, 82 | { 83 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.batch/apiVersion", 84 | "flags": 0, 85 | "value": "apiregistration.k8s.io/v1beta1" 86 | }, 87 | { 88 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io/apiVersion", 89 | "flags": 0, 90 | "value": "apiregistration.k8s.io/v1beta1" 91 | }, 92 | { 93 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io/apiVersion", 94 | "flags": 0, 95 | "value": "apiregistration.k8s.io/v1beta1" 96 | }, 97 | { 98 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.extensions/apiVersion", 99 | "flags": 0, 100 | "value": "apiregistration.k8s.io/v1beta1" 101 | }, 102 | { 103 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.policy/apiVersion", 104 | "flags": 0, 105 | "value": "apiregistration.k8s.io/v1beta1" 106 | }, 107 | { 108 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/apiVersion", 109 | "flags": 0, 110 | "value": "apiregistration.k8s.io/v1beta1" 111 | }, 112 | { 113 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io/apiVersion", 114 | "flags": 0, 115 | "value": "apiregistration.k8s.io/v1beta1" 116 | }, 117 | { 118 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta2.apps/apiVersion", 119 | "flags": 0, 120 | "value": "apiregistration.k8s.io/v1beta1" 121 | }, 122 | { 123 | "key": "registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling/apiVersion", 124 | "flags": 0, 125 | "value": "apiregistration.k8s.io/v1beta1" 126 | }, 127 | { 128 | "key": "registry/apiregistration.k8s.io/apiservices/v1./kind", 129 | "flags": 0, 130 | "value": "APIService" 131 | }, 132 | { 133 | "key": "registry/apiregistration.k8s.io/apiservices/v1.apps/kind", 134 | "flags": 0, 135 | "value": "APIService" 136 | }, 137 | { 138 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/kind", 139 | "flags": 0, 140 | "value": "APIService" 141 | }, 142 | { 143 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io/kind", 144 | "flags": 0, 145 | "value": "APIService" 146 | }, 147 | { 148 | "key": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/kind", 149 | "flags": 0, 150 | "value": "APIService" 151 | }, 152 | { 153 | "key": "registry/apiregistration.k8s.io/apiservices/v1.batch/kind", 154 | "flags": 0, 155 | "value": "APIService" 156 | }, 157 | { 158 | "key": "registry/apiregistration.k8s.io/apiservices/v1.crd.projectcalico.org/kind", 159 | "flags": 0, 160 | "value": "APIService" 161 | }, 162 | { 163 | "key": "registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io/kind", 164 | "flags": 0, 165 | "value": "APIService" 166 | }, 167 | { 168 | "key": "registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io/kind", 169 | "flags": 0, 170 | "value": "APIService" 171 | }, 172 | { 173 | "key": "registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io/kind", 174 | "flags": 0, 175 | "value": "APIService" 176 | }, 177 | { 178 | "key": "registry/apiregistration.k8s.io/apiservices/v1alpha1.scheduling.k8s.io/kind", 179 | "flags": 0, 180 | "value": "APIService" 181 | }, 182 | { 183 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io/kind", 184 | "flags": 0, 185 | "value": "APIService" 186 | }, 187 | { 188 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io/kind", 189 | "flags": 0, 190 | "value": "APIService" 191 | }, 192 | { 193 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apps/kind", 194 | "flags": 0, 195 | "value": "APIService" 196 | }, 197 | { 198 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io/kind", 199 | "flags": 0, 200 | "value": "APIService" 201 | }, 202 | { 203 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io/kind", 204 | "flags": 0, 205 | "value": "APIService" 206 | }, 207 | { 208 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.batch/kind", 209 | "flags": 0, 210 | "value": "APIService" 211 | }, 212 | { 213 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io/kind", 214 | "flags": 0, 215 | "value": "APIService" 216 | }, 217 | { 218 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io/kind", 219 | "flags": 0, 220 | "value": "APIService" 221 | }, 222 | { 223 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.extensions/kind", 224 | "flags": 0, 225 | "value": "APIService" 226 | }, 227 | { 228 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.policy/kind", 229 | "flags": 0, 230 | "value": "APIService" 231 | }, 232 | { 233 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/kind", 234 | "flags": 0, 235 | "value": "APIService" 236 | }, 237 | { 238 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io/kind", 239 | "flags": 0, 240 | "value": "APIService" 241 | }, 242 | { 243 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta2.apps/kind", 244 | "flags": 0, 245 | "value": "APIService" 246 | }, 247 | { 248 | "key": "registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling/kind", 249 | "flags": 0, 250 | "value": "APIService" 251 | }, 252 | { 253 | "key": "registry/apiregistration.k8s.io/apiservices/v1./name", 254 | "flags": 0, 255 | "value": "v1." 256 | }, 257 | { 258 | "key": "registry/apiregistration.k8s.io/apiservices/v1.apps/name", 259 | "flags": 0, 260 | "value": "v1.apps" 261 | }, 262 | { 263 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/name", 264 | "flags": 0, 265 | "value": "v1.authentication.k8s.io" 266 | }, 267 | { 268 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io/name", 269 | "flags": 0, 270 | "value": "v1.authorization.k8s.io" 271 | }, 272 | { 273 | "key": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/name", 274 | "flags": 0, 275 | "value": "v1.autoscaling" 276 | }, 277 | { 278 | "key": "registry/apiregistration.k8s.io/apiservices/v1.batch/name", 279 | "flags": 0, 280 | "value": "v1.batch" 281 | }, 282 | { 283 | "key": "registry/apiregistration.k8s.io/apiservices/v1.crd.projectcalico.org/name", 284 | "flags": 0, 285 | "value": "v1.crd.projectcalico.org" 286 | }, 287 | { 288 | "key": "registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io/name", 289 | "flags": 0, 290 | "value": "v1.networking.k8s.io" 291 | }, 292 | { 293 | "key": "registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io/name", 294 | "flags": 0, 295 | "value": "v1.rbac.authorization.k8s.io" 296 | }, 297 | { 298 | "key": "registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io/name", 299 | "flags": 0, 300 | "value": "v1.storage.k8s.io" 301 | }, 302 | { 303 | "key": "registry/apiregistration.k8s.io/apiservices/v1alpha1.scheduling.k8s.io/name", 304 | "flags": 0, 305 | "value": "v1alpha1.scheduling.k8s.io" 306 | }, 307 | { 308 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io/name", 309 | "flags": 0, 310 | "value": "v1beta1.admissionregistration.k8s.io" 311 | }, 312 | { 313 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io/name", 314 | "flags": 0, 315 | "value": "v1beta1.apiextensions.k8s.io" 316 | }, 317 | { 318 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apps/name", 319 | "flags": 0, 320 | "value": "v1beta1.apps" 321 | }, 322 | { 323 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io/name", 324 | "flags": 0, 325 | "value": "v1beta1.authentication.k8s.io" 326 | }, 327 | { 328 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io/name", 329 | "flags": 0, 330 | "value": "v1beta1.authorization.k8s.io" 331 | }, 332 | { 333 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.batch/name", 334 | "flags": 0, 335 | "value": "v1beta1.batch" 336 | }, 337 | { 338 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io/name", 339 | "flags": 0, 340 | "value": "v1beta1.certificates.k8s.io" 341 | }, 342 | { 343 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io/name", 344 | "flags": 0, 345 | "value": "v1beta1.events.k8s.io" 346 | }, 347 | { 348 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.extensions/name", 349 | "flags": 0, 350 | "value": "v1beta1.extensions" 351 | }, 352 | { 353 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.policy/name", 354 | "flags": 0, 355 | "value": "v1beta1.policy" 356 | }, 357 | { 358 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/name", 359 | "flags": 0, 360 | "value": "v1beta1.rbac.authorization.k8s.io" 361 | }, 362 | { 363 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io/name", 364 | "flags": 0, 365 | "value": "v1beta1.storage.k8s.io" 366 | }, 367 | { 368 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta2.apps/name", 369 | "flags": 0, 370 | "value": "v1beta2.apps" 371 | }, 372 | { 373 | "key": "registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling/name", 374 | "flags": 0, 375 | "value": "v2beta1.autoscaling" 376 | }, 377 | { 378 | "key": "registry/apiregistration.k8s.io/apiservices/v1./spec/group", 379 | "flags": 0, 380 | "value": null 381 | }, 382 | { 383 | "key": "registry/apiregistration.k8s.io/apiservices/v1.apps/spec/group", 384 | "flags": 0, 385 | "value": "apps" 386 | }, 387 | { 388 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/spec/group", 389 | "flags": 0, 390 | "value": "authentication.k8s.io" 391 | }, 392 | { 393 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io/spec/group", 394 | "flags": 0, 395 | "value": "authorization.k8s.io" 396 | }, 397 | { 398 | "key": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/spec/group", 399 | "flags": 0, 400 | "value": "autoscaling" 401 | }, 402 | { 403 | "key": "registry/apiregistration.k8s.io/apiservices/v1.batch/spec/group", 404 | "flags": 0, 405 | "value": "batch" 406 | }, 407 | { 408 | "key": "registry/apiregistration.k8s.io/apiservices/v1.crd.projectcalico.org/spec/group", 409 | "flags": 0, 410 | "value": "crd.projectcalico.org" 411 | }, 412 | { 413 | "key": "registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io/spec/group", 414 | "flags": 0, 415 | "value": "networking.k8s.io" 416 | }, 417 | { 418 | "key": "registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io/spec/group", 419 | "flags": 0, 420 | "value": "rbac.authorization.k8s.io" 421 | }, 422 | { 423 | "key": "registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io/spec/group", 424 | "flags": 0, 425 | "value": "storage.k8s.io" 426 | }, 427 | { 428 | "key": "registry/apiregistration.k8s.io/apiservices/v1alpha1.scheduling.k8s.io/spec/group", 429 | "flags": 0, 430 | "value": "scheduling.k8s.io" 431 | }, 432 | { 433 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io/spec/group", 434 | "flags": 0, 435 | "value": "admissionregistration.k8s.io" 436 | }, 437 | { 438 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io/spec/group", 439 | "flags": 0, 440 | "value": "apiextensions.k8s.io" 441 | }, 442 | { 443 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apps/spec/group", 444 | "flags": 0, 445 | "value": "apps" 446 | }, 447 | { 448 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io/spec/group", 449 | "flags": 0, 450 | "value": "authentication.k8s.io" 451 | }, 452 | { 453 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io/spec/group", 454 | "flags": 0, 455 | "value": "authorization.k8s.io" 456 | }, 457 | { 458 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.batch/spec/group", 459 | "flags": 0, 460 | "value": "batch" 461 | }, 462 | { 463 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io/spec/group", 464 | "flags": 0, 465 | "value": "certificates.k8s.io" 466 | }, 467 | { 468 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io/spec/group", 469 | "flags": 0, 470 | "value": "events.k8s.io" 471 | }, 472 | { 473 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.extensions/spec/group", 474 | "flags": 0, 475 | "value": "extensions" 476 | }, 477 | { 478 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.policy/spec/group", 479 | "flags": 0, 480 | "value": "policy" 481 | }, 482 | { 483 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/spec/group", 484 | "flags": 0, 485 | "value": "rbac.authorization.k8s.io" 486 | }, 487 | { 488 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io/spec/group", 489 | "flags": 0, 490 | "value": "storage.k8s.io" 491 | }, 492 | { 493 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta2.apps/spec/group", 494 | "flags": 0, 495 | "value": "apps" 496 | }, 497 | { 498 | "key": "registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling/spec/group", 499 | "flags": 0, 500 | "value": "autoscaling" 501 | }, 502 | { 503 | "key": "registry/apiregistration.k8s.io/apiservices/v1./spec/groupPriorityMinimum", 504 | "flags": 0, 505 | "value": "18000" 506 | }, 507 | { 508 | "key": "registry/apiregistration.k8s.io/apiservices/v1.apps/spec/groupPriorityMinimum", 509 | "flags": 0, 510 | "value": "17800" 511 | }, 512 | { 513 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/spec/groupPriorityMinimum", 514 | "flags": 0, 515 | "value": "17700" 516 | }, 517 | { 518 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io/spec/groupPriorityMinimum", 519 | "flags": 0, 520 | "value": "17600" 521 | }, 522 | { 523 | "key": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/spec/groupPriorityMinimum", 524 | "flags": 0, 525 | "value": "17500" 526 | }, 527 | { 528 | "key": "registry/apiregistration.k8s.io/apiservices/v1.batch/spec/groupPriorityMinimum", 529 | "flags": 0, 530 | "value": "17400" 531 | }, 532 | { 533 | "key": "registry/apiregistration.k8s.io/apiservices/v1.crd.projectcalico.org/spec/groupPriorityMinimum", 534 | "flags": 0, 535 | "value": "1000" 536 | }, 537 | { 538 | "key": "registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io/spec/groupPriorityMinimum", 539 | "flags": 0, 540 | "value": "17200" 541 | }, 542 | { 543 | "key": "registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io/spec/groupPriorityMinimum", 544 | "flags": 0, 545 | "value": "17000" 546 | }, 547 | { 548 | "key": "registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io/spec/groupPriorityMinimum", 549 | "flags": 0, 550 | "value": "16800" 551 | }, 552 | { 553 | "key": "registry/apiregistration.k8s.io/apiservices/v1alpha1.scheduling.k8s.io/spec/groupPriorityMinimum", 554 | "flags": 0, 555 | "value": "16600" 556 | }, 557 | { 558 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io/spec/groupPriorityMinimum", 559 | "flags": 0, 560 | "value": "16700" 561 | }, 562 | { 563 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io/spec/groupPriorityMinimum", 564 | "flags": 0, 565 | "value": "16700" 566 | }, 567 | { 568 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apps/spec/groupPriorityMinimum", 569 | "flags": 0, 570 | "value": "17800" 571 | }, 572 | { 573 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io/spec/groupPriorityMinimum", 574 | "flags": 0, 575 | "value": "17700" 576 | }, 577 | { 578 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io/spec/groupPriorityMinimum", 579 | "flags": 0, 580 | "value": "17600" 581 | }, 582 | { 583 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.batch/spec/groupPriorityMinimum", 584 | "flags": 0, 585 | "value": "17400" 586 | }, 587 | { 588 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io/spec/groupPriorityMinimum", 589 | "flags": 0, 590 | "value": "17300" 591 | }, 592 | { 593 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io/spec/groupPriorityMinimum", 594 | "flags": 0, 595 | "value": "17750" 596 | }, 597 | { 598 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.extensions/spec/groupPriorityMinimum", 599 | "flags": 0, 600 | "value": "17900" 601 | }, 602 | { 603 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.policy/spec/groupPriorityMinimum", 604 | "flags": 0, 605 | "value": "17100" 606 | }, 607 | { 608 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/spec/groupPriorityMinimum", 609 | "flags": 0, 610 | "value": "17000" 611 | }, 612 | { 613 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io/spec/groupPriorityMinimum", 614 | "flags": 0, 615 | "value": "16800" 616 | }, 617 | { 618 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta2.apps/spec/groupPriorityMinimum", 619 | "flags": 0, 620 | "value": "17800" 621 | }, 622 | { 623 | "key": "registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling/spec/groupPriorityMinimum", 624 | "flags": 0, 625 | "value": "17500" 626 | }, 627 | { 628 | "key": "registry/apiregistration.k8s.io/apiservices/v1./spec/version", 629 | "flags": 0, 630 | "value": "v1" 631 | }, 632 | { 633 | "key": "registry/apiregistration.k8s.io/apiservices/v1.apps/spec/version", 634 | "flags": 0, 635 | "value": "v1" 636 | }, 637 | { 638 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/spec/version", 639 | "flags": 0, 640 | "value": "v1" 641 | }, 642 | { 643 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io/spec/version", 644 | "flags": 0, 645 | "value": "v1" 646 | }, 647 | { 648 | "key": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/spec/version", 649 | "flags": 0, 650 | "value": "v1" 651 | }, 652 | { 653 | "key": "registry/apiregistration.k8s.io/apiservices/v1.batch/spec/version", 654 | "flags": 0, 655 | "value": "v1" 656 | }, 657 | { 658 | "key": "registry/apiregistration.k8s.io/apiservices/v1.crd.projectcalico.org/spec/version", 659 | "flags": 0, 660 | "value": "v1" 661 | }, 662 | { 663 | "key": "registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io/spec/version", 664 | "flags": 0, 665 | "value": "v1" 666 | }, 667 | { 668 | "key": "registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io/spec/version", 669 | "flags": 0, 670 | "value": "v1" 671 | }, 672 | { 673 | "key": "registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io/spec/version", 674 | "flags": 0, 675 | "value": "v1" 676 | }, 677 | { 678 | "key": "registry/apiregistration.k8s.io/apiservices/v1alpha1.scheduling.k8s.io/spec/version", 679 | "flags": 0, 680 | "value": "v1alpha1" 681 | }, 682 | { 683 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io/spec/version", 684 | "flags": 0, 685 | "value": "v1beta1" 686 | }, 687 | { 688 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io/spec/version", 689 | "flags": 0, 690 | "value": "v1beta1" 691 | }, 692 | { 693 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apps/spec/version", 694 | "flags": 0, 695 | "value": "v1beta1" 696 | }, 697 | { 698 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io/spec/version", 699 | "flags": 0, 700 | "value": "v1beta1" 701 | }, 702 | { 703 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io/spec/version", 704 | "flags": 0, 705 | "value": "v1beta1" 706 | }, 707 | { 708 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.batch/spec/version", 709 | "flags": 0, 710 | "value": "v1beta1" 711 | }, 712 | { 713 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io/spec/version", 714 | "flags": 0, 715 | "value": "v1beta1" 716 | }, 717 | { 718 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io/spec/version", 719 | "flags": 0, 720 | "value": "v1beta1" 721 | }, 722 | { 723 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.extensions/spec/version", 724 | "flags": 0, 725 | "value": "v1beta1" 726 | }, 727 | { 728 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.policy/spec/version", 729 | "flags": 0, 730 | "value": "v1beta1" 731 | }, 732 | { 733 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/spec/version", 734 | "flags": 0, 735 | "value": "v1beta1" 736 | }, 737 | { 738 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io/spec/version", 739 | "flags": 0, 740 | "value": "v1beta1" 741 | }, 742 | { 743 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta2.apps/spec/version", 744 | "flags": 0, 745 | "value": "v1beta2" 746 | }, 747 | { 748 | "key": "registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling/spec/version", 749 | "flags": 0, 750 | "value": "v2beta1" 751 | }, 752 | { 753 | "key": "registry/apiregistration.k8s.io/apiservices/v1./spec/versionPriority", 754 | "flags": 0, 755 | "value": "1" 756 | }, 757 | { 758 | "key": "registry/apiregistration.k8s.io/apiservices/v1.apps/spec/versionPriority", 759 | "flags": 0, 760 | "value": "15" 761 | }, 762 | { 763 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authentication.k8s.io/spec/versionPriority", 764 | "flags": 0, 765 | "value": "15" 766 | }, 767 | { 768 | "key": "registry/apiregistration.k8s.io/apiservices/v1.authorization.k8s.io/spec/versionPriority", 769 | "flags": 0, 770 | "value": "15" 771 | }, 772 | { 773 | "key": "registry/apiregistration.k8s.io/apiservices/v1.autoscaling/spec/versionPriority", 774 | "flags": 0, 775 | "value": "15" 776 | }, 777 | { 778 | "key": "registry/apiregistration.k8s.io/apiservices/v1.batch/spec/versionPriority", 779 | "flags": 0, 780 | "value": "15" 781 | }, 782 | { 783 | "key": "registry/apiregistration.k8s.io/apiservices/v1.crd.projectcalico.org/spec/versionPriority", 784 | "flags": 0, 785 | "value": "100" 786 | }, 787 | { 788 | "key": "registry/apiregistration.k8s.io/apiservices/v1.networking.k8s.io/spec/versionPriority", 789 | "flags": 0, 790 | "value": "15" 791 | }, 792 | { 793 | "key": "registry/apiregistration.k8s.io/apiservices/v1.rbac.authorization.k8s.io/spec/versionPriority", 794 | "flags": 0, 795 | "value": "15" 796 | }, 797 | { 798 | "key": "registry/apiregistration.k8s.io/apiservices/v1.storage.k8s.io/spec/versionPriority", 799 | "flags": 0, 800 | "value": "15" 801 | }, 802 | { 803 | "key": "registry/apiregistration.k8s.io/apiservices/v1alpha1.scheduling.k8s.io/spec/versionPriority", 804 | "flags": 0, 805 | "value": "9" 806 | }, 807 | { 808 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.admissionregistration.k8s.io/spec/versionPriority", 809 | "flags": 0, 810 | "value": "12" 811 | }, 812 | { 813 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apiextensions.k8s.io/spec/versionPriority", 814 | "flags": 0, 815 | "value": "9" 816 | }, 817 | { 818 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.apps/spec/versionPriority", 819 | "flags": 0, 820 | "value": "1" 821 | }, 822 | { 823 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authentication.k8s.io/spec/versionPriority", 824 | "flags": 0, 825 | "value": "9" 826 | }, 827 | { 828 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.authorization.k8s.io/spec/versionPriority", 829 | "flags": 0, 830 | "value": "9" 831 | }, 832 | { 833 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.batch/spec/versionPriority", 834 | "flags": 0, 835 | "value": "9" 836 | }, 837 | { 838 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.certificates.k8s.io/spec/versionPriority", 839 | "flags": 0, 840 | "value": "9" 841 | }, 842 | { 843 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.events.k8s.io/spec/versionPriority", 844 | "flags": 0, 845 | "value": "5" 846 | }, 847 | { 848 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.extensions/spec/versionPriority", 849 | "flags": 0, 850 | "value": "1" 851 | }, 852 | { 853 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.policy/spec/versionPriority", 854 | "flags": 0, 855 | "value": "9" 856 | }, 857 | { 858 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.rbac.authorization.k8s.io/spec/versionPriority", 859 | "flags": 0, 860 | "value": "12" 861 | }, 862 | { 863 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta1.storage.k8s.io/spec/versionPriority", 864 | "flags": 0, 865 | "value": "9" 866 | }, 867 | { 868 | "key": "registry/apiregistration.k8s.io/apiservices/v1beta2.apps/spec/versionPriority", 869 | "flags": 0, 870 | "value": "9" 871 | }, 872 | { 873 | "key": "registry/apiregistration.k8s.io/apiservices/v2beta1.autoscaling/spec/versionPriority", 874 | "flags": 0, 875 | "value": "9" 876 | } 877 | ] 878 | 879 | --------------------------------------------------------------------------------