Chore: Update to the latest grafana-plugin-sdk-go and more swagger fixes (#52445)

* Fix get legacy alert response

* Swagger: Fix get folder by UID response

* Fix conflicting swagger model Alert

Reanme legacy alerting swagger model to LegacyAlert to differentiate it
from the prometheus Alert

* Bump grafana-plugin-sdk-go

* Fix get folder response

* Use go-swagger command for merging the specifications and remove merge_specs script
This commit is contained in:
Sofia Papagiannaki 2022-07-20 16:09:42 +03:00 committed by GitHub
parent d3d8fdd878
commit f7c5eceb21
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 916 additions and 962 deletions

View File

@ -39,8 +39,9 @@ NGALERT_SPEC_TARGET = pkg/services/ngalert/api/tooling/api.json
$(NGALERT_SPEC_TARGET): $(NGALERT_SPEC_TARGET):
+$(MAKE) -C pkg/services/ngalert/api/tooling api.json +$(MAKE) -C pkg/services/ngalert/api/tooling api.json
$(MERGED_SPEC_TARGET): $(SPEC_TARGET) $(NGALERT_SPEC_TARGET) ## Merge generated and ngalert API specs $(MERGED_SPEC_TARGET): $(SPEC_TARGET) $(NGALERT_SPEC_TARGET) $(SWAGGER) ## Merge generated and ngalert API specs
go run pkg/api/docs/merge/merge_specs.go -o=$(MERGED_SPEC_TARGET) $(<) $(NGALERT_SPEC_TARGET) # known conflicts DsPermissionType, AddApiKeyCommand, Json, Duration (identical models referenced by both specs)
$(SWAGGER) mixin $(SPEC_TARGET) $(NGALERT_SPEC_TARGET) --ignore-conflicts -o $(MERGED_SPEC_TARGET)
--swagger-api-spec: $(API_DEFINITION_FILES) $(SWAGGER) ## Generate API Swagger specification --swagger-api-spec: $(API_DEFINITION_FILES) $(SWAGGER) ## Generate API Swagger specification
SWAGGER_GENERATE_EXTENSION=false $(SWAGGER) generate spec -m -w pkg/server -o public/api-spec.json \ SWAGGER_GENERATE_EXTENSION=false $(SWAGGER) generate spec -m -w pkg/server -o public/api-spec.json \

2
go.mod
View File

@ -54,7 +54,7 @@ require (
github.com/grafana/cuetsy v0.0.3 github.com/grafana/cuetsy v0.0.3
github.com/grafana/grafana-aws-sdk v0.10.7 github.com/grafana/grafana-aws-sdk v0.10.7
github.com/grafana/grafana-azure-sdk-go v1.3.0 github.com/grafana/grafana-azure-sdk-go v1.3.0
github.com/grafana/grafana-plugin-sdk-go v0.138.0 github.com/grafana/grafana-plugin-sdk-go v0.139.0
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
github.com/hashicorp/go-hclog v1.0.0 github.com/hashicorp/go-hclog v1.0.0
github.com/hashicorp/go-plugin v1.4.3 github.com/hashicorp/go-plugin v1.4.3

2
go.sum
View File

@ -1345,6 +1345,8 @@ github.com/grafana/grafana-google-sdk-go v0.0.0-20211104130251-b190293eaf58/go.m
github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk= github.com/grafana/grafana-plugin-sdk-go v0.114.0/go.mod h1:D7x3ah+1d4phNXpbnOaxa/osSaZlwh9/ZUnGGzegRbk=
github.com/grafana/grafana-plugin-sdk-go v0.138.0 h1:uJWNwHL4RoQF3axoi3RDSwoNu/KHy5F+5dnrK0fx5yc= github.com/grafana/grafana-plugin-sdk-go v0.138.0 h1:uJWNwHL4RoQF3axoi3RDSwoNu/KHy5F+5dnrK0fx5yc=
github.com/grafana/grafana-plugin-sdk-go v0.138.0/go.mod h1:Y+Ps2sesZ62AyCnX+hzrYnyDQYe/ZZl+A8yKLOBm12c= github.com/grafana/grafana-plugin-sdk-go v0.138.0/go.mod h1:Y+Ps2sesZ62AyCnX+hzrYnyDQYe/ZZl+A8yKLOBm12c=
github.com/grafana/grafana-plugin-sdk-go v0.139.0 h1:2RQKM2QpSaWTtaGN6sK+R7LO7zykOeTYF0QkAMA7JsI=
github.com/grafana/grafana-plugin-sdk-go v0.139.0/go.mod h1:Y+Ps2sesZ62AyCnX+hzrYnyDQYe/ZZl+A8yKLOBm12c=
github.com/grafana/saml v0.0.0-20211007135653-aed1b2edd86b h1:YiSGp34F4V0G08HHx1cJBf2GVgwYAkXQjzuVs1t8jYk= github.com/grafana/saml v0.0.0-20211007135653-aed1b2edd86b h1:YiSGp34F4V0G08HHx1cJBf2GVgwYAkXQjzuVs1t8jYk=
github.com/grafana/saml v0.0.0-20211007135653-aed1b2edd86b/go.mod h1:q83kyQoMD0vhy+RzFLlbw0UgHJ6TAihQpuXvdFmm4s4= github.com/grafana/saml v0.0.0-20211007135653-aed1b2edd86b/go.mod h1:q83kyQoMD0vhy+RzFLlbw0UgHJ6TAihQpuXvdFmm4s4=
github.com/grafana/thema v0.0.0-20220523183731-72aebd14e751 h1:5PpsfN52XA0hxOjD/qQ0QNiEkp9Y9Tb+yz/Hj9fyL4M= github.com/grafana/thema v0.0.0-20220523183731-72aebd14e751 h1:5PpsfN52XA0hxOjD/qQ0QNiEkp9Y9Tb+yz/Hj9fyL4M=

View File

@ -22,7 +22,7 @@ import (
// Get folder by uid. // Get folder by uid.
// //
// Responses: // Responses:
// 200: // 200: folderResponse
// 401: unauthorisedError // 401: unauthorisedError
// 403: forbiddenError // 403: forbiddenError
// 404: notFoundError // 404: notFoundError

View File

@ -148,7 +148,7 @@ type GetAlertsResponse struct {
type GetAlertResponse struct { type GetAlertResponse struct {
// The response message // The response message
// in: body // in: body
Body []*models.Alert `json:"body"` Body *models.Alert `json:"body"`
} }
// swagger:response pauseAlertResponse // swagger:response pauseAlertResponse

View File

@ -65,7 +65,7 @@ import (
// Get Team Members. // Get Team Members.
// //
// Responses: // Responses:
// 200: okResponse // 200: getTeamMembersResponse
// 401: unauthorisedError // 401: unauthorisedError
// 403: forbiddenError // 403: forbiddenError
// 404: notFoundError // 404: notFoundError

View File

@ -1,147 +0,0 @@
package main
import (
"bytes"
_ "embed"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"os"
"reflect"
"strings"
"github.com/go-openapi/loads"
"github.com/go-openapi/spec"
)
func mergeVectors(a, b []string) []string {
for _, p := range b {
exist := false
for _, op := range a {
if op == p {
exist = true
break
}
}
if !exist {
a = append(a, p)
}
}
return a
}
func compareDefinition(a, b spec.Schema) bool {
return reflect.DeepEqual(a.Type, b.Type) && a.Format == b.Format && reflect.DeepEqual(a.Properties, b.Properties)
}
// mergeSpecs merges OSS API spec with one or more other OpenAPI specs
func mergeSpecs(output string, sources ...string) error {
if len(sources) < 2 {
return fmt.Errorf("no APIs to merge")
}
f, err := os.Open(sources[0])
if err != nil {
return err
}
specData, err := ioutil.ReadAll(f)
if err != nil {
return err
}
var specOSS spec.Swagger
if err := json.Unmarshal(specData, &specOSS); err != nil {
return fmt.Errorf("failed to unmarshal original spec: %w", err)
}
for _, s := range sources[1:] {
additionalSpec, err := loads.JSONSpec(s)
if err != nil {
return fmt.Errorf("failed to load spec from: %s: %w", s, err)
}
// Merge consumes
specOSS.SwaggerProps.Consumes = mergeVectors(specOSS.SwaggerProps.Consumes, additionalSpec.OrigSpec().Consumes)
// Merge produces
specOSS.SwaggerProps.Produces = mergeVectors(specOSS.SwaggerProps.Produces, additionalSpec.OrigSpec().Produces)
// Merge schemes
specOSS.SwaggerProps.Schemes = mergeVectors(specOSS.SwaggerProps.Schemes, additionalSpec.OrigSpec().Schemes)
//TODO: When there are conflict between definitions, we need to error out, but here we need to fix the existing conflict first
// there are false positives, we will have to fix those by regenerate alerting api spec
for k, ad := range additionalSpec.OrigSpec().SwaggerProps.Definitions {
if ossd, exists := specOSS.SwaggerProps.Definitions[k]; exists {
if !compareDefinition(ad, ossd) {
fmt.Printf("the definition of %s differs in specs!\n", k)
}
}
specOSS.SwaggerProps.Definitions[k] = ad
}
for k, ar := range additionalSpec.OrigSpec().SwaggerProps.Responses {
if ossr, exists := specOSS.SwaggerProps.Responses[k]; exists {
if !reflect.DeepEqual(ar, ossr) {
fmt.Printf("the definition of response %s differs in specs!\n", k)
}
}
specOSS.SwaggerProps.Responses[k] = ar
}
for k, p := range additionalSpec.OrigSpec().SwaggerProps.Parameters {
specOSS.SwaggerProps.Parameters[k] = p
}
paths := additionalSpec.OrigSpec().SwaggerProps.Paths
if paths != nil {
for k, pi := range paths.Paths {
kk := strings.TrimPrefix(k, specOSS.BasePath) // remove base path if exists
if specOSS.SwaggerProps.Paths == nil {
specOSS.SwaggerProps.Paths = &spec.Paths{
Paths: make(map[string]spec.PathItem),
}
}
specOSS.SwaggerProps.Paths.Paths[kk] = pi
}
}
specOSS.SwaggerProps.Tags = append(specOSS.SwaggerProps.Tags, additionalSpec.OrigSpec().SwaggerProps.Tags...)
}
// write result to file
newSpec, err := specOSS.MarshalJSON()
if err != nil {
return fmt.Errorf("failed to marshal result spec: %w", err)
}
var prettyJSON bytes.Buffer
err = json.Indent(&prettyJSON, newSpec, "", "\t")
if err != nil {
return fmt.Errorf("failed to intend new spec: %w", err)
}
f, err = os.Create(output)
if err != nil {
return fmt.Errorf("failed to create file for new spec: %w", err)
}
_, err = f.Write(prettyJSON.Bytes())
if err != nil {
return fmt.Errorf("failed to write new spec: %w", err)
}
// validate result
return nil
}
func main() {
output := flag.String("o", "../../../swagger-ui/merged.json", "the output path")
flag.Parse()
err := mergeSpecs(*output, flag.Args()...)
if err != nil {
fmt.Printf("something went wrong: %s\n", err.Error())
}
}

View File

@ -63,6 +63,7 @@ func (s ExecutionErrorOption) ToAlertState() AlertStateType {
return AlertStateType(s) return AlertStateType(s)
} }
// swagger:model LegacyAlert
type Alert struct { type Alert struct {
Id int64 Id int64
Version int64 Version int64

File diff suppressed because it is too large Load Diff

View File

@ -2618,7 +2618,7 @@
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/UpdateDashboardAclCommand" "$ref": "#/definitions/UpdateDashboardACLCommand"
} }
}, },
{ {
@ -2976,7 +2976,7 @@
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/UpdateDashboardAclCommand" "$ref": "#/definitions/UpdateDashboardACLCommand"
} }
}, },
{ {
@ -4218,7 +4218,7 @@
], ],
"responses": { "responses": {
"200": { "200": {
"description": "" "$ref": "#/responses/folderResponse"
}, },
"401": { "401": {
"$ref": "#/responses/unauthorisedError" "$ref": "#/responses/unauthorisedError"
@ -4368,7 +4368,7 @@
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/UpdateDashboardAclCommand" "$ref": "#/definitions/UpdateDashboardACLCommand"
} }
} }
], ],
@ -7866,7 +7866,7 @@
], ],
"responses": { "responses": {
"200": { "200": {
"$ref": "#/responses/okResponse" "$ref": "#/responses/getTeamMembersResponse"
}, },
"401": { "401": {
"$ref": "#/responses/unauthorisedError" "$ref": "#/responses/unauthorisedError"
@ -9120,82 +9120,6 @@
} }
} }
}, },
"Alert": {
"type": "object",
"properties": {
"Created": {
"type": "string",
"format": "date-time"
},
"DashboardId": {
"type": "integer",
"format": "int64"
},
"EvalData": {
"$ref": "#/definitions/Json"
},
"ExecutionError": {
"type": "string"
},
"For": {
"$ref": "#/definitions/Duration"
},
"Frequency": {
"type": "integer",
"format": "int64"
},
"Handler": {
"type": "integer",
"format": "int64"
},
"Id": {
"type": "integer",
"format": "int64"
},
"Message": {
"type": "string"
},
"Name": {
"type": "string"
},
"NewStateDate": {
"type": "string",
"format": "date-time"
},
"OrgId": {
"type": "integer",
"format": "int64"
},
"PanelId": {
"type": "integer",
"format": "int64"
},
"Settings": {
"$ref": "#/definitions/Json"
},
"Severity": {
"type": "string"
},
"Silenced": {
"type": "boolean"
},
"State": {
"$ref": "#/definitions/AlertStateType"
},
"StateChanges": {
"type": "integer",
"format": "int64"
},
"Updated": {
"type": "string",
"format": "date-time"
},
"Version": {
"type": "integer",
"format": "int64"
}
}
},
"AlertListItemDTO": { "AlertListItemDTO": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -9889,7 +9813,7 @@
} }
} }
}, },
"DashboardAclInfoDTO": { "DashboardACLInfoDTO": {
"type": "object", "type": "object",
"properties": { "properties": {
"created": { "created": {
@ -9964,7 +9888,7 @@
} }
} }
}, },
"DashboardAclUpdateItem": { "DashboardACLUpdateItem": {
"type": "object", "type": "object",
"properties": { "properties": {
"permission": { "permission": {
@ -10078,6 +10002,9 @@
"publicDashboardAccessToken": { "publicDashboardAccessToken": {
"type": "string" "type": "string"
}, },
"publicDashboardEnabled": {
"type": "boolean"
},
"slug": { "slug": {
"type": "string" "type": "string"
}, },
@ -10547,6 +10474,10 @@
} }
} }
}, },
"DataTopic": {
"type": "string",
"title": "DataTopic is used to identify which topic the frame should be assigned to."
},
"DeleteTokenCommand": { "DeleteTokenCommand": {
"type": "object", "type": "object",
"properties": { "properties": {
@ -10624,7 +10555,7 @@
"$ref": "#/definitions/FieldConfig" "$ref": "#/definitions/FieldConfig"
}, },
"labels": { "labels": {
"$ref": "#/definitions/Labels" "$ref": "#/definitions/FrameLabels"
}, },
"name": { "name": {
"description": "Name is default identifier of the field. The name does not have to be unique, but the combination\nof name and Labels should be unique for proper behavior in all situations.", "description": "Name is default identifier of the field. The name does not have to be unique, but the combination\nof name and Labels should be unique for proper behavior in all situations.",
@ -10835,6 +10766,13 @@
} }
} }
}, },
"FrameLabels": {
"description": "Labels are used to add metadata to an object. The JSON will always be sorted keys",
"type": "object",
"additionalProperties": {
"type": "string"
}
},
"FrameMeta": { "FrameMeta": {
"description": "https://github.com/grafana/grafana/blob/master/packages/grafana-data/src/types/data.ts#L11\nNOTE -- in javascript this can accept any `[key: string]: any;` however\nthis interface only exposes the values we want to be exposed", "description": "https://github.com/grafana/grafana/blob/master/packages/grafana-data/src/types/data.ts#L11\nNOTE -- in javascript this can accept any `[key: string]: any;` however\nthis interface only exposes the values we want to be exposed",
"type": "object", "type": "object",
@ -10848,6 +10786,9 @@
"description": "Custom datasource specific values.", "description": "Custom datasource specific values.",
"type": "object" "type": "object"
}, },
"dataTopic": {
"$ref": "#/definitions/DataTopic"
},
"executedQueryString": { "executedQueryString": {
"description": "ExecutedQueryString is the raw query sent to the underlying system. All macros and templating\nhave been applied. When metadata contains this value, it will be shown in the query inspector.", "description": "ExecutedQueryString is the raw query sent to the underlying system. All macros and templating\nhave been applied. When metadata contains this value, it will be shown in the query inspector.",
"type": "string" "type": "string"
@ -11175,11 +11116,80 @@
"Json": { "Json": {
"type": "object" "type": "object"
}, },
"Labels": { "LegacyAlert": {
"description": "Labels are used to add metadata to an object. The JSON will always be sorted keys",
"type": "object", "type": "object",
"additionalProperties": { "properties": {
"type": "string" "Created": {
"type": "string",
"format": "date-time"
},
"DashboardId": {
"type": "integer",
"format": "int64"
},
"EvalData": {
"$ref": "#/definitions/Json"
},
"ExecutionError": {
"type": "string"
},
"For": {
"$ref": "#/definitions/Duration"
},
"Frequency": {
"type": "integer",
"format": "int64"
},
"Handler": {
"type": "integer",
"format": "int64"
},
"Id": {
"type": "integer",
"format": "int64"
},
"Message": {
"type": "string"
},
"Name": {
"type": "string"
},
"NewStateDate": {
"type": "string",
"format": "date-time"
},
"OrgId": {
"type": "integer",
"format": "int64"
},
"PanelId": {
"type": "integer",
"format": "int64"
},
"Settings": {
"$ref": "#/definitions/Json"
},
"Severity": {
"type": "string"
},
"Silenced": {
"type": "boolean"
},
"State": {
"$ref": "#/definitions/AlertStateType"
},
"StateChanges": {
"type": "integer",
"format": "int64"
},
"Updated": {
"type": "string",
"format": "date-time"
},
"Version": {
"type": "integer",
"format": "int64"
}
} }
}, },
"LibraryElementConnectionDTO": { "LibraryElementConnectionDTO": {
@ -12270,7 +12280,7 @@
} }
}, },
"Responses": { "Responses": {
"description": "The QueryData method the QueryDataHandler method will set the RefId\nproperty on the DataRespones' frames based on these RefIDs.", "description": "The QueryData method the QueryDataHandler method will set the RefId\nproperty on the DataResponses' frames based on these RefIDs.",
"type": "object", "type": "object",
"title": "Responses is a map of RefIDs (Unique Query ID) to DataResponses.", "title": "Responses is a map of RefIDs (Unique Query ID) to DataResponses.",
"additionalProperties": { "additionalProperties": {
@ -13164,13 +13174,13 @@
} }
} }
}, },
"UpdateDashboardAclCommand": { "UpdateDashboardACLCommand": {
"type": "object", "type": "object",
"properties": { "properties": {
"items": { "items": {
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/DashboardAclUpdateItem" "$ref": "#/definitions/DashboardACLUpdateItem"
} }
} }
} }
@ -14058,10 +14068,7 @@
"getAlertResponse": { "getAlertResponse": {
"description": "", "description": "",
"schema": { "schema": {
"type": "array", "$ref": "#/definitions/LegacyAlert"
"items": {
"$ref": "#/definitions/Alert"
}
} }
}, },
"getAlertsResponse": { "getAlertsResponse": {
@ -14126,7 +14133,7 @@
"schema": { "schema": {
"type": "array", "type": "array",
"items": { "items": {
"$ref": "#/definitions/DashboardAclInfoDTO" "$ref": "#/definitions/DashboardACLInfoDTO"
} }
} }
}, },