From 3d4cb37cbfe79625192392605bad18594131fc84 Mon Sep 17 00:00:00 2001 From: justinsb Date: Tue, 21 May 2024 11:49:56 -0400 Subject: [PATCH] chore: create generated mappers and roundtrip test for Dashboard This allows us to see unsupported fields. --- go.mod | 1 + go.sum | 2 + .../dashboard_generated.mappings.go | 949 ++++++++++++++++++ .../direct/monitoring/dashboard_mappings.go | 139 +++ pkg/controller/direct/monitoring/maputils.go | 188 ++++ .../direct/monitoring/roundtrip_test.go | 419 ++++++++ pkg/controller/direct/monitoring/utils.go | 27 + 7 files changed, 1725 insertions(+) create mode 100644 pkg/controller/direct/monitoring/dashboard_generated.mappings.go create mode 100644 pkg/controller/direct/monitoring/dashboard_mappings.go create mode 100644 pkg/controller/direct/monitoring/maputils.go create mode 100644 pkg/controller/direct/monitoring/roundtrip_test.go create mode 100644 pkg/controller/direct/monitoring/utils.go diff --git a/go.mod b/go.mod index 4b7ee91319..9c5ed0ca34 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ replace github.com/GoogleCloudPlatform/k8s-config-connector/mockgcp => ./mockgcp require ( cloud.google.com/go/apikeys v1.1.5 + cloud.google.com/go/monitoring v1.19.0 cloud.google.com/go/profiler v0.1.0 cloud.google.com/go/resourcemanager v1.9.7 contrib.go.opencensus.io/exporter/prometheus v0.1.0 diff --git a/go.sum b/go.sum index 3e58574cd7..de17257369 100644 --- a/go.sum +++ b/go.sum @@ -52,6 +52,8 @@ cloud.google.com/go/iam v1.1.7 h1:z4VHOhwKLF/+UYXAJDFwGtNF0b6gjsW1Pk9Ml0U/IoM= cloud.google.com/go/iam v1.1.7/go.mod h1:J4PMPg8TtyurAUvSmPj8FF3EDgY1SPRZxcUGrn7WXGA= cloud.google.com/go/longrunning v0.5.6 h1:xAe8+0YaWoCKr9t1+aWe+OeQgN/iJK1fEgZSXmjuEaE= cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA= +cloud.google.com/go/monitoring v1.19.0 h1:NCXf8hfQi+Kmr56QJezXRZ6GPb80ZI7El1XztyUuLQI= +cloud.google.com/go/monitoring v1.19.0/go.mod h1:25IeMR5cQ5BoZ8j1eogHE5VPJLlReQ7zFp5OiLgiGZw= cloud.google.com/go/profiler v0.1.0 h1:MG/rxKC1MztRfEWMGYKFISxyZak5hNh29f0A/z2tvWk= cloud.google.com/go/profiler v0.1.0/go.mod h1:D7S7LV/zKbRWkOzYL1b5xytpqt8Ikd/v/yvf1/Tx2pQ= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= diff --git a/pkg/controller/direct/monitoring/dashboard_generated.mappings.go b/pkg/controller/direct/monitoring/dashboard_generated.mappings.go new file mode 100644 index 0000000000..d12fa0d4ad --- /dev/null +++ b/pkg/controller/direct/monitoring/dashboard_generated.mappings.go @@ -0,0 +1,949 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package monitoring + +import ( + pb "cloud.google.com/go/monitoring/dashboard/apiv1/dashboardpb" + + krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/monitoring/v1beta1" +) + +func Aggregation_FromProto(mapCtx *MapContext, in *pb.Aggregation) *krm.Aggregation { + if in == nil { + return nil + } + out := &krm.Aggregation{} + out.AlignmentPeriod = Aggregation_AlignmentPeriod_FromProto(mapCtx, in.GetAlignmentPeriod()) + out.PerSeriesAligner = Enum_FromProto(mapCtx, in.PerSeriesAligner) + out.CrossSeriesReducer = Enum_FromProto(mapCtx, in.CrossSeriesReducer) + out.GroupByFields = in.GroupByFields + return out +} +func Aggregation_ToProto(mapCtx *MapContext, in *krm.Aggregation) *pb.Aggregation { + if in == nil { + return nil + } + out := &pb.Aggregation{} + out.AlignmentPeriod = Aggregation_AlignmentPeriod_ToProto(mapCtx, in.AlignmentPeriod) + out.PerSeriesAligner = Enum_ToProto[pb.Aggregation_Aligner](mapCtx, in.PerSeriesAligner) + out.CrossSeriesReducer = Enum_ToProto[pb.Aggregation_Reducer](mapCtx, in.CrossSeriesReducer) + out.GroupByFields = in.GroupByFields + return out +} +func AlertChart_FromProto(mapCtx *MapContext, in *pb.AlertChart) *krm.AlertChart { + if in == nil { + return nil + } + out := &krm.AlertChart{} + out.Name = LazyPtr(in.GetName()) + return out +} +func AlertChart_ToProto(mapCtx *MapContext, in *krm.AlertChart) *pb.AlertChart { + if in == nil { + return nil + } + out := &pb.AlertChart{} + out.Name = ValueOf(in.Name) + return out +} +func ChartOptions_FromProto(mapCtx *MapContext, in *pb.ChartOptions) *krm.ChartOptions { + if in == nil { + return nil + } + out := &krm.ChartOptions{} + out.Mode = Enum_FromProto(mapCtx, in.Mode) + return out +} +func ChartOptions_ToProto(mapCtx *MapContext, in *krm.ChartOptions) *pb.ChartOptions { + if in == nil { + return nil + } + out := &pb.ChartOptions{} + out.Mode = Enum_ToProto[pb.ChartOptions_Mode](mapCtx, in.Mode) + return out +} +func CollapsibleGroup_FromProto(mapCtx *MapContext, in *pb.CollapsibleGroup) *krm.CollapsibleGroup { + if in == nil { + return nil + } + out := &krm.CollapsibleGroup{} + out.Collapsed = LazyPtr(in.GetCollapsed()) + return out +} +func CollapsibleGroup_ToProto(mapCtx *MapContext, in *krm.CollapsibleGroup) *pb.CollapsibleGroup { + if in == nil { + return nil + } + out := &pb.CollapsibleGroup{} + out.Collapsed = ValueOf(in.Collapsed) + return out +} +func ColumnLayout_FromProto(mapCtx *MapContext, in *pb.ColumnLayout) *krm.ColumnLayout { + if in == nil { + return nil + } + out := &krm.ColumnLayout{} + out.Columns = Slice_FromProto(mapCtx, in.Columns, ColumnLayout_Column_FromProto) + return out +} +func ColumnLayout_ToProto(mapCtx *MapContext, in *krm.ColumnLayout) *pb.ColumnLayout { + if in == nil { + return nil + } + out := &pb.ColumnLayout{} + out.Columns = Slice_ToProto(mapCtx, in.Columns, ColumnLayout_Column_ToProto) + return out +} +func ColumnLayout_Column_FromProto(mapCtx *MapContext, in *pb.ColumnLayout_Column) *krm.ColumnLayout_Column { + if in == nil { + return nil + } + out := &krm.ColumnLayout_Column{} + out.Weight = LazyPtr(in.GetWeight()) + out.Widgets = Slice_FromProto(mapCtx, in.Widgets, Widget_FromProto) + return out +} +func ColumnLayout_Column_ToProto(mapCtx *MapContext, in *krm.ColumnLayout_Column) *pb.ColumnLayout_Column { + if in == nil { + return nil + } + out := &pb.ColumnLayout_Column{} + out.Weight = ValueOf(in.Weight) + out.Widgets = Slice_ToProto(mapCtx, in.Widgets, Widget_ToProto) + return out +} + +// func DashboardFilter_FromProto(mapCtx *MapContext, in *pb.DashboardFilter) *krm.DashboardFilter { +// if in == nil { +// return nil +// } +// out := &krm.DashboardFilter{} +// out.LabelKey = LazyPtr(in.GetLabelKey()) +// out.TemplateVariable = LazyPtr(in.GetTemplateVariable()) +// out.StringValue = LazyPtr(in.GetStringValue()) +// out.FilterType = Enum_FromProto(mapCtx, in.FilterType) +// return out +// } +// func DashboardFilter_ToProto(mapCtx *MapContext, in *krm.DashboardFilter) *pb.DashboardFilter { +// if in == nil { +// return nil +// } +// out := &pb.DashboardFilter{} +// out.LabelKey = ValueOf(in.LabelKey) +// out.TemplateVariable = ValueOf(in.TemplateVariable) +// if oneof := DashboardFilter_StringValue_ToProto(mapCtx, in.StringValue); oneof != nil { +// out.DefaultValue = oneof +// } +// out.FilterType = Enum_ToProto[pb.DashboardFilter_FilterType](mapCtx, in.FilterType) +// return out +// } + +// func Dashboard_LabelsEntry_FromProto(mapCtx *MapContext, in *pb.Dashboard_LabelsEntry) *krm.Dashboard_LabelsEntry { +// if in == nil { +// return nil +// } +// out := &krm.Dashboard_LabelsEntry{} +// out.Key = LazyPtr(in.GetKey()) +// out.Value = LazyPtr(in.GetValue()) +// return out +// } +// +// func Dashboard_LabelsEntry_ToProto(mapCtx *MapContext, in *krm.Dashboard_LabelsEntry) *pb.Dashboard_LabelsEntry { +// if in == nil { +// return nil +// } +// out := &pb.Dashboard_LabelsEntry{} +// out.Key = ValueOf(in.Key) +// out.Value = ValueOf(in.Value) +// return out +// } +func ErrorReportingPanel_FromProto(mapCtx *MapContext, in *pb.ErrorReportingPanel) *krm.ErrorReportingPanel { + if in == nil { + return nil + } + out := &krm.ErrorReportingPanel{} + out.ProjectNames = in.ProjectNames + out.Services = in.Services + out.Versions = in.Versions + return out +} +func ErrorReportingPanel_ToProto(mapCtx *MapContext, in *krm.ErrorReportingPanel) *pb.ErrorReportingPanel { + if in == nil { + return nil + } + out := &pb.ErrorReportingPanel{} + out.ProjectNames = in.ProjectNames + out.Services = in.Services + out.Versions = in.Versions + return out +} +func GridLayout_FromProto(mapCtx *MapContext, in *pb.GridLayout) *krm.GridLayout { + if in == nil { + return nil + } + out := &krm.GridLayout{} + out.Columns = LazyPtr(in.GetColumns()) + out.Widgets = Slice_FromProto(mapCtx, in.Widgets, Widget_FromProto) + return out +} +func GridLayout_ToProto(mapCtx *MapContext, in *krm.GridLayout) *pb.GridLayout { + if in == nil { + return nil + } + out := &pb.GridLayout{} + out.Columns = ValueOf(in.Columns) + out.Widgets = Slice_ToProto(mapCtx, in.Widgets, Widget_ToProto) + return out +} + +// func IncidentList_FromProto(mapCtx *MapContext, in *pb.IncidentList) *krm.IncidentList { +// if in == nil { +// return nil +// } +// out := &krm.IncidentList{} +// out.MonitoredResources = Slice_FromProto(mapCtx, in.MonitoredResources, string_FromProto) +// out.PolicyNames = in.PolicyNames +// return out +// } +// +// func IncidentList_ToProto(mapCtx *MapContext, in *krm.IncidentList) *pb.IncidentList { +// if in == nil { +// return nil +// } +// out := &pb.IncidentList{} +// out.MonitoredResources = Slice_ToProto(mapCtx, in.MonitoredResources, string_ToProto) +// out.PolicyNames = in.PolicyNames +// return out +// } +func LogsPanel_FromProto(mapCtx *MapContext, in *pb.LogsPanel) *krm.LogsPanel { + if in == nil { + return nil + } + out := &krm.LogsPanel{} + out.Filter = LazyPtr(in.GetFilter()) + out.ResourceNames = LogsPanel_ResourceNames_FromProto(mapCtx, in.ResourceNames) + return out +} + +func LogsPanel_ToProto(mapCtx *MapContext, in *krm.LogsPanel) *pb.LogsPanel { + if in == nil { + return nil + } + out := &pb.LogsPanel{} + out.Filter = ValueOf(in.Filter) + out.ResourceNames = LogsPanel_ResourceNames_ToProto(mapCtx, in.ResourceNames) + return out +} +func MonitoringDashboardSpec_FromProto(mapCtx *MapContext, in *pb.Dashboard) *krm.MonitoringDashboardSpec { + if in == nil { + return nil + } + out := &krm.MonitoringDashboardSpec{} + // MISSING: Name + out.DisplayName = LazyPtr(in.GetDisplayName()) + // MISSING: Etag + out.GridLayout = GridLayout_FromProto(mapCtx, in.GetGridLayout()) + out.MosaicLayout = MosaicLayout_FromProto(mapCtx, in.GetMosaicLayout()) + out.RowLayout = RowLayout_FromProto(mapCtx, in.GetRowLayout()) + out.ColumnLayout = ColumnLayout_FromProto(mapCtx, in.GetColumnLayout()) + // MISSING: DashboardFilters + // MISSING: Labels + return out +} +func MonitoringDashboardSpec_ToProto(mapCtx *MapContext, in *krm.MonitoringDashboardSpec) *pb.Dashboard { + if in == nil { + return nil + } + out := &pb.Dashboard{} + // MISSING: Name + out.DisplayName = ValueOf(in.DisplayName) + // MISSING: Etag + if oneof := GridLayout_ToProto(mapCtx, in.GridLayout); oneof != nil { + out.Layout = &pb.Dashboard_GridLayout{GridLayout: oneof} + } + if oneof := MosaicLayout_ToProto(mapCtx, in.MosaicLayout); oneof != nil { + out.Layout = &pb.Dashboard_MosaicLayout{MosaicLayout: oneof} + } + if oneof := RowLayout_ToProto(mapCtx, in.RowLayout); oneof != nil { + out.Layout = &pb.Dashboard_RowLayout{RowLayout: oneof} + } + if oneof := ColumnLayout_ToProto(mapCtx, in.ColumnLayout); oneof != nil { + out.Layout = &pb.Dashboard_ColumnLayout{ColumnLayout: oneof} + } + // MISSING: DashboardFilters + // MISSING: Labels + return out +} +func MonitoringDashboardStatus_FromProto(mapCtx *MapContext, in *pb.Dashboard) *krm.MonitoringDashboardStatus { + if in == nil { + return nil + } + out := &krm.MonitoringDashboardStatus{} + // MISSING: Name + // MISSING: DisplayName + out.Etag = LazyPtr(in.GetEtag()) + // MISSING: GridLayout + // MISSING: MosaicLayout + // MISSING: RowLayout + // MISSING: ColumnLayout + // MISSING: DashboardFilters + // MISSING: Labels + return out +} +func MonitoringDashboardStatus_ToProto(mapCtx *MapContext, in *krm.MonitoringDashboardStatus) *pb.Dashboard { + if in == nil { + return nil + } + out := &pb.Dashboard{} + // MISSING: Name + // MISSING: DisplayName + out.Etag = ValueOf(in.Etag) + // MISSING: GridLayout + // MISSING: MosaicLayout + // MISSING: RowLayout + // MISSING: ColumnLayout + // MISSING: DashboardFilters + // MISSING: Labels + return out +} +func MosaicLayout_FromProto(mapCtx *MapContext, in *pb.MosaicLayout) *krm.MosaicLayout { + if in == nil { + return nil + } + out := &krm.MosaicLayout{} + out.Columns = LazyPtr(in.GetColumns()) + out.Tiles = Slice_FromProto(mapCtx, in.Tiles, MosaicLayout_Tile_FromProto) + return out +} +func MosaicLayout_ToProto(mapCtx *MapContext, in *krm.MosaicLayout) *pb.MosaicLayout { + if in == nil { + return nil + } + out := &pb.MosaicLayout{} + out.Columns = ValueOf(in.Columns) + out.Tiles = Slice_ToProto(mapCtx, in.Tiles, MosaicLayout_Tile_ToProto) + return out +} +func MosaicLayout_Tile_FromProto(mapCtx *MapContext, in *pb.MosaicLayout_Tile) *krm.MosaicLayout_Tile { + if in == nil { + return nil + } + out := &krm.MosaicLayout_Tile{} + out.XPos = LazyPtr(in.GetXPos()) + out.YPos = LazyPtr(in.GetYPos()) + out.Width = LazyPtr(in.GetWidth()) + out.Height = LazyPtr(in.GetHeight()) + out.Widget = Widget_FromProto(mapCtx, in.GetWidget()) + return out +} +func MosaicLayout_Tile_ToProto(mapCtx *MapContext, in *krm.MosaicLayout_Tile) *pb.MosaicLayout_Tile { + if in == nil { + return nil + } + out := &pb.MosaicLayout_Tile{} + out.XPos = ValueOf(in.XPos) + out.YPos = ValueOf(in.YPos) + out.Width = ValueOf(in.Width) + out.Height = ValueOf(in.Height) + out.Widget = Widget_ToProto(mapCtx, in.Widget) + return out +} +func PickTimeSeriesFilter_FromProto(mapCtx *MapContext, in *pb.PickTimeSeriesFilter) *krm.PickTimeSeriesFilter { + if in == nil { + return nil + } + out := &krm.PickTimeSeriesFilter{} + out.RankingMethod = Enum_FromProto(mapCtx, in.RankingMethod) + out.NumTimeSeries = LazyPtr(in.GetNumTimeSeries()) + out.Direction = Enum_FromProto(mapCtx, in.Direction) + // MISSING: Interval + return out +} +func PickTimeSeriesFilter_ToProto(mapCtx *MapContext, in *krm.PickTimeSeriesFilter) *pb.PickTimeSeriesFilter { + if in == nil { + return nil + } + out := &pb.PickTimeSeriesFilter{} + out.RankingMethod = Enum_ToProto[pb.PickTimeSeriesFilter_Method](mapCtx, in.RankingMethod) + out.NumTimeSeries = ValueOf(in.NumTimeSeries) + out.Direction = Enum_ToProto[pb.PickTimeSeriesFilter_Direction](mapCtx, in.Direction) + // MISSING: Interval + return out +} + +// func PieChart_FromProto(mapCtx *MapContext, in *pb.PieChart) *krm.PieChart { +// if in == nil { +// return nil +// } +// out := &krm.PieChart{} +// out.DataSets = Slice_FromProto(mapCtx, in.DataSets, PieChart_PieChartDataSet_FromProto) +// out.ChartType = Enum_FromProto(mapCtx, in.ChartType) +// out.ShowLabels = LazyPtr(in.GetShowLabels()) +// return out +// } +// func PieChart_ToProto(mapCtx *MapContext, in *krm.PieChart) *pb.PieChart { +// if in == nil { +// return nil +// } +// out := &pb.PieChart{} +// out.DataSets = Slice_ToProto(mapCtx, in.DataSets, PieChart_PieChartDataSet_ToProto) +// out.ChartType = Enum_ToProto[pb.PieChart_PieChartType](mapCtx, in.ChartType) +// out.ShowLabels = ValueOf(in.ShowLabels) +// return out +// } + +// func PieChart_PieChartDataSet_FromProto(mapCtx *MapContext, in *pb.PieChart_PieChartDataSet) *krm.PieChart_PieChartDataSet { +// if in == nil { +// return nil +// } +// out := &krm.PieChart_PieChartDataSet{} +// out.TimeSeriesQuery = TimeSeriesQuery_FromProto(mapCtx, in.GetTimeSeriesQuery()) +// out.SliceNameTemplate = LazyPtr(in.GetSliceNameTemplate()) +// out.MinAlignmentPeriod = PieChartDataSet_MinAlignmentPeriod_FromProto(mapCtx, in.GetMinAlignmentPeriod()) +// return out +// } +// +// func PieChart_PieChartDataSet_ToProto(mapCtx *MapContext, in *krm.PieChart_PieChartDataSet) *pb.PieChart_PieChartDataSet { +// if in == nil { +// return nil +// } +// out := &pb.PieChart_PieChartDataSet{} +// out.TimeSeriesQuery = TimeSeriesQuery_ToProto(mapCtx, in.TimeSeriesQuery) +// out.SliceNameTemplate = ValueOf(in.SliceNameTemplate) +// out.MinAlignmentPeriod = PieChartDataSet_MinAlignmentPeriod_ToProto(mapCtx, in.MinAlignmentPeriod) +// return out +// } +func RowLayout_FromProto(mapCtx *MapContext, in *pb.RowLayout) *krm.RowLayout { + if in == nil { + return nil + } + out := &krm.RowLayout{} + out.Rows = Slice_FromProto(mapCtx, in.Rows, RowLayout_Row_FromProto) + return out +} +func RowLayout_ToProto(mapCtx *MapContext, in *krm.RowLayout) *pb.RowLayout { + if in == nil { + return nil + } + out := &pb.RowLayout{} + out.Rows = Slice_ToProto(mapCtx, in.Rows, RowLayout_Row_ToProto) + return out +} +func RowLayout_Row_FromProto(mapCtx *MapContext, in *pb.RowLayout_Row) *krm.RowLayout_Row { + if in == nil { + return nil + } + out := &krm.RowLayout_Row{} + out.Weight = LazyPtr(in.GetWeight()) + out.Widgets = Slice_FromProto(mapCtx, in.Widgets, Widget_FromProto) + return out +} +func RowLayout_Row_ToProto(mapCtx *MapContext, in *krm.RowLayout_Row) *pb.RowLayout_Row { + if in == nil { + return nil + } + out := &pb.RowLayout_Row{} + out.Weight = ValueOf(in.Weight) + out.Widgets = Slice_ToProto(mapCtx, in.Widgets, Widget_ToProto) + return out +} +func Scorecard_FromProto(mapCtx *MapContext, in *pb.Scorecard) *krm.Scorecard { + if in == nil { + return nil + } + out := &krm.Scorecard{} + out.TimeSeriesQuery = TimeSeriesQuery_FromProto(mapCtx, in.GetTimeSeriesQuery()) + out.GaugeView = Scorecard_GaugeView_FromProto(mapCtx, in.GetGaugeView()) + out.SparkChartView = Scorecard_SparkChartView_FromProto(mapCtx, in.GetSparkChartView()) + // MISSING: BlankView + out.Thresholds = Slice_FromProto(mapCtx, in.Thresholds, Threshold_FromProto) + return out +} +func Scorecard_ToProto(mapCtx *MapContext, in *krm.Scorecard) *pb.Scorecard { + if in == nil { + return nil + } + out := &pb.Scorecard{} + out.TimeSeriesQuery = TimeSeriesQuery_ToProto(mapCtx, in.TimeSeriesQuery) + if oneof := Scorecard_GaugeView_ToProto(mapCtx, in.GaugeView); oneof != nil { + out.DataView = &pb.Scorecard_GaugeView_{GaugeView: oneof} + } + if oneof := Scorecard_SparkChartView_ToProto(mapCtx, in.SparkChartView); oneof != nil { + out.DataView = &pb.Scorecard_SparkChartView_{SparkChartView: oneof} + } + // MISSING: BlankView + out.Thresholds = Slice_ToProto(mapCtx, in.Thresholds, Threshold_ToProto) + return out +} +func Scorecard_GaugeView_FromProto(mapCtx *MapContext, in *pb.Scorecard_GaugeView) *krm.Scorecard_GaugeView { + if in == nil { + return nil + } + out := &krm.Scorecard_GaugeView{} + out.LowerBound = LazyPtr(in.GetLowerBound()) + out.UpperBound = LazyPtr(in.GetUpperBound()) + return out +} +func Scorecard_GaugeView_ToProto(mapCtx *MapContext, in *krm.Scorecard_GaugeView) *pb.Scorecard_GaugeView { + if in == nil { + return nil + } + out := &pb.Scorecard_GaugeView{} + out.LowerBound = ValueOf(in.LowerBound) + out.UpperBound = ValueOf(in.UpperBound) + return out +} +func Scorecard_SparkChartView_FromProto(mapCtx *MapContext, in *pb.Scorecard_SparkChartView) *krm.Scorecard_SparkChartView { + if in == nil { + return nil + } + out := &krm.Scorecard_SparkChartView{} + out.SparkChartType = Enum_FromProto(mapCtx, in.SparkChartType) + out.MinAlignmentPeriod = SparkChartView_MinAlignmentPeriod_FromProto(mapCtx, in.GetMinAlignmentPeriod()) + return out +} +func Scorecard_SparkChartView_ToProto(mapCtx *MapContext, in *krm.Scorecard_SparkChartView) *pb.Scorecard_SparkChartView { + if in == nil { + return nil + } + out := &pb.Scorecard_SparkChartView{} + out.SparkChartType = Enum_ToProto[pb.SparkChartType](mapCtx, in.SparkChartType) + out.MinAlignmentPeriod = SparkChartView_MinAlignmentPeriod_ToProto(mapCtx, in.MinAlignmentPeriod) + return out +} +func SectionHeader_FromProto(mapCtx *MapContext, in *pb.SectionHeader) *krm.SectionHeader { + if in == nil { + return nil + } + out := &krm.SectionHeader{} + out.Subtitle = LazyPtr(in.GetSubtitle()) + out.DividerBelow = LazyPtr(in.GetDividerBelow()) + return out +} +func SectionHeader_ToProto(mapCtx *MapContext, in *krm.SectionHeader) *pb.SectionHeader { + if in == nil { + return nil + } + out := &pb.SectionHeader{} + out.Subtitle = ValueOf(in.Subtitle) + out.DividerBelow = ValueOf(in.DividerBelow) + return out +} +func SingleViewGroup_FromProto(mapCtx *MapContext, in *pb.SingleViewGroup) *krm.SingleViewGroup { + if in == nil { + return nil + } + out := &krm.SingleViewGroup{} + return out +} +func SingleViewGroup_ToProto(mapCtx *MapContext, in *krm.SingleViewGroup) *pb.SingleViewGroup { + if in == nil { + return nil + } + out := &pb.SingleViewGroup{} + return out +} +func StatisticalTimeSeriesFilter_FromProto(mapCtx *MapContext, in *pb.StatisticalTimeSeriesFilter) *krm.StatisticalTimeSeriesFilter { + if in == nil { + return nil + } + out := &krm.StatisticalTimeSeriesFilter{} + out.RankingMethod = Enum_FromProto(mapCtx, in.RankingMethod) + out.NumTimeSeries = LazyPtr(in.GetNumTimeSeries()) + return out +} +func StatisticalTimeSeriesFilter_ToProto(mapCtx *MapContext, in *krm.StatisticalTimeSeriesFilter) *pb.StatisticalTimeSeriesFilter { + if in == nil { + return nil + } + out := &pb.StatisticalTimeSeriesFilter{} + out.RankingMethod = Enum_ToProto[pb.StatisticalTimeSeriesFilter_Method](mapCtx, in.RankingMethod) + out.NumTimeSeries = ValueOf(in.NumTimeSeries) + return out +} +func TableDisplayOptions_FromProto(mapCtx *MapContext, in *pb.TableDisplayOptions) *krm.TableDisplayOptions { + if in == nil { + return nil + } + out := &krm.TableDisplayOptions{} + out.ShownColumns = in.ShownColumns + return out +} +func TableDisplayOptions_ToProto(mapCtx *MapContext, in *krm.TableDisplayOptions) *pb.TableDisplayOptions { + if in == nil { + return nil + } + out := &pb.TableDisplayOptions{} + out.ShownColumns = in.ShownColumns + return out +} +func Text_FromProto(mapCtx *MapContext, in *pb.Text) *krm.Text { + if in == nil { + return nil + } + out := &krm.Text{} + out.Content = LazyPtr(in.GetContent()) + out.Format = Enum_FromProto(mapCtx, in.Format) + // MISSING: Style + return out +} +func Text_ToProto(mapCtx *MapContext, in *krm.Text) *pb.Text { + if in == nil { + return nil + } + out := &pb.Text{} + out.Content = ValueOf(in.Content) + out.Format = Enum_ToProto[pb.Text_Format](mapCtx, in.Format) + // MISSING: Style + return out +} +func Text_TextStyle_FromProto(mapCtx *MapContext, in *pb.Text_TextStyle) *krm.Text_TextStyle { + if in == nil { + return nil + } + out := &krm.Text_TextStyle{} + out.BackgroundColor = LazyPtr(in.GetBackgroundColor()) + out.TextColor = LazyPtr(in.GetTextColor()) + out.HorizontalAlignment = Enum_FromProto(mapCtx, in.HorizontalAlignment) + out.VerticalAlignment = Enum_FromProto(mapCtx, in.VerticalAlignment) + out.Padding = Enum_FromProto(mapCtx, in.Padding) + out.FontSize = Enum_FromProto(mapCtx, in.FontSize) + out.PointerLocation = Enum_FromProto(mapCtx, in.PointerLocation) + return out +} +func Text_TextStyle_ToProto(mapCtx *MapContext, in *krm.Text_TextStyle) *pb.Text_TextStyle { + if in == nil { + return nil + } + out := &pb.Text_TextStyle{} + out.BackgroundColor = ValueOf(in.BackgroundColor) + out.TextColor = ValueOf(in.TextColor) + out.HorizontalAlignment = Enum_ToProto[pb.Text_TextStyle_HorizontalAlignment](mapCtx, in.HorizontalAlignment) + out.VerticalAlignment = Enum_ToProto[pb.Text_TextStyle_VerticalAlignment](mapCtx, in.VerticalAlignment) + out.Padding = Enum_ToProto[pb.Text_TextStyle_PaddingSize](mapCtx, in.Padding) + out.FontSize = Enum_ToProto[pb.Text_TextStyle_FontSize](mapCtx, in.FontSize) + out.PointerLocation = Enum_ToProto[pb.Text_TextStyle_PointerLocation](mapCtx, in.PointerLocation) + return out +} +func Threshold_FromProto(mapCtx *MapContext, in *pb.Threshold) *krm.Threshold { + if in == nil { + return nil + } + out := &krm.Threshold{} + out.Label = LazyPtr(in.GetLabel()) + out.Value = LazyPtr(in.GetValue()) + out.Color = Enum_FromProto(mapCtx, in.Color) + out.Direction = Enum_FromProto(mapCtx, in.Direction) + // MISSING: TargetAxis + return out +} +func Threshold_ToProto(mapCtx *MapContext, in *krm.Threshold) *pb.Threshold { + if in == nil { + return nil + } + out := &pb.Threshold{} + out.Label = ValueOf(in.Label) + out.Value = ValueOf(in.Value) + out.Color = Enum_ToProto[pb.Threshold_Color](mapCtx, in.Color) + out.Direction = Enum_ToProto[pb.Threshold_Direction](mapCtx, in.Direction) + // MISSING: TargetAxis + return out +} +func TimeSeriesFilter_FromProto(mapCtx *MapContext, in *pb.TimeSeriesFilter) *krm.TimeSeriesFilter { + if in == nil { + return nil + } + out := &krm.TimeSeriesFilter{} + out.Filter = LazyPtr(in.GetFilter()) + out.Aggregation = Aggregation_FromProto(mapCtx, in.GetAggregation()) + out.SecondaryAggregation = Aggregation_FromProto(mapCtx, in.GetSecondaryAggregation()) + out.PickTimeSeriesFilter = PickTimeSeriesFilter_FromProto(mapCtx, in.GetPickTimeSeriesFilter()) + // MISSING: StatisticalTimeSeriesFilter + return out +} +func TimeSeriesFilter_ToProto(mapCtx *MapContext, in *krm.TimeSeriesFilter) *pb.TimeSeriesFilter { + if in == nil { + return nil + } + out := &pb.TimeSeriesFilter{} + out.Filter = ValueOf(in.Filter) + out.Aggregation = Aggregation_ToProto(mapCtx, in.Aggregation) + out.SecondaryAggregation = Aggregation_ToProto(mapCtx, in.SecondaryAggregation) + if oneof := PickTimeSeriesFilter_ToProto(mapCtx, in.PickTimeSeriesFilter); oneof != nil { + out.OutputFilter = &pb.TimeSeriesFilter_PickTimeSeriesFilter{PickTimeSeriesFilter: oneof} + } + // MISSING: StatisticalTimeSeriesFilter + return out +} +func TimeSeriesFilterRatio_FromProto(mapCtx *MapContext, in *pb.TimeSeriesFilterRatio) *krm.TimeSeriesFilterRatio { + if in == nil { + return nil + } + out := &krm.TimeSeriesFilterRatio{} + out.Numerator = TimeSeriesFilterRatio_RatioPart_FromProto(mapCtx, in.GetNumerator()) + out.Denominator = TimeSeriesFilterRatio_RatioPart_FromProto(mapCtx, in.GetDenominator()) + out.SecondaryAggregation = Aggregation_FromProto(mapCtx, in.GetSecondaryAggregation()) + out.PickTimeSeriesFilter = PickTimeSeriesFilter_FromProto(mapCtx, in.GetPickTimeSeriesFilter()) + // MISSING: StatisticalTimeSeriesFilter + return out +} +func TimeSeriesFilterRatio_ToProto(mapCtx *MapContext, in *krm.TimeSeriesFilterRatio) *pb.TimeSeriesFilterRatio { + if in == nil { + return nil + } + out := &pb.TimeSeriesFilterRatio{} + out.Numerator = TimeSeriesFilterRatio_RatioPart_ToProto(mapCtx, in.Numerator) + out.Denominator = TimeSeriesFilterRatio_RatioPart_ToProto(mapCtx, in.Denominator) + out.SecondaryAggregation = Aggregation_ToProto(mapCtx, in.SecondaryAggregation) + if oneof := PickTimeSeriesFilter_ToProto(mapCtx, in.PickTimeSeriesFilter); oneof != nil { + out.OutputFilter = &pb.TimeSeriesFilterRatio_PickTimeSeriesFilter{PickTimeSeriesFilter: oneof} + } + // MISSING: StatisticalTimeSeriesFilter + return out +} +func TimeSeriesFilterRatio_RatioPart_FromProto(mapCtx *MapContext, in *pb.TimeSeriesFilterRatio_RatioPart) *krm.TimeSeriesFilterRatio_RatioPart { + if in == nil { + return nil + } + out := &krm.TimeSeriesFilterRatio_RatioPart{} + out.Filter = LazyPtr(in.GetFilter()) + out.Aggregation = Aggregation_FromProto(mapCtx, in.GetAggregation()) + return out +} +func TimeSeriesFilterRatio_RatioPart_ToProto(mapCtx *MapContext, in *krm.TimeSeriesFilterRatio_RatioPart) *pb.TimeSeriesFilterRatio_RatioPart { + if in == nil { + return nil + } + out := &pb.TimeSeriesFilterRatio_RatioPart{} + out.Filter = ValueOf(in.Filter) + out.Aggregation = Aggregation_ToProto(mapCtx, in.Aggregation) + return out +} +func TimeSeriesQuery_FromProto(mapCtx *MapContext, in *pb.TimeSeriesQuery) *krm.TimeSeriesQuery { + if in == nil { + return nil + } + out := &krm.TimeSeriesQuery{} + out.TimeSeriesFilter = TimeSeriesFilter_FromProto(mapCtx, in.GetTimeSeriesFilter()) + out.TimeSeriesFilterRatio = TimeSeriesFilterRatio_FromProto(mapCtx, in.GetTimeSeriesFilterRatio()) + out.TimeSeriesQueryLanguage = LazyPtr(in.GetTimeSeriesQueryLanguage()) + // MISSING: PrometheusQuery + out.UnitOverride = LazyPtr(in.GetUnitOverride()) + // MISSING: OutputFullDuration + return out +} +func TimeSeriesQuery_ToProto(mapCtx *MapContext, in *krm.TimeSeriesQuery) *pb.TimeSeriesQuery { + if in == nil { + return nil + } + out := &pb.TimeSeriesQuery{} + if oneof := TimeSeriesFilter_ToProto(mapCtx, in.TimeSeriesFilter); oneof != nil { + out.Source = &pb.TimeSeriesQuery_TimeSeriesFilter{TimeSeriesFilter: oneof} + } + if oneof := TimeSeriesFilterRatio_ToProto(mapCtx, in.TimeSeriesFilterRatio); oneof != nil { + out.Source = &pb.TimeSeriesQuery_TimeSeriesFilterRatio{TimeSeriesFilterRatio: oneof} + } + if oneof := TimeSeriesQuery_TimeSeriesQueryLanguage_ToProto(mapCtx, in.TimeSeriesQueryLanguage); oneof != nil { + out.Source = oneof + } + // MISSING: PrometheusQuery + out.UnitOverride = ValueOf(in.UnitOverride) + // MISSING: OutputFullDuration + return out +} +func TimeSeriesTable_FromProto(mapCtx *MapContext, in *pb.TimeSeriesTable) *krm.TimeSeriesTable { + if in == nil { + return nil + } + out := &krm.TimeSeriesTable{} + out.DataSets = Slice_FromProto(mapCtx, in.DataSets, TimeSeriesTable_TableDataSet_FromProto) + // MISSING: MetricVisualization + out.ColumnSettings = Slice_FromProto(mapCtx, in.ColumnSettings, TimeSeriesTable_ColumnSettings_FromProto) + return out +} +func TimeSeriesTable_ToProto(mapCtx *MapContext, in *krm.TimeSeriesTable) *pb.TimeSeriesTable { + if in == nil { + return nil + } + out := &pb.TimeSeriesTable{} + out.DataSets = Slice_ToProto(mapCtx, in.DataSets, TimeSeriesTable_TableDataSet_ToProto) + // MISSING: MetricVisualization + out.ColumnSettings = Slice_ToProto(mapCtx, in.ColumnSettings, TimeSeriesTable_ColumnSettings_ToProto) + return out +} +func TimeSeriesTable_ColumnSettings_FromProto(mapCtx *MapContext, in *pb.TimeSeriesTable_ColumnSettings) *krm.TimeSeriesTable_ColumnSettings { + if in == nil { + return nil + } + out := &krm.TimeSeriesTable_ColumnSettings{} + out.Column = LazyPtr(in.GetColumn()) + out.Visible = LazyPtr(in.GetVisible()) + return out +} +func TimeSeriesTable_ColumnSettings_ToProto(mapCtx *MapContext, in *krm.TimeSeriesTable_ColumnSettings) *pb.TimeSeriesTable_ColumnSettings { + if in == nil { + return nil + } + out := &pb.TimeSeriesTable_ColumnSettings{} + out.Column = ValueOf(in.Column) + out.Visible = ValueOf(in.Visible) + return out +} +func TimeSeriesTable_TableDataSet_FromProto(mapCtx *MapContext, in *pb.TimeSeriesTable_TableDataSet) *krm.TimeSeriesTable_TableDataSet { + if in == nil { + return nil + } + out := &krm.TimeSeriesTable_TableDataSet{} + out.TimeSeriesQuery = TimeSeriesQuery_FromProto(mapCtx, in.GetTimeSeriesQuery()) + out.TableTemplate = LazyPtr(in.GetTableTemplate()) + out.MinAlignmentPeriod = TableDataSet_MinAlignmentPeriod_FromProto(mapCtx, in.GetMinAlignmentPeriod()) + out.TableDisplayOptions = TableDisplayOptions_FromProto(mapCtx, in.GetTableDisplayOptions()) + return out +} +func TimeSeriesTable_TableDataSet_ToProto(mapCtx *MapContext, in *krm.TimeSeriesTable_TableDataSet) *pb.TimeSeriesTable_TableDataSet { + if in == nil { + return nil + } + out := &pb.TimeSeriesTable_TableDataSet{} + out.TimeSeriesQuery = TimeSeriesQuery_ToProto(mapCtx, in.TimeSeriesQuery) + out.TableTemplate = ValueOf(in.TableTemplate) + out.MinAlignmentPeriod = TableDataSet_MinAlignmentPeriod_ToProto(mapCtx, in.MinAlignmentPeriod) + out.TableDisplayOptions = TableDisplayOptions_ToProto(mapCtx, in.TableDisplayOptions) + return out +} +func Widget_FromProto(mapCtx *MapContext, in *pb.Widget) *krm.Widget { + if in == nil { + return nil + } + out := &krm.Widget{} + out.Title = LazyPtr(in.GetTitle()) + out.XyChart = XyChart_FromProto(mapCtx, in.GetXyChart()) + out.Scorecard = Scorecard_FromProto(mapCtx, in.GetScorecard()) + out.Text = Text_FromProto(mapCtx, in.GetText()) + out.Blank = Empty_FromProto(mapCtx, in.GetBlank()) + // MISSING: AlertChart + // MISSING: TimeSeriesTable + // MISSING: CollapsibleGroup + out.LogsPanel = LogsPanel_FromProto(mapCtx, in.GetLogsPanel()) + // MISSING: IncidentList + // MISSING: PieChart + // MISSING: ErrorReportingPanel + // MISSING: SectionHeader + // MISSING: SingleViewGroup + // MISSING: Id + return out +} +func Widget_ToProto(mapCtx *MapContext, in *krm.Widget) *pb.Widget { + if in == nil { + return nil + } + out := &pb.Widget{} + out.Title = ValueOf(in.Title) + if oneof := XyChart_ToProto(mapCtx, in.XyChart); oneof != nil { + out.Content = &pb.Widget_XyChart{XyChart: oneof} + } + if oneof := Scorecard_ToProto(mapCtx, in.Scorecard); oneof != nil { + out.Content = &pb.Widget_Scorecard{Scorecard: oneof} + } + if oneof := Text_ToProto(mapCtx, in.Text); oneof != nil { + out.Content = &pb.Widget_Text{Text: oneof} + } + if oneof := Empty_ToProto(mapCtx, in.Blank); oneof != nil { + out.Content = &pb.Widget_Blank{Blank: oneof} + } + // MISSING: AlertChart + // MISSING: TimeSeriesTable + // MISSING: CollapsibleGroup + if oneof := LogsPanel_ToProto(mapCtx, in.LogsPanel); oneof != nil { + out.Content = &pb.Widget_LogsPanel{LogsPanel: oneof} + } + // MISSING: IncidentList + // MISSING: PieChart + // MISSING: ErrorReportingPanel + // MISSING: SectionHeader + // MISSING: SingleViewGroup + // MISSING: Id + return out +} +func XyChart_FromProto(mapCtx *MapContext, in *pb.XyChart) *krm.XyChart { + if in == nil { + return nil + } + out := &krm.XyChart{} + out.DataSets = Slice_FromProto(mapCtx, in.DataSets, XyChart_DataSet_FromProto) + out.TimeshiftDuration = XyChart_TimeshiftDuration_FromProto(mapCtx, in.GetTimeshiftDuration()) + out.Thresholds = Slice_FromProto(mapCtx, in.Thresholds, Threshold_FromProto) + out.XAxis = XyChart_Axis_FromProto(mapCtx, in.GetXAxis()) + out.YAxis = XyChart_Axis_FromProto(mapCtx, in.GetYAxis()) + // MISSING: Y2Axis + out.ChartOptions = ChartOptions_FromProto(mapCtx, in.GetChartOptions()) + return out +} +func XyChart_ToProto(mapCtx *MapContext, in *krm.XyChart) *pb.XyChart { + if in == nil { + return nil + } + out := &pb.XyChart{} + out.DataSets = Slice_ToProto(mapCtx, in.DataSets, XyChart_DataSet_ToProto) + out.TimeshiftDuration = XyChart_TimeshiftDuration_ToProto(mapCtx, in.TimeshiftDuration) + out.Thresholds = Slice_ToProto(mapCtx, in.Thresholds, Threshold_ToProto) + out.XAxis = XyChart_Axis_ToProto(mapCtx, in.XAxis) + out.YAxis = XyChart_Axis_ToProto(mapCtx, in.YAxis) + // MISSING: Y2Axis + out.ChartOptions = ChartOptions_ToProto(mapCtx, in.ChartOptions) + return out +} +func XyChart_Axis_FromProto(mapCtx *MapContext, in *pb.XyChart_Axis) *krm.XyChart_Axis { + if in == nil { + return nil + } + out := &krm.XyChart_Axis{} + out.Label = LazyPtr(in.GetLabel()) + out.Scale = Enum_FromProto(mapCtx, in.Scale) + return out +} +func XyChart_Axis_ToProto(mapCtx *MapContext, in *krm.XyChart_Axis) *pb.XyChart_Axis { + if in == nil { + return nil + } + out := &pb.XyChart_Axis{} + out.Label = ValueOf(in.Label) + out.Scale = Enum_ToProto[pb.XyChart_Axis_Scale](mapCtx, in.Scale) + return out +} +func XyChart_DataSet_FromProto(mapCtx *MapContext, in *pb.XyChart_DataSet) *krm.XyChart_DataSet { + if in == nil { + return nil + } + out := &krm.XyChart_DataSet{} + out.TimeSeriesQuery = TimeSeriesQuery_FromProto(mapCtx, in.GetTimeSeriesQuery()) + out.PlotType = Enum_FromProto(mapCtx, in.PlotType) + out.LegendTemplate = LazyPtr(in.GetLegendTemplate()) + out.MinAlignmentPeriod = DataSet_MinAlignmentPeriod_FromProto(mapCtx, in.GetMinAlignmentPeriod()) + // MISSING: TargetAxis + return out +} +func XyChart_DataSet_ToProto(mapCtx *MapContext, in *krm.XyChart_DataSet) *pb.XyChart_DataSet { + if in == nil { + return nil + } + out := &pb.XyChart_DataSet{} + out.TimeSeriesQuery = TimeSeriesQuery_ToProto(mapCtx, in.TimeSeriesQuery) + out.PlotType = Enum_ToProto[pb.XyChart_DataSet_PlotType](mapCtx, in.PlotType) + out.LegendTemplate = ValueOf(in.LegendTemplate) + out.MinAlignmentPeriod = DataSet_MinAlignmentPeriod_ToProto(mapCtx, in.MinAlignmentPeriod) + // MISSING: TargetAxis + return out +} diff --git a/pkg/controller/direct/monitoring/dashboard_mappings.go b/pkg/controller/direct/monitoring/dashboard_mappings.go new file mode 100644 index 0000000000..ee55c1126d --- /dev/null +++ b/pkg/controller/direct/monitoring/dashboard_mappings.go @@ -0,0 +1,139 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package monitoring + +import ( + "strings" + + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/emptypb" + + pb "cloud.google.com/go/monitoring/dashboard/apiv1/dashboardpb" + krm "github.com/GoogleCloudPlatform/k8s-config-connector/apis/monitoring/v1beta1" + "github.com/GoogleCloudPlatform/k8s-config-connector/pkg/clients/generated/apis/k8s/v1alpha1" +) + +func Empty_FromProto(mapCtx *MapContext, in *emptypb.Empty) *krm.Empty { + if in == nil { + return nil + } + out := &krm.Empty{} + return out +} +func Empty_ToProto(mapCtx *MapContext, in *krm.Empty) *emptypb.Empty { + if in == nil { + return nil + } + out := &emptypb.Empty{} + return out +} + +func Aggregation_AlignmentPeriod_FromProto(mapCtx *MapContext, in *durationpb.Duration) *string { + return SecondsString_FromProto(mapCtx, in) +} + +func Aggregation_AlignmentPeriod_ToProto(mapCtx *MapContext, in *string) *durationpb.Duration { + return SecondsString_ToProto(mapCtx, in, "alignmentPeriod") +} + +// TODO: The format is not documented, we need to validate +func DataSet_MinAlignmentPeriod_FromProto(mapCtx *MapContext, in *durationpb.Duration) *string { + return SecondsString_FromProto(mapCtx, in) +} + +// TODO: The format is not documented, we need to validate +func DataSet_MinAlignmentPeriod_ToProto(mapCtx *MapContext, in *string) *durationpb.Duration { + return SecondsString_ToProto(mapCtx, in, "minAlignmentPeriod") +} + +// TODO: The format is not documented, we need to validate +func SparkChartView_MinAlignmentPeriod_FromProto(mapCtx *MapContext, in *durationpb.Duration) *string { + return SecondsString_FromProto(mapCtx, in) +} + +// TODO: The format is not documented, we need to validate +func SparkChartView_MinAlignmentPeriod_ToProto(mapCtx *MapContext, in *string) *durationpb.Duration { + return SecondsString_ToProto(mapCtx, in, "minAlignmentPeriod") +} + +// TODO: The format is not documented, we need to validate +func XyChart_TimeshiftDuration_FromProto(mapCtx *MapContext, in *durationpb.Duration) *string { + return Duration_FromProto(mapCtx, in) +} + +// TODO: The format is not documented, we need to validate +func XyChart_TimeshiftDuration_ToProto(mapCtx *MapContext, in *string) *durationpb.Duration { + return Duration_ToProto(mapCtx, in) +} + +func TableDataSet_MinAlignmentPeriod_FromProto(mapCtx *MapContext, in *durationpb.Duration) *string { + return Duration_FromProto(mapCtx, in) +} + +func TableDataSet_MinAlignmentPeriod_ToProto(mapCtx *MapContext, in *string) *durationpb.Duration { + return Duration_ToProto(mapCtx, in) +} + +func TimeSeriesQuery_TimeSeriesQueryLanguage_ToProto(mapCtx *MapContext, in *string) *pb.TimeSeriesQuery_TimeSeriesQueryLanguage { + if in == nil { + return nil + } + + return &pb.TimeSeriesQuery_TimeSeriesQueryLanguage{ + TimeSeriesQueryLanguage: ValueOf(in), + } +} + +func LogsPanel_ResourceNames_FromProto(mapCtx *MapContext, in []string) []v1alpha1.ResourceRef { + if in == nil { + return nil + } + var out []v1alpha1.ResourceRef + for _, v := range in { + tokens := strings.Split(v, "/") + if len(tokens) == 2 && tokens[0] == "projects" { + out = append(out, v1alpha1.ResourceRef{ + Kind: "Project", + External: v, + }) + } else { + mapCtx.Errorf("resourceName %q was not recognized", v) + } + } + return out +} + +func LogsPanel_ResourceNames_ToProto(mapCtx *MapContext, in []v1alpha1.ResourceRef) []string { + if in == nil { + return nil + } + var out []string + for _, ref := range in { + if ref.External == "" { + mapCtx.Errorf("reference was not pre-resolved") + } + out = append(out, ref.External) + } + return out +} + +func DashboardTimeSeriesQuery_TimeSeriesQueryLanguage_ToProto(mapCtx *MapContext, in *string) *pb.TimeSeriesQuery_TimeSeriesQueryLanguage { + if in == nil { + return nil + } + return &pb.TimeSeriesQuery_TimeSeriesQueryLanguage{ + TimeSeriesQueryLanguage: *in, + } +} diff --git a/pkg/controller/direct/monitoring/maputils.go b/pkg/controller/direct/monitoring/maputils.go new file mode 100644 index 0000000000..cd59b38a51 --- /dev/null +++ b/pkg/controller/direct/monitoring/maputils.go @@ -0,0 +1,188 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package monitoring + +import ( + "errors" + "fmt" + "strconv" + "strings" + "time" + + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/types/known/durationpb" +) + +type MapContext struct { + errs []error +} + +func (c *MapContext) Errorf(msg string, args ...interface{}) { + c.errs = append(c.errs, fmt.Errorf(msg, args...)) +} + +func (c *MapContext) Err() error { + return errors.Join(c.errs...) +} + +func Slice_ToProto[T, U any](mapCtx *MapContext, in []T, mapper func(mapCtx *MapContext, in *T) *U) []*U { + if in == nil { + return nil + } + + outSlice := make([]*U, 0, len(in)) + for _, inItem := range in { + outItem := mapper(mapCtx, &inItem) + outSlice = append(outSlice, outItem) + } + return outSlice +} + +func Slice_FromProto[T, U any](mapCtx *MapContext, in []*T, mapper func(mapCtx *MapContext, in *T) *U) []U { + if in == nil { + return nil + } + + outSlice := make([]U, 0, len(in)) + for _, inItem := range in { + outItem := mapper(mapCtx, inItem) + outSlice = append(outSlice, *outItem) + } + return outSlice +} + +type ProtoEnum interface { + ~int32 + Descriptor() protoreflect.EnumDescriptor +} + +func Enum_ToProto[U ProtoEnum](mapCtx *MapContext, in *string) U { + var defaultU U + descriptor := defaultU.Descriptor() + + inValue := ValueOf(in) + if inValue == "" { + unspecifiedValue := U(0) + return unspecifiedValue + } + + n := descriptor.Values().Len() + for i := 0; i < n; i++ { + value := descriptor.Values().Get(i) + if string(value.Name()) == inValue { + v := U(value.Number()) + return v + } + } + + var validValues []string + for i := 0; i < n; i++ { + value := descriptor.Values().Get(i) + validValues = append(validValues, string(value.Name())) + } + + mapCtx.Errorf("unknown enum value %q for %v (valid values are %v)", inValue, descriptor.FullName(), strings.Join(validValues, ", ")) + return 0 +} + +func Enum_FromProto[U ProtoEnum](mapCtx *MapContext, v U) *string { + descriptor := v.Descriptor() + + if v == 0 { + return nil + } + + val := descriptor.Values().ByNumber(protoreflect.EnumNumber(v)) + if val == nil { + mapCtx.Errorf("unknown enum value %d", v) + return nil + } + s := string(val.Name()) + return &s +} + +func Duration_ToProto(mapCtx *MapContext, in *string) *durationpb.Duration { + if in == nil { + return nil + } + + s := *in + if s == "" { + return nil + } + + if strings.HasPrefix(s, "seconds:") { + v := strings.TrimPrefix(s, "seconds:") + d, err := time.ParseDuration(v + "s") + if err != nil { + mapCtx.Errorf("parsing duration %q: %w", v, err) + return nil + } + out := durationpb.New(d) + return out + } + + // TODO: Is this 1:1 with durationpb? + d, err := time.ParseDuration(s) + if err != nil { + mapCtx.Errorf("parsing duration %q: %w", s, err) + return nil + } + out := durationpb.New(d) + return out +} + +func Duration_FromProto(mapCtx *MapContext, in *durationpb.Duration) *string { + if in == nil { + return nil + } + + s := in.String() + return &s +} + +func LazyPtr[V comparable](v V) *V { + var defaultV V + if v == defaultV { + return nil + } + return &v +} + +func SecondsString_FromProto(mapCtx *MapContext, in *durationpb.Duration) *string { + if in == nil { + return nil + } + seconds := in.GetSeconds() + out := strconv.FormatInt(seconds, 10) + return &out +} + +func SecondsString_ToProto(mapCtx *MapContext, in *string, fieldName string) *durationpb.Duration { + if in == nil { + return nil + } + v := *in + if strings.HasSuffix(v, "s") { + v = strings.TrimSuffix(v, "s") + } + seconds, err := strconv.ParseInt(v, 10, 64) + if err != nil { + mapCtx.Errorf("%s value %q is not valid", fieldName, *in) + return nil + } + out := &durationpb.Duration{Seconds: seconds} + return out +} diff --git a/pkg/controller/direct/monitoring/roundtrip_test.go b/pkg/controller/direct/monitoring/roundtrip_test.go new file mode 100644 index 0000000000..9cbbba6169 --- /dev/null +++ b/pkg/controller/direct/monitoring/roundtrip_test.go @@ -0,0 +1,419 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package monitoring + +import ( + "fmt" + "math/rand" + "strings" + "testing" + + pb "cloud.google.com/go/monitoring/dashboard/apiv1/dashboardpb" + + "github.com/google/go-cmp/cmp" + "google.golang.org/protobuf/encoding/prototext" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/testing/protocmp" + "k8s.io/apimachinery/pkg/util/sets" + "k8s.io/klog/v2" +) + +// IDEA: Load all the samples, and check that we have all the KRM paths covered + +func FuzzFromProto(f *testing.F) { + f.Fuzz(func(t *testing.T, seed int64) { + randStream := rand.New(rand.NewSource(seed)) + + p1 := &pb.Dashboard{} + fillWithRandom(t, randStream, p1) + + // We don't expect output fields to round-trip + outputFields := sets.New(".etag") + + // A few fields are not implemented yet in KRM, don't test them + unimplementedFields := sets.New( + ".name", + ".labels", + ".dashboard_filters", + ) + + // Widgets are under a few paths + widgetPaths := []string{ + ".grid_layout.widgets[]", + ".mosaic_layout.tiles[].widget", + ".column_layout.columns[].widgets[]", + ".row_layout.rows[].widgets[]", + } + for _, widgetPath := range widgetPaths { + unimplementedFields.Insert(widgetPath + ".xy_chart.data_sets[].target_axis") + unimplementedFields.Insert(widgetPath + ".xy_chart.data_sets[].time_series_query.prometheus_query") + unimplementedFields.Insert(widgetPath + ".xy_chart.y2_axis") + unimplementedFields.Insert(widgetPath + ".xy_chart.timeshift_duration") + unimplementedFields.Insert(widgetPath + ".xy_chart.thresholds[].target_axis") + + // This one might be a bug? + unimplementedFields.Insert(widgetPath + ".xy_chart.data_sets[].min_alignment_period.nanos") + + unimplementedFields.Insert(widgetPath + ".scorecard.thresholds[].target_axis") + unimplementedFields.Insert(widgetPath + ".scorecard.blank_view") + unimplementedFields.Insert(widgetPath + ".scorecard.time_series_query.prometheus_query") + unimplementedFields.Insert(widgetPath + ".scorecard.time_series_query.output_full_duration") + + unimplementedFields.Insert(widgetPath + ".alert_chart") + + unimplementedFields.Insert(widgetPath + ".time_series_table") + + unimplementedFields.Insert(widgetPath + ".collapsible_group") + + unimplementedFields.Insert(widgetPath + ".pie_chart") + + unimplementedFields.Insert(widgetPath + ".single_view_group") + + unimplementedFields.Insert(widgetPath + ".section_header") + + unimplementedFields.Insert(widgetPath + ".time_series_table") + + unimplementedFields.Insert(widgetPath + ".error_reporting_panel") + + unimplementedFields.Insert(widgetPath + ".incident_list") + + unimplementedFields.Insert(widgetPath + ".text.style") + + unimplementedFields.Insert(widgetPath + ".id") + } + + // Remove any output only or known-unimplemented fields + clearFields := &ClearFields{ + Paths: unimplementedFields.Union(outputFields), + } + visit("", p1.ProtoReflect(), nil, clearFields) + + // Force resource_names to be valid + r := &ReplaceFields{} + r.Func = func(path string, val protoreflect.Value) (protoreflect.Value, bool) { + if strings.HasSuffix(path, ".resource_names[]") { + return protoreflect.ValueOfString("projects/" + val.String()), true + } + return protoreflect.Value{}, false + } + visit("", p1.ProtoReflect(), nil, r) + + ctx := &MapContext{} + k := MonitoringDashboardSpec_FromProto(ctx, p1) + if ctx.Err() != nil { + t.Fatalf("error mapping from proto to krm: %v", ctx.Err()) + } + + p2 := MonitoringDashboardSpec_ToProto(ctx, k) + if ctx.Err() != nil { + t.Fatalf("error mapping from krm to proto: %v", ctx.Err()) + } + + if diff := cmp.Diff(p1, p2, protocmp.Transform()); diff != "" { + t.Logf("p1 = %v", prototext.Format(p1)) + t.Logf("p2 = %v", prototext.Format(p2)) + t.Errorf("roundtrip failed; diff:\n%s", diff) + } + }) +} + +func fillWithRandom(t *testing.T, randStream *rand.Rand, msg proto.Message) { + fillWithRandom0(t, randStream, msg.ProtoReflect()) +} + +func fillWithRandom0(t *testing.T, randStream *rand.Rand, msg protoreflect.Message) { + descriptor := msg.Descriptor() + if string(descriptor.FullName()) == "google.protobuf.Duration" { + count := randStream.Intn(10) + // Bias to zero + if count > 4 { + return + } + seconds := randStream.Intn(365 * 24 * 60 * 60) + nanos := randStream.Intn(1000000000) + msg.Set(descriptor.Fields().ByName("seconds"), protoreflect.ValueOfInt32(int32(seconds))) + msg.Set(descriptor.Fields().ByName("nanos"), protoreflect.ValueOfInt32(int32(nanos))) + return + } + + fields := descriptor.Fields() + n := fields.Len() + for i := 0; i < n; i++ { + field := fields.Get(i) + + if field.IsList() { + count := randStream.Intn(10) + // Bias heavily to zero + if count > 4 { + count = 0 + } + listVal := msg.Mutable(field).List() + switch field.Kind() { + case protoreflect.MessageKind: + for j := 0; j < count; j++ { + el := listVal.AppendMutable() + fillWithRandom0(t, randStream, el.Message()) + } + case protoreflect.StringKind: + for j := 0; j < count; j++ { + s := randomString(randStream) + listVal.Append(protoreflect.ValueOf(s)) + } + + default: + t.Fatalf("unhandled field kind %v: %v", field.Kind(), field) + } + continue + } + + if field.IsMap() { + count := randStream.Intn(10) + // Bias heavily to zero + if count > 4 { + count = 0 + } + mapType := fmt.Sprintf("%s->%s", field.MapKey().Kind(), field.MapValue().Kind()) + switch mapType { + case "string->string": + mapVal := msg.Mutable(field).Map() + for j := 0; j < count; j++ { + k := randomString(randStream) + v := randomString(randStream) + mapVal.Set(protoreflect.ValueOf(k).MapKey(), protoreflect.ValueOf(v)) + } + + default: + t.Fatalf("unhandled map kind %q: %v", mapType, field) + } + continue + } + + if field.Cardinality() == protoreflect.Optional { + if randStream.Intn(3) < 2 { + continue + } + } + + switch field.Kind() { + case protoreflect.MessageKind: + fieldVal := msg.Mutable(field) + fillWithRandom0(t, randStream, fieldVal.Message()) + + case protoreflect.BoolKind: + msg.Set(field, protoreflect.ValueOfBool(randStream.Intn(2) == 1)) + + case protoreflect.DoubleKind: + msg.Set(field, protoreflect.ValueOfFloat64(randStream.NormFloat64())) + case protoreflect.Int32Kind: + msg.Set(field, protoreflect.ValueOfInt32(randStream.Int31())) + case protoreflect.Int64Kind: + msg.Set(field, protoreflect.ValueOfInt64(randStream.Int63())) + case protoreflect.StringKind: + s := randomString(randStream) + msg.Set(field, protoreflect.ValueOfString(s)) + case protoreflect.EnumKind: + fieldDescriptor := field.Enum() + n := fieldDescriptor.Values().Len() + val := fieldDescriptor.Values().Get(randStream.Intn(n)) + msg.Set(field, protoreflect.ValueOf(val.Number())) + default: + t.Fatalf("unhandled field kind %v: %v", field.Kind(), field) + } + } +} + +func randomString(randStream *rand.Rand) string { + // TODO: This is not a good random string! + return fmt.Sprintf("%x", randStream.Int63()) +} + +type ProtoVisitor interface { + VisitPrimitive(path string, val protoreflect.Value, setter func(v protoreflect.Value)) + VisitMessage(path string, msg protoreflect.Message, setter func(v protoreflect.Value)) + VisitList(path string, msg protoreflect.List, setter func(v protoreflect.Value)) + VisitMap(path string, msg protoreflect.Map, setter func(v protoreflect.Value)) +} + +type ProtoVisitorBase struct { +} + +func (v *ProtoVisitorBase) VisitPrimitive(path string, val protoreflect.Value, setter func(v protoreflect.Value)) { + +} + +func (v *ProtoVisitorBase) VisitMessage(path string, msg protoreflect.Message, setter func(v protoreflect.Value)) { +} + +func (v *ProtoVisitorBase) VisitList(path string, msg protoreflect.List, setter func(v protoreflect.Value)) { +} + +func (v *ProtoVisitorBase) VisitMap(path string, msg protoreflect.Map, setter func(v protoreflect.Value)) { +} + +var _ ProtoVisitor = &ProtoVisitorBase{} + +type ClearFields struct { + ProtoVisitorBase + + Paths sets.Set[string] +} + +func (v *ClearFields) VisitPrimitive(path string, val protoreflect.Value, setter func(v protoreflect.Value)) { + if v.Paths.Has(path) { + setter(protoreflect.Value{}) + } +} + +func (v *ClearFields) VisitMessage(path string, msg protoreflect.Message, setter func(v protoreflect.Value)) { + if v.Paths.Has(path) { + setter(protoreflect.Value{}) + } +} + +func (v *ClearFields) VisitList(path string, msg protoreflect.List, setter func(v protoreflect.Value)) { + if v.Paths.Has(path) { + setter(protoreflect.Value{}) + } +} + +func (v *ClearFields) VisitMap(path string, msg protoreflect.Map, setter func(v protoreflect.Value)) { + if v.Paths.Has(path) { + setter(protoreflect.Value{}) + } +} + +var _ ProtoVisitor = &ClearFields{} + +type ReplaceFields struct { + ProtoVisitorBase + + Func func(path string, val protoreflect.Value) (protoreflect.Value, bool) +} + +func (v *ReplaceFields) VisitPrimitive(path string, val protoreflect.Value, setter func(v protoreflect.Value)) { + if newVal, ok := v.Func(path, val); ok { + setter(newVal) + } +} + +var _ ProtoVisitor = &ClearFields{} + +func visit(msgPath string, msg protoreflect.Message, setter func(v protoreflect.Value), visitor ProtoVisitor) { + visitor.VisitMessage(msgPath, msg, setter) + msg.Range(func(field protoreflect.FieldDescriptor, fieldVal protoreflect.Value) bool { + path := msgPath + "." + string(field.Name()) + klog.Infof("visit %q", path) + + if field.IsList() { + listVal := fieldVal.List() + setter := func(v protoreflect.Value) { + if v.IsValid() { + msg.Set(field, v) + } else { + msg.Clear(field) + } + } + visitor.VisitList(path, listVal, setter) + count := listVal.Len() + switch field.Kind() { + case protoreflect.MessageKind: + for j := 0; j < count; j++ { + el := listVal.Get(j) + setter := func(v protoreflect.Value) { + listVal.Set(j, v) + } + visit(path+"[]", el.Message(), setter, visitor) + } + case protoreflect.StringKind: + for j := 0; j < count; j++ { + el := listVal.Get(j) + setter := func(v protoreflect.Value) { + listVal.Set(j, v) + } + visitor.VisitPrimitive(path+"[]", el, setter) + } + + default: + klog.Fatalf("unhandled field kind %v: %v", field.Kind(), field) + } + return true + } + + if field.IsMap() { + mapType := fmt.Sprintf("%s->%s", field.MapKey().Kind(), field.MapValue().Kind()) + switch mapType { + case "string->string": + mapVal := msg.Mutable(field).Map() + setter := func(v protoreflect.Value) { + if v.IsValid() { + msg.Set(field, v) + } else { + msg.Clear(field) + } + } + visitor.VisitMap(path, mapVal, setter) + + // In case the value changes + mapVal = msg.Mutable(field).Map() + mapVal.Range(func(k protoreflect.MapKey, val protoreflect.Value) bool { + mapPath := path + "[" + k.String() + "]" + setter := func(v protoreflect.Value) { + mapVal.Set(k, v) + } + visitor.VisitPrimitive(mapPath, val, setter) + return true + }) + + default: + klog.Fatalf("unhandled map kind %q: %v", mapType, field) + } + return true + } + + switch field.Kind() { + case protoreflect.MessageKind: + setter := func(v protoreflect.Value) { + if v.IsValid() { + msg.Set(field, v) + } else { + msg.Clear(field) + } + } + visit(path, fieldVal.Message(), setter, visitor) + + case protoreflect.BoolKind, + protoreflect.DoubleKind, + protoreflect.Int32Kind, + protoreflect.Int64Kind, + protoreflect.StringKind, + protoreflect.EnumKind: + setter := func(v protoreflect.Value) { + if v.IsValid() { + msg.Set(field, v) + } else { + msg.Clear(field) + } + } + visitor.VisitPrimitive(path, fieldVal, setter) + + default: + klog.Fatalf("unhandled field kind %v: %v", field.Kind(), field) + } + + return true + }) + +} diff --git a/pkg/controller/direct/monitoring/utils.go b/pkg/controller/direct/monitoring/utils.go new file mode 100644 index 0000000000..f9889a247c --- /dev/null +++ b/pkg/controller/direct/monitoring/utils.go @@ -0,0 +1,27 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package monitoring + +func ValueOf[T any](p *T) T { + var v T + if p != nil { + v = *p + } + return v +} + +func PtrTo[T any](t T) *T { + return &t +}