-
Notifications
You must be signed in to change notification settings - Fork 5k
costmanagement: convert view resources to use typed models with Decode/Encode #32191
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4,6 +4,14 @@ | |||||||||||||
| package costmanagement | ||||||||||||||
|
|
||||||||||||||
| import ( | ||||||||||||||
| "context" | ||||||||||||||
| "fmt" | ||||||||||||||
| "time" | ||||||||||||||
|
|
||||||||||||||
| "github.com/hashicorp/go-azure-helpers/lang/pointer" | ||||||||||||||
| "github.com/hashicorp/go-azure-helpers/lang/response" | ||||||||||||||
| "github.com/hashicorp/go-azure-sdk/resource-manager/costmanagement/2023-08-01/views" | ||||||||||||||
| "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" | ||||||||||||||
| "github.com/hashicorp/terraform-provider-azurerm/internal/sdk" | ||||||||||||||
| "github.com/hashicorp/terraform-provider-azurerm/internal/services/costmanagement/validate" | ||||||||||||||
| resourceValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/resource/validate" | ||||||||||||||
|
|
@@ -15,6 +23,19 @@ type ResourceGroupCostManagementViewResource struct { | |||||||||||||
| base costManagementViewBaseResource | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| type ResourceGroupCostManagementViewModel struct { | ||||||||||||||
| Name string `tfschema:"name"` | ||||||||||||||
| ResourceGroupId string `tfschema:"resource_group_id"` | ||||||||||||||
| DisplayName string `tfschema:"display_name"` | ||||||||||||||
| ChartType string `tfschema:"chart_type"` | ||||||||||||||
| Accumulated bool `tfschema:"accumulated"` | ||||||||||||||
| ReportType string `tfschema:"report_type"` | ||||||||||||||
| Timeframe string `tfschema:"timeframe"` | ||||||||||||||
| Dataset []CostManagementViewDatasetModel `tfschema:"dataset"` | ||||||||||||||
| Kpi []CostManagementViewKpiModel `tfschema:"kpi"` | ||||||||||||||
| Pivot []CostManagementViewPivotModel `tfschema:"pivot"` | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| var _ sdk.Resource = ResourceGroupCostManagementViewResource{} | ||||||||||||||
|
|
||||||||||||||
| func (r ResourceGroupCostManagementViewResource) Arguments() map[string]*pluginsdk.Schema { | ||||||||||||||
|
|
@@ -40,7 +61,7 @@ func (r ResourceGroupCostManagementViewResource) Attributes() map[string]*plugin | |||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| func (r ResourceGroupCostManagementViewResource) ModelObject() interface{} { | ||||||||||||||
| return nil | ||||||||||||||
| return &ResourceGroupCostManagementViewModel{} | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| func (r ResourceGroupCostManagementViewResource) ResourceType() string { | ||||||||||||||
|
|
@@ -52,17 +73,178 @@ func (r ResourceGroupCostManagementViewResource) IDValidationFunc() pluginsdk.Sc | |||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| func (r ResourceGroupCostManagementViewResource) Create() sdk.ResourceFunc { | ||||||||||||||
| return r.base.createFunc(r.ResourceType(), "resource_group_id") | ||||||||||||||
| return sdk.ResourceFunc{ | ||||||||||||||
| Timeout: 30 * time.Minute, | ||||||||||||||
| Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { | ||||||||||||||
| client := metadata.Client.CostManagement.ViewsClient | ||||||||||||||
|
|
||||||||||||||
| var config ResourceGroupCostManagementViewModel | ||||||||||||||
| if err := metadata.Decode(&config); err != nil { | ||||||||||||||
| return fmt.Errorf("decoding: %+v", err) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| id := views.NewScopedViewID(config.ResourceGroupId, config.Name) | ||||||||||||||
|
|
||||||||||||||
| existing, err := client.GetByScope(ctx, id) | ||||||||||||||
| if err != nil { | ||||||||||||||
| if !response.WasNotFound(existing.HttpResponse) { | ||||||||||||||
| return fmt.Errorf("checking for presence of existing %s: %+v", id, err) | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| if !response.WasNotFound(existing.HttpResponse) { | ||||||||||||||
| return tf.ImportAsExistsError(r.ResourceType(), id.ID()) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| accumulated := views.AccumulatedTypeFalse | ||||||||||||||
| if config.Accumulated { | ||||||||||||||
| accumulated = views.AccumulatedTypeTrue | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| props := views.View{ | ||||||||||||||
| Properties: &views.ViewProperties{ | ||||||||||||||
| Accumulated: pointer.To(accumulated), | ||||||||||||||
| DisplayName: pointer.To(config.DisplayName), | ||||||||||||||
| Chart: pointer.To(views.ChartType(config.ChartType)), | ||||||||||||||
| Query: &views.ReportConfigDefinition{ | ||||||||||||||
| DataSet: expandDatasetFromModel(config.Dataset), | ||||||||||||||
| Timeframe: views.ReportTimeframeType(config.Timeframe), | ||||||||||||||
| Type: views.ReportTypeUsage, | ||||||||||||||
| }, | ||||||||||||||
| Kpis: expandKpisFromModel(config.Kpi), | ||||||||||||||
| Pivots: expandPivotsFromModel(config.Pivot), | ||||||||||||||
| }, | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| if _, err = client.CreateOrUpdateByScope(ctx, id, props); err != nil { | ||||||||||||||
| return fmt.Errorf("creating %s: %+v", id, err) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| metadata.SetID(id) | ||||||||||||||
| return nil | ||||||||||||||
| }, | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| func (r ResourceGroupCostManagementViewResource) Read() sdk.ResourceFunc { | ||||||||||||||
| return r.base.readFunc("resource_group_id") | ||||||||||||||
| return sdk.ResourceFunc{ | ||||||||||||||
| Timeout: 5 * time.Minute, | ||||||||||||||
| Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { | ||||||||||||||
| client := metadata.Client.CostManagement.ViewsClient | ||||||||||||||
|
|
||||||||||||||
| id, err := views.ParseScopedViewID(metadata.ResourceData.Id()) | ||||||||||||||
| if err != nil { | ||||||||||||||
| return err | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| resp, err := client.GetByScope(ctx, *id) | ||||||||||||||
| if err != nil { | ||||||||||||||
| if response.WasNotFound(resp.HttpResponse) { | ||||||||||||||
| return metadata.MarkAsGone(id) | ||||||||||||||
| } | ||||||||||||||
| return fmt.Errorf("reading %s: %+v", *id, err) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| state := ResourceGroupCostManagementViewModel{ | ||||||||||||||
| Name: id.ViewName, | ||||||||||||||
| ResourceGroupId: id.Scope, | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| if model := resp.Model; model != nil { | ||||||||||||||
| if props := model.Properties; props != nil { | ||||||||||||||
| state.ChartType = string(pointer.From(props.Chart)) | ||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
| state.DisplayName = pointer.From(props.DisplayName) | ||||||||||||||
|
|
||||||||||||||
| accumulated := false | ||||||||||||||
| if props.Accumulated != nil { | ||||||||||||||
| accumulated = views.AccumulatedTypeTrue == *props.Accumulated | ||||||||||||||
| } | ||||||||||||||
| state.Accumulated = accumulated | ||||||||||||||
|
Comment on lines
+158
to
+162
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can be simplified using
Suggested change
|
||||||||||||||
|
|
||||||||||||||
| state.Kpi = flattenKpisToModel(props.Kpis) | ||||||||||||||
| state.Pivot = flattenPivotsToModel(props.Pivots) | ||||||||||||||
|
|
||||||||||||||
| if query := props.Query; query != nil { | ||||||||||||||
| state.Timeframe = string(query.Timeframe) | ||||||||||||||
| state.ReportType = string(query.Type) | ||||||||||||||
| if query.DataSet != nil { | ||||||||||||||
| state.Dataset = flattenDatasetToModel(query.DataSet) | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| return metadata.Encode(&state) | ||||||||||||||
| }, | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| func (r ResourceGroupCostManagementViewResource) Delete() sdk.ResourceFunc { | ||||||||||||||
| return r.base.deleteFunc() | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| func (r ResourceGroupCostManagementViewResource) Update() sdk.ResourceFunc { | ||||||||||||||
| return r.base.updateFunc() | ||||||||||||||
| return sdk.ResourceFunc{ | ||||||||||||||
| Timeout: 30 * time.Minute, | ||||||||||||||
| Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error { | ||||||||||||||
| client := metadata.Client.CostManagement.ViewsClient | ||||||||||||||
|
|
||||||||||||||
| id, err := views.ParseScopedViewID(metadata.ResourceData.Id()) | ||||||||||||||
| if err != nil { | ||||||||||||||
| return err | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| var config ResourceGroupCostManagementViewModel | ||||||||||||||
| if err := metadata.Decode(&config); err != nil { | ||||||||||||||
| return fmt.Errorf("decoding: %+v", err) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| // Update operation requires latest eTag to be set in the request. | ||||||||||||||
| existing, err := client.GetByScope(ctx, *id) | ||||||||||||||
| if err != nil { | ||||||||||||||
| return fmt.Errorf("reading %s: %+v", *id, err) | ||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||
| } | ||||||||||||||
| model := existing.Model | ||||||||||||||
|
|
||||||||||||||
| if model != nil { | ||||||||||||||
| if model.ETag == nil { | ||||||||||||||
| return fmt.Errorf("add %s: etag was nil", *id) | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| if model.Properties == nil { | ||||||||||||||
| return fmt.Errorf("retreiving properties for %s for update: %+v", *id, err) | ||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. err will always be nil, it doesn't make sense to include it, and a typo fix
Suggested change
|
||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| if metadata.ResourceData.HasChange("display_name") { | ||||||||||||||
| model.Properties.DisplayName = pointer.To(config.DisplayName) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| if metadata.ResourceData.HasChange("chart_type") { | ||||||||||||||
| model.Properties.Chart = pointer.To(views.ChartType(config.ChartType)) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| if metadata.ResourceData.HasChange("dataset") { | ||||||||||||||
| model.Properties.Query.DataSet = expandDatasetFromModel(config.Dataset) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| if metadata.ResourceData.HasChange("timeframe") { | ||||||||||||||
| model.Properties.Query.Timeframe = views.ReportTimeframeType(config.Timeframe) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| if metadata.ResourceData.HasChange("kpi") { | ||||||||||||||
| model.Properties.Kpis = expandKpisFromModel(config.Kpi) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| if metadata.ResourceData.HasChange("pivot") { | ||||||||||||||
| model.Properties.Pivots = expandPivotsFromModel(config.Pivot) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| if _, err = client.CreateOrUpdateByScope(ctx, *id, *model); err != nil { | ||||||||||||||
| return fmt.Errorf("updating %s: %+v", *id, err) | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| return nil | ||||||||||||||
| }, | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.