K8s/Dashboards: Fix panics in Dashboards v2alpha1 API (#102123)

* K8s/Dashboards: Fix panics in Dashboards v2alpha1 API

Signed-off-by: Igor Suleymanov <igor.suleymanov@grafana.com>

* Update generated code to use the `MappingType` properly

Signed-off-by: Igor Suleymanov <igor.suleymanov@grafana.com>

---------

Signed-off-by: Igor Suleymanov <igor.suleymanov@grafana.com>
This commit is contained in:
Igor Suleymanov 2025-03-17 15:04:11 +02:00 committed by GitHub
parent f1470de478
commit 3f270d1de0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 91 additions and 112 deletions

View File

@ -42,6 +42,9 @@ dashboard: {
}
go: {
enabled: true
config: {
allowMarshalEmptyDisjunctions: true
}
}
}

View File

@ -263,15 +263,12 @@ ValueMapping: ValueMap | RangeMap | RegexMap | SpecialValueMap
// `range`: Maps numerical ranges to a display text and color. For example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.
// `regex`: Maps regular expressions to replacement text and a color. For example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.
// `special`: Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color. See SpecialValueMatch to see the list of special values. For example, you can configure a special value mapping so that null values appear as N/A.
MappingType: "value" | "range" | "regex" | "special" @cog(kind="enum",memberNames="ValueToText|RangeToText|RegexToText|SpecialValue")
MappingType: "value" | "range" | "regex" | "special"
// Maps text values to a color or different display text and color.
// For example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.
ValueMap: {
// TODO (@radiohead): Something broke in cog / app SDK codegen
// And this is no longer producing valid TS / Go output
// type: MappingType & "value"
type: "value"
type: MappingType & "value"
// Map with <value_to_match>: ValueMappingResult. For example: { "10": { text: "Perfection!", color: "green" } }
options: [string]: ValueMappingResult
}
@ -279,10 +276,7 @@ ValueMap: {
// Maps numerical ranges to a display text and color.
// For example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.
RangeMap: {
// TODO (@radiohead): Something broke in cog / app SDK codegen
// And this is no longer producing valid TS / Go output
// type: MappingType & "range"
type: "range"
type: MappingType & "range"
// Range to match against and the result to apply when the value is within the range
options: {
// Min value of the range. It can be null which means -Infinity
@ -297,10 +291,7 @@ RangeMap: {
// Maps regular expressions to replacement text and a color.
// For example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.
RegexMap: {
// TODO (@radiohead): Something broke in cog / app SDK codegen
// And this is no longer producing valid TS / Go output
// type: MappingType & "regex"
type: "regex"
type: MappingType & "regex"
// Regular expression to match against and the result to apply when the value matches the regex
options: {
// Regular expression to match against
@ -314,10 +305,7 @@ RegexMap: {
// See SpecialValueMatch to see the list of special values.
// For example, you can configure a special value mapping so that null values appear as N/A.
SpecialValueMap: {
// TODO (@radiohead): Something broke in cog / app SDK codegen
// And this is no longer producing valid TS / Go output
// type: MappingType & "special"
type: "special"
type: MappingType & "special"
options: {
// Special value to match against
match: SpecialValueMatch
@ -562,11 +550,11 @@ RowsLayoutRowKind: {
}
RowsLayoutRowSpec: {
title?: string
collapsed: bool
conditionalRendering?: ConditionalRenderingGroupKind
repeat?: RowRepeatOptions
layout: GridLayoutKind | ResponsiveGridLayoutKind | TabsLayoutKind
title?: string
collapsed: bool
conditionalRendering?: ConditionalRenderingGroupKind
repeat?: RowRepeatOptions
layout: GridLayoutKind | ResponsiveGridLayoutKind | TabsLayoutKind
}
ResponsiveGridLayoutKind: {
@ -586,9 +574,9 @@ ResponsiveGridLayoutItemKind: {
}
ResponsiveGridLayoutItemSpec: {
element: ElementReference
repeat?: ResponsiveGridRepeatOptions
conditionalRendering?: ConditionalRenderingGroupKind
element: ElementReference
repeat?: ResponsiveGridRepeatOptions
conditionalRendering?: ConditionalRenderingGroupKind
}
TabsLayoutKind: {
@ -925,40 +913,40 @@ AdhocVariableKind: {
}
ConditionalRenderingGroupKind: {
kind: "ConditionalRenderingGroup"
spec: ConditionalRenderingGroupSpec
kind: "ConditionalRenderingGroup"
spec: ConditionalRenderingGroupSpec
}
ConditionalRenderingGroupSpec: {
condition: "and" | "or"
items: [...ConditionalRenderingVariableKind | ConditionalRenderingDataKind | ConditionalRenderingTimeIntervalKind]
condition: "and" | "or"
items: [...ConditionalRenderingVariableKind | ConditionalRenderingDataKind | ConditionalRenderingTimeIntervalKind]
}
ConditionalRenderingVariableKind: {
kind: "ConditionalRenderingVariable"
spec: ConditionalRenderingVariableSpec
kind: "ConditionalRenderingVariable"
spec: ConditionalRenderingVariableSpec
}
ConditionalRenderingVariableSpec: {
variable: string
operator: "equals" | "notEquals"
value: string
variable: string
operator: "equals" | "notEquals"
value: string
}
ConditionalRenderingDataKind: {
kind: "ConditionalRenderingData"
spec: ConditionalRenderingDataSpec
kind: "ConditionalRenderingData"
spec: ConditionalRenderingDataSpec
}
ConditionalRenderingDataSpec: {
value: bool
value: bool
}
ConditionalRenderingTimeIntervalKind: {
kind: "ConditionalRenderingTimeInterval"
spec: ConditionalRenderingTimeIntervalSpec
}
kind: "ConditionalRenderingTimeInterval"
spec: ConditionalRenderingTimeIntervalSpec
}
ConditionalRenderingTimeIntervalSpec: {
value: string
}
value: string
}

View File

@ -407,10 +407,7 @@ func NewDashboardValueMapping() *DashboardValueMapping {
// For example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.
// +k8s:openapi-gen=true
type DashboardValueMap struct {
// TODO (@radiohead): Something broke in cog / app SDK codegen
// And this is no longer producing valid TS / Go output
// type: MappingType & "value"
Type string `json:"type"`
Type DashboardMappingType `json:"type"`
// Map with <value_to_match>: ValueMappingResult. For example: { "10": { text: "Perfection!", color: "green" } }
Options map[string]DashboardValueMappingResult `json:"options"`
}
@ -418,10 +415,25 @@ type DashboardValueMap struct {
// NewDashboardValueMap creates a new DashboardValueMap object.
func NewDashboardValueMap() *DashboardValueMap {
return &DashboardValueMap{
Type: "value",
Type: DashboardMappingTypeValue,
}
}
// Supported value mapping types
// `value`: Maps text values to a color or different display text and color. For example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.
// `range`: Maps numerical ranges to a display text and color. For example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.
// `regex`: Maps regular expressions to replacement text and a color. For example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.
// `special`: Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color. See SpecialValueMatch to see the list of special values. For example, you can configure a special value mapping so that null values appear as N/A.
// +k8s:openapi-gen=true
type DashboardMappingType string
const (
DashboardMappingTypeValue DashboardMappingType = "value"
DashboardMappingTypeRange DashboardMappingType = "range"
DashboardMappingTypeRegex DashboardMappingType = "regex"
DashboardMappingTypeSpecial DashboardMappingType = "special"
)
// Result used as replacement with text and color when the value matches
// +k8s:openapi-gen=true
type DashboardValueMappingResult struct {
@ -444,10 +456,7 @@ func NewDashboardValueMappingResult() *DashboardValueMappingResult {
// For example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.
// +k8s:openapi-gen=true
type DashboardRangeMap struct {
// TODO (@radiohead): Something broke in cog / app SDK codegen
// And this is no longer producing valid TS / Go output
// type: MappingType & "range"
Type string `json:"type"`
Type DashboardMappingType `json:"type"`
// Range to match against and the result to apply when the value is within the range
Options DashboardV2alpha1RangeMapOptions `json:"options"`
}
@ -455,7 +464,7 @@ type DashboardRangeMap struct {
// NewDashboardRangeMap creates a new DashboardRangeMap object.
func NewDashboardRangeMap() *DashboardRangeMap {
return &DashboardRangeMap{
Type: "range",
Type: DashboardMappingTypeRange,
Options: *NewDashboardV2alpha1RangeMapOptions(),
}
}
@ -464,10 +473,7 @@ func NewDashboardRangeMap() *DashboardRangeMap {
// For example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.
// +k8s:openapi-gen=true
type DashboardRegexMap struct {
// TODO (@radiohead): Something broke in cog / app SDK codegen
// And this is no longer producing valid TS / Go output
// type: MappingType & "regex"
Type string `json:"type"`
Type DashboardMappingType `json:"type"`
// Regular expression to match against and the result to apply when the value matches the regex
Options DashboardV2alpha1RegexMapOptions `json:"options"`
}
@ -475,7 +481,7 @@ type DashboardRegexMap struct {
// NewDashboardRegexMap creates a new DashboardRegexMap object.
func NewDashboardRegexMap() *DashboardRegexMap {
return &DashboardRegexMap{
Type: "regex",
Type: DashboardMappingTypeRegex,
Options: *NewDashboardV2alpha1RegexMapOptions(),
}
}
@ -485,17 +491,14 @@ func NewDashboardRegexMap() *DashboardRegexMap {
// For example, you can configure a special value mapping so that null values appear as N/A.
// +k8s:openapi-gen=true
type DashboardSpecialValueMap struct {
// TODO (@radiohead): Something broke in cog / app SDK codegen
// And this is no longer producing valid TS / Go output
// type: MappingType & "special"
Type string `json:"type"`
Type DashboardMappingType `json:"type"`
Options DashboardV2alpha1SpecialValueMapOptions `json:"options"`
}
// NewDashboardSpecialValueMap creates a new DashboardSpecialValueMap object.
func NewDashboardSpecialValueMap() *DashboardSpecialValueMap {
return &DashboardSpecialValueMap{
Type: "special",
Type: DashboardMappingTypeSpecial,
Options: *NewDashboardV2alpha1SpecialValueMapOptions(),
}
}
@ -1820,8 +1823,7 @@ func (resource DashboardPanelKindOrLibraryPanelKind) MarshalJSON() ([]byte, erro
if resource.LibraryPanelKind != nil {
return json.Marshal(resource.LibraryPanelKind)
}
return nil, fmt.Errorf("no value for disjunction of refs")
return []byte("null"), nil
}
// UnmarshalJSON implements a custom JSON unmarshalling logic to decode `DashboardPanelKindOrLibraryPanelKind` from JSON.
@ -1890,8 +1892,7 @@ func (resource DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap) MarshalJS
if resource.SpecialValueMap != nil {
return json.Marshal(resource.SpecialValueMap)
}
return nil, fmt.Errorf("no value for disjunction of refs")
return []byte("null"), nil
}
// UnmarshalJSON implements a custom JSON unmarshalling logic to decode `DashboardValueMapOrRangeMapOrRegexMapOrSpecialValueMap` from JSON.
@ -1968,8 +1969,7 @@ func (resource DashboardGridLayoutItemKindOrGridLayoutRowKind) MarshalJSON() ([]
if resource.GridLayoutRowKind != nil {
return json.Marshal(resource.GridLayoutRowKind)
}
return nil, fmt.Errorf("no value for disjunction of refs")
return []byte("null"), nil
}
// UnmarshalJSON implements a custom JSON unmarshalling logic to decode `DashboardGridLayoutItemKindOrGridLayoutRowKind` from JSON.
@ -2034,8 +2034,7 @@ func (resource DashboardGridLayoutKindOrResponsiveGridLayoutKindOrTabsLayoutKind
if resource.TabsLayoutKind != nil {
return json.Marshal(resource.TabsLayoutKind)
}
return nil, fmt.Errorf("no value for disjunction of refs")
return []byte("null"), nil
}
// UnmarshalJSON implements a custom JSON unmarshalling logic to decode `DashboardGridLayoutKindOrResponsiveGridLayoutKindOrTabsLayoutKind` from JSON.
@ -2108,8 +2107,7 @@ func (resource DashboardConditionalRenderingVariableKindOrConditionalRenderingDa
if resource.ConditionalRenderingTimeIntervalKind != nil {
return json.Marshal(resource.ConditionalRenderingTimeIntervalKind)
}
return nil, fmt.Errorf("no value for disjunction of refs")
return []byte("null"), nil
}
// UnmarshalJSON implements a custom JSON unmarshalling logic to decode `DashboardConditionalRenderingVariableKindOrConditionalRenderingDataKindOrConditionalRenderingTimeIntervalKind` from JSON.
@ -2182,8 +2180,7 @@ func (resource DashboardGridLayoutKindOrRowsLayoutKindOrResponsiveGridLayoutKind
if resource.ResponsiveGridLayoutKind != nil {
return json.Marshal(resource.ResponsiveGridLayoutKind)
}
return nil, fmt.Errorf("no value for disjunction of refs")
return []byte("null"), nil
}
// UnmarshalJSON implements a custom JSON unmarshalling logic to decode `DashboardGridLayoutKindOrRowsLayoutKindOrResponsiveGridLayoutKind` from JSON.
@ -2276,8 +2273,7 @@ func (resource DashboardQueryVariableKindOrTextVariableKindOrConstantVariableKin
if resource.AdhocVariableKind != nil {
return json.Marshal(resource.AdhocVariableKind)
}
return nil, fmt.Errorf("no value for disjunction of refs")
return []byte("null"), nil
}
// UnmarshalJSON implements a custom JSON unmarshalling logic to decode `DashboardQueryVariableKindOrTextVariableKindOrConstantVariableKindOrDatasourceVariableKindOrIntervalVariableKindOrCustomVariableKindOrGroupByVariableKindOrAdhocVariableKind` from JSON.
@ -2388,7 +2384,7 @@ func (resource DashboardStringOrArrayOfString) MarshalJSON() ([]byte, error) {
return json.Marshal(resource.ArrayOfString)
}
return nil, fmt.Errorf("no value for disjunction of scalars")
return []byte("null"), nil
}
// UnmarshalJSON implements a custom JSON unmarshalling logic to decode `DashboardStringOrArrayOfString` from JSON.
@ -2443,7 +2439,7 @@ func (resource DashboardStringOrFloat64) MarshalJSON() ([]byte, error) {
return json.Marshal(resource.Float64)
}
return nil, fmt.Errorf("no value for disjunction of scalars")
return []byte("null"), nil
}
// UnmarshalJSON implements a custom JSON unmarshalling logic to decode `DashboardStringOrFloat64` from JSON.
@ -2504,8 +2500,7 @@ func (resource DashboardGridLayoutKindOrRowsLayoutKindOrResponsiveGridLayoutKind
if resource.TabsLayoutKind != nil {
return json.Marshal(resource.TabsLayoutKind)
}
return nil, fmt.Errorf("no value for disjunction of refs")
return []byte("null"), nil
}
// UnmarshalJSON implements a custom JSON unmarshalling logic to decode `DashboardGridLayoutKindOrRowsLayoutKindOrResponsiveGridLayoutKindOrTabsLayoutKind` from JSON.

View File

@ -3237,10 +3237,9 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardRangeMap(ref common.ReferenceCa
Properties: map[string]spec.Schema{
"type": {
SchemaProps: spec.SchemaProps{
Description: "And this is no longer producing valid TS / Go output type: MappingType & \"range\"",
Default: "",
Type: []string{"string"},
Format: "",
Default: "",
Type: []string{"string"},
Format: "",
},
},
"options": {
@ -3268,10 +3267,9 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardRegexMap(ref common.ReferenceCa
Properties: map[string]spec.Schema{
"type": {
SchemaProps: spec.SchemaProps{
Description: "And this is no longer producing valid TS / Go output type: MappingType & \"regex\"",
Default: "",
Type: []string{"string"},
Format: "",
Default: "",
Type: []string{"string"},
Format: "",
},
},
"options": {
@ -3795,10 +3793,9 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardSpecialValueMap(ref common.Refe
Properties: map[string]spec.Schema{
"type": {
SchemaProps: spec.SchemaProps{
Description: "And this is no longer producing valid TS / Go output type: MappingType & \"special\"",
Default: "",
Type: []string{"string"},
Format: "",
Default: "",
Type: []string{"string"},
Format: "",
},
},
"options": {
@ -4463,10 +4460,9 @@ func schema_pkg_apis_dashboard_v2alpha1_DashboardValueMap(ref common.ReferenceCa
Properties: map[string]spec.Schema{
"type": {
SchemaProps: spec.SchemaProps{
Description: "And this is no longer producing valid TS / Go output type: MappingType & \"value\"",
Default: "",
Type: []string{"string"},
Format: "",
Default: "",
Type: []string{"string"},
Format: "",
},
},
"options": {

View File

@ -333,10 +333,7 @@ export const defaultValueMapping = (): ValueMapping => (defaultValueMap());
// Maps text values to a color or different display text and color.
// For example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.
export interface ValueMap {
// TODO (@radiohead): Something broke in cog / app SDK codegen
// And this is no longer producing valid TS / Go output
// type: MappingType & "value"
type: "value";
type: MappingType & "value";
// Map with <value_to_match>: ValueMappingResult. For example: { "10": { text: "Perfection!", color: "green" } }
options: Record<string, ValueMappingResult>;
}
@ -346,6 +343,15 @@ export const defaultValueMap = (): ValueMap => ({
options: {},
});
// Supported value mapping types
// `value`: Maps text values to a color or different display text and color. For example, you can configure a value mapping so that all instances of the value 10 appear as Perfection! rather than the number.
// `range`: Maps numerical ranges to a display text and color. For example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.
// `regex`: Maps regular expressions to replacement text and a color. For example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.
// `special`: Maps special values like Null, NaN (not a number), and boolean values like true and false to a display text and color. See SpecialValueMatch to see the list of special values. For example, you can configure a special value mapping so that null values appear as N/A.
export type MappingType = "value" | "range" | "regex" | "special";
export const defaultMappingType = (): MappingType => ("value");
// Result used as replacement with text and color when the value matches
export interface ValueMappingResult {
// Text to display when the value matches
@ -364,10 +370,7 @@ export const defaultValueMappingResult = (): ValueMappingResult => ({
// Maps numerical ranges to a display text and color.
// For example, if a value is within a certain range, you can configure a range value mapping to display Low or High rather than the number.
export interface RangeMap {
// TODO (@radiohead): Something broke in cog / app SDK codegen
// And this is no longer producing valid TS / Go output
// type: MappingType & "range"
type: "range";
type: MappingType & "range";
// Range to match against and the result to apply when the value is within the range
options: {
// Min value of the range. It can be null which means -Infinity
@ -391,10 +394,7 @@ export const defaultRangeMap = (): RangeMap => ({
// Maps regular expressions to replacement text and a color.
// For example, if a value is www.example.com, you can configure a regex value mapping so that Grafana displays www and truncates the domain.
export interface RegexMap {
// TODO (@radiohead): Something broke in cog / app SDK codegen
// And this is no longer producing valid TS / Go output
// type: MappingType & "regex"
type: "regex";
type: MappingType & "regex";
// Regular expression to match against and the result to apply when the value matches the regex
options: {
// Regular expression to match against
@ -416,10 +416,7 @@ export const defaultRegexMap = (): RegexMap => ({
// See SpecialValueMatch to see the list of special values.
// For example, you can configure a special value mapping so that null values appear as N/A.
export interface SpecialValueMap {
// TODO (@radiohead): Something broke in cog / app SDK codegen
// And this is no longer producing valid TS / Go output
// type: MappingType & "special"
type: "special";
type: MappingType & "special";
options: {
// Special value to match against
match: SpecialValueMatch;