Files
grafana/pkg/registry/apis/datasource/openapi.go
Ryan McKinley 732d4351de with hooks
2025-07-03 17:44:44 -07:00

132 lines
3.8 KiB
Go

package datasource
import (
"fmt"
"maps"
"strings"
"k8s.io/kube-openapi/pkg/spec3"
"k8s.io/kube-openapi/pkg/validation/spec"
secretsV0 "github.com/grafana/grafana/pkg/apis/secret/v0alpha1"
"github.com/grafana/grafana/pkg/registry/apis/query/queryschema"
"github.com/grafana/grafana/pkg/services/apiserver/builder"
)
func (b *DataSourceAPIBuilder) PostProcessOpenAPI(oas *spec3.OpenAPI) (*spec3.OpenAPI, error) {
// The plugin description
oas.Info.Description = b.pluginJSON.Info.Description
// The root api URL
root := "/apis/" + b.datasourceResourceInfo.GroupVersion().String() + "/"
// Add queries to the request properties
if err := queryschema.AddQueriesToOpenAPI(queryschema.OASQueryOptions{
Swagger: oas,
PluginJSON: &b.pluginJSON,
QueryTypes: b.queryTypes,
Root: root,
QueryPath: "namespaces/{namespace}/datasources/{name}/query",
QueryDescription: fmt.Sprintf("Query the %s datasources", b.pluginJSON.Name),
}); err != nil {
return nil, err
}
// Set explicit apiVersion and kind on the datasource
ds, ok := oas.Components.Schemas["com.github.grafana.grafana.pkg.apis.datasource.v0alpha1.DataSource"]
if !ok {
return nil, fmt.Errorf("missing DS type")
}
ds.Properties["apiVersion"] = *spec.StringProperty().WithEnum(b.GetGroupVersion().String())
ds.Properties["kind"] = *spec.StringProperty().WithEnum("DataSource")
if b.specProvider == nil {
return oas, nil
}
custom, err := b.specProvider()
if err != nil {
return nil, err
}
if custom == nil {
return oas, nil // nothing special
}
// Add custom schemas
maps.Copy(oas.Components.Schemas, custom.Schemas)
// Replace the generic DataSourceSpec with the explicit one
if custom.DataSourceSpec != nil {
oas.Components.Schemas["DataSourceSpec"] = custom.DataSourceSpec
ds.Properties["spec"] = spec.Schema{
SchemaProps: spec.SchemaProps{
Ref: spec.MustCreateRef("#/components/schemas/DataSourceSpec"),
},
}
}
if custom.SecureValues != nil {
example := secretsV0.InlineSecureValues{}
ref := spec.MustCreateRef("#/components/schemas/com.github.grafana.grafana.pkg.apis.secret.v0alpha1.InlineSecureValue")
secure := &spec.Schema{
SchemaProps: spec.SchemaProps{
Properties: make(map[string]spec.Schema),
AdditionalProperties: &spec.SchemaOrBool{Allows: false},
}}
secure.Description = "custom secure value definition"
for _, v := range custom.SecureValues {
secure.Properties[v.Key] = spec.Schema{
SchemaProps: spec.SchemaProps{
Description: v.Description,
Ref: ref,
},
}
if v.Required {
secure.Required = append(secure.Required, v.Key)
example[v.Key] = secretsV0.InlineSecureValue{Create: "***"}
}
}
if len(example) > 0 {
secure.Example = example
}
// Link the explicit secure values in the resource
oas.Components.Schemas["SecureValues"] = secure
ds.Properties["secure"] = spec.Schema{
SchemaProps: spec.SchemaProps{
Ref: spec.MustCreateRef("#/components/schemas/SecureValues"),
},
}
}
if len(custom.Routes) > 0 {
ds := oas.Paths.Paths[root+"namespaces/{namespace}/datasources/{name}"]
if ds == nil || len(ds.Parameters) < 2 {
return nil, fmt.Errorf("missing parmeters")
}
prefix := root + "namespaces/{namespace}/datasources/{name}/resource"
for k := range oas.Paths.Paths {
if strings.HasPrefix(k, prefix) {
delete(oas.Paths.Paths, k)
}
}
for k, v := range custom.Routes {
if k != "" && !strings.HasPrefix(k, "/") {
return nil, fmt.Errorf("path must have slash prefix")
}
v.Parameters = append(v.Parameters, ds.Parameters[0:2]...)
for _, op := range builder.GetPathOperations(v) {
if op != nil {
op.Tags = append(op.Tags, "Route") // Custom resource?
}
}
oas.Paths.Paths[prefix+k] = v // TODO add namepsace + name parameters
}
}
return oas, err
}