Commit 9691af83 by Chris Trott Committed by GitHub

DashboardSchemas: OpenAPI Schema Generation (#30242)

* Go program to output openapi

* Fix number type syntax

Resolves error: 'unsupported op for number &'

* Render just the schemas

* Use args as entrypoints and add test

* Update README, tidy go.mod
parent b1debc9c
......@@ -20,7 +20,7 @@ package main
// 0 for no shared crosshair or tooltip (default).
// 1 for shared crosshair.
// 2 for shared crosshair AND shared tooltip.
graphTooltip: int & >=0 & <=2 | *0
graphTooltip: int >= 0 <= 2 | *0
// Time range for dashboard, e.g. last 6 hours, last 7 days, etc
time?: {
from: string | *"now-6h"
......
......@@ -63,9 +63,24 @@ be a base schema for panels. `#Gauge` extends `#panel` with the following:
## Exporting OpenAPI
[OpenAPI](https://swagger.io/specification/) schemas can be exported from these CUE sources. Use the `cue`
command as follows, to generate OpenAPI JSON to stdout:
[OpenAPI](https://www.openapis.org/) schemas can be exported from these CUE
sources.
### Command Line
While you can use `cue export` to output OpenAPI documents, it does not expand
references which makes the output unusable.
```
cue export --out openapi -o - ./...
```
### Using Go
You need to use Go to generate useable OpenAPI schemas. This directory contains
a Go program that will output just the OpenAPI schemas for one or many Cue
packages.
```
cue export --out openapi -o - ./dashboard-schemas/...
go run . <entrypoint> ...
```
module github.com/grafana/grafana/dashboard-schemas
go 1.15
require cuelang.org/go v0.2.2
package main
import (
"fmt"
"log"
"os"
"cuelang.org/go/cue"
"cuelang.org/go/cue/load"
"cuelang.org/go/encoding/openapi"
)
func main() {
b, err := openAPISchemas(os.Args[1:])
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
}
// openAPISchemas returns OpenAPI schema JSON of the Cue entrypoints passed to
// it. It is not a valid OpenAPI document - just the schemas.
func openAPISchemas(entrypoints []string) ([]byte, error) {
var r cue.Runtime
cfg := openapi.Config{
ExpandReferences: true,
}
bis := load.Instances(entrypoints, nil)
// collect all schemas
var pairs []openapi.KeyValue
for _, bi := range bis {
if bi.Err != nil {
return nil, bi.Err
}
inst, err := r.Build(bi)
if err != nil {
return nil, err
}
om, err := cfg.Schemas(inst)
if err != nil {
return nil, err
}
pairs = append(pairs, om.Pairs()...)
}
// add all schemas to new ordered map
om := openapi.OrderedMap{}
om.SetAll(pairs)
j, err := om.MarshalJSON()
if err != nil {
return nil, err
}
return j, nil
}
package main
import (
"encoding/json"
"testing"
)
func TestOpenAPISchemas(t *testing.T) {
tests := map[string]struct {
entrypoints []string
}{
"All packages": {
entrypoints: []string{"./..."},
},
"One package": {
entrypoints: []string{"./panels"},
},
"Many packags": {
entrypoints: []string{
"./panels",
"./targets",
"./transformations",
"./variables",
},
},
}
for testName, test := range tests {
t.Logf("Running test case %s...", testName)
j, err := openAPISchemas(test.entrypoints)
if err != nil {
t.Fatal(err)
}
// We don't want to validate the JSON content since it's expected to change
// often. Only that it is valid JSON by unmarshalling it.
var iface interface{}
err = json.Unmarshal(j, &iface)
if err != nil {
t.Fatal(err)
}
}
}
......@@ -20,10 +20,10 @@ package panels
overrides: [..._override]
}
// Amount of color fill for a series. Expects a value between 0 and 1.
fill: number & >=0 & <=1 | *1
fill: number >= 0 <= 1 | *1
// Degree of gradient on the area fill. 0 is no gradient, 10 is a steep
// gradient.
fillGradient: int & >=0 & <=10 | *0
fillGradient: int >= 0 <= 10 | *0
// Hide the series.
hiddenSeries: bool | *false
// Lengend options.
......@@ -133,7 +133,7 @@ package panels
// and in increasing order, with the lowest value at the top of the list.
// * 2 (decreasing) - The series in the hover tooltip are sorted by value
// and in decreasing order, with the highest value at the top of the list.
sort: int & >=0 & <=2 | *2
sort: int >= 0 <= 2 | *2
// Value type.
value_type: string | *"individual"
}
......
......@@ -2,11 +2,11 @@ package panels
_gridPos: {
// Panel height.
h: int & >0 | *9
h?: int > 0 | *9
// Panel width.
w: int & >0 <= 24 | 12
w?: int > 0 <= 24 | *12
// Panel x position.
x: int & >0 < 24
x?: int >= 0 < 24 | *0
// Panel y position.
y: int & >0
y?: int >= 0 | *0
}
......@@ -20,7 +20,7 @@ package variables
// * 4 - Numerical (desc).
// * 5 - Alphabetical (case-insensitive, asc).
// * 6 - Alphabetical (case-insensitive, desc).
sort: int & >=0 & <=6 | *0
sort: int >= 0 <= 6 | *0
tagValuesQuery?: string
tags: [...string] | *[]
tagsQuery?: string
......
......@@ -11,7 +11,7 @@ _variable: {
// * 0 - Show all.
// * 1 - Hide label.
// * 2 - Hide label and variable.
hide: int & >=0 & <=2 | *0
hide: int >= 0 <= 2 | *0
// Enable include all option.
includeAll: bool | *false
// When includeAll is enabled, this sets its value.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment