Skip to content

Commit

Permalink
Migrate synthetics_private_location to framework
Browse files Browse the repository at this point in the history
  • Loading branch information
AntoineDona committed Mar 3, 2025
1 parent 013f6db commit b69defb
Show file tree
Hide file tree
Showing 8 changed files with 368 additions and 408 deletions.
1 change: 1 addition & 0 deletions datadog/fwprovider/framework_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ var Resources = []func() resource.Resource{
NewLogsCustomDestinationResource,
NewTenantBasedHandleResource,
NewActionConnectionResource,
NewSyntheticsPrivateLocationResource,
}

var Datasources = []func() datasource.DataSource{
Expand Down
278 changes: 278 additions & 0 deletions datadog/fwprovider/resource_datadog_synthetics_private_location.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
package fwprovider

import (
"context"
"encoding/json"
"fmt"

"github.com/DataDog/datadog-api-client-go/v2/api/datadogV1"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework/diag"
frameworkPath "github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"

"github.com/terraform-providers/terraform-provider-datadog/datadog/internal/utils"
)

var (
_ resource.ResourceWithConfigure = &syntheticsPrivateLocationResource{}
_ resource.ResourceWithImportState = &syntheticsPrivateLocationResource{}
)

type syntheticsPrivateLocationResource struct {
Api *datadogV1.SyntheticsApi
Auth context.Context
}

type syntheticsPrivateLocationModel struct {
Id types.String `tfsdk:"id"`
Config types.String `tfsdk:"config"`
Description types.String `tfsdk:"description"`
Metadata []metadataModel `tfsdk:"metadata"`
Name types.String `tfsdk:"name"`
Tags types.List `tfsdk:"tags"`
}

type metadataModel struct {
RestrictedRoles types.Set `tfsdk:"restricted_roles"`
}

func NewSyntheticsPrivateLocationResource() resource.Resource {
return &syntheticsPrivateLocationResource{}
}

func (r *syntheticsPrivateLocationResource) Configure(_ context.Context, request resource.ConfigureRequest, response *resource.ConfigureResponse) {
providerData, _ := request.ProviderData.(*FrameworkProvider)
r.Api = providerData.DatadogApiInstances.GetSyntheticsApiV1()
r.Auth = providerData.Auth
}

func (r *syntheticsPrivateLocationResource) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) {
response.TypeName = "synthetics_private_location"
}

func (r *syntheticsPrivateLocationResource) Schema(_ context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) {
response.Schema = schema.Schema{
Description: "Provides a Datadog SyntheticsPrivateLocation resource. This can be used to create and manage Datadog synthetics_private_location.",
Attributes: map[string]schema.Attribute{
"description": schema.StringAttribute{
Optional: true,
Description: "Description of the private location.",
},
"name": schema.StringAttribute{
Required: true,
Description: "Name of the private location.",
},
"tags": schema.ListAttribute{
Optional: true,
Description: "Array of tags attached to the private location.",
ElementType: types.StringType,
},
"config": schema.StringAttribute{
Description: "Configuration skeleton for the private location. See installation instructions of the private location on how to use this configuration.",
Computed: true,
Sensitive: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"id": utils.ResourceIDAttribute(),
},
Blocks: map[string]schema.Block{
"metadata": schema.ListNestedBlock{
Description: "The private location metadata",
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"restricted_roles": schema.SetAttribute{
Description: "A list of role identifiers pulled from the Roles API to restrict read and write access.",
DeprecationMessage: "This field is no longer supported by the Datadog API. Please use `datadog_restriction_policy` instead.",
Optional: true,
ElementType: types.StringType,
},
},
},
Validators: []validator.List{
listvalidator.SizeAtMost(1),
},
},
},
}
}

func (r *syntheticsPrivateLocationResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, frameworkPath.Root("id"), request, response)
}

func (r *syntheticsPrivateLocationResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) {
var state syntheticsPrivateLocationModel
response.Diagnostics.Append(request.State.Get(ctx, &state)...)
if response.Diagnostics.HasError() {
return
}

id := state.Id.ValueString()
resp, httpResp, err := r.Api.GetPrivateLocation(r.Auth, id)
if err != nil {
if httpResp != nil && httpResp.StatusCode == 404 {
response.State.RemoveResource(ctx)
return
}
response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error retrieving SyntheticsPrivateLocation"))
return
}
if err := utils.CheckForUnparsed(resp); err != nil {
response.Diagnostics.AddError("response contains unparsedObject", err.Error())
return
}

r.updateState(ctx, &state, &resp)

// Save data into Terraform state
response.Diagnostics.Append(response.State.Set(ctx, &state)...)
}

func (r *syntheticsPrivateLocationResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) {
var state syntheticsPrivateLocationModel
response.Diagnostics.Append(request.Plan.Get(ctx, &state)...)
if response.Diagnostics.HasError() {
return
}

body, diags := r.buildSyntheticsPrivateLocationRequestBody(ctx, &state)
response.Diagnostics.Append(diags...)
if response.Diagnostics.HasError() {
return
}

resp, _, err := r.Api.CreatePrivateLocation(r.Auth, *body)
if err != nil {
response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error retrieving SyntheticsPrivateLocation"))
return
}
if err := utils.CheckForUnparsed(resp); err != nil {
response.Diagnostics.AddError("response contains unparsedObject", err.Error())
return
}
r.updateState(ctx, &state, resp.PrivateLocation)

// set the config that is only returned when creating the private location
conf, err := json.Marshal(resp.GetConfig())
if err != nil {
response.Diagnostics.AddError(
"Error marshaling config to JSON",
fmt.Sprintf("Could not marshal config: %s", err.Error()),
)
}

state.Config = types.StringValue(string(conf))

// Save data into Terraform state
response.Diagnostics.Append(response.State.Set(ctx, &state)...)
}

func (r *syntheticsPrivateLocationResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) {
var state syntheticsPrivateLocationModel
response.Diagnostics.Append(request.Plan.Get(ctx, &state)...)
if response.Diagnostics.HasError() {
return
}

id := state.Id.ValueString()

body, diags := r.buildSyntheticsPrivateLocationRequestBody(ctx, &state)
response.Diagnostics.Append(diags...)
if response.Diagnostics.HasError() {
return
}

resp, _, err := r.Api.UpdatePrivateLocation(r.Auth, id, *body)
if err != nil {
response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error retrieving SyntheticsPrivateLocation"))
return
}
if err := utils.CheckForUnparsed(resp); err != nil {
response.Diagnostics.AddError("response contains unparsedObject", err.Error())
return
}
r.updateState(ctx, &state, &resp)

// Save data into Terraform state
response.Diagnostics.Append(response.State.Set(ctx, &state)...)
}

func (r *syntheticsPrivateLocationResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) {
var state syntheticsPrivateLocationModel
response.Diagnostics.Append(request.State.Get(ctx, &state)...)
if response.Diagnostics.HasError() {
return
}

id := state.Id.ValueString()

httpResp, err := r.Api.DeletePrivateLocation(r.Auth, id)
if err != nil {
if httpResp != nil && httpResp.StatusCode == 404 {
return
}
response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error deleting synthetics_private_location"))
return
}
response.State.RemoveResource(ctx)
}

func (r *syntheticsPrivateLocationResource) updateState(ctx context.Context, state *syntheticsPrivateLocationModel, resp *datadogV1.SyntheticsPrivateLocation) {

state.Id = types.StringValue(resp.GetId())

state.Description = types.StringValue(resp.GetDescription())

state.Name = types.StringValue(resp.GetName())

state.Tags, _ = types.ListValueFrom(ctx, types.StringType, resp.GetTags())

if metadata, ok := resp.GetMetadataOk(); ok {

metadataTf := metadataModel{}
if restrictedRoles, ok := metadata.GetRestrictedRolesOk(); ok && len(*restrictedRoles) > 0 {

metadataTf.RestrictedRoles, _ = types.SetValueFrom(ctx, types.StringType, *restrictedRoles)
}
state.Metadata = []metadataModel{metadataTf}
}
}

func (r *syntheticsPrivateLocationResource) buildSyntheticsPrivateLocationRequestBody(ctx context.Context, state *syntheticsPrivateLocationModel) (*datadogV1.SyntheticsPrivateLocation, diag.Diagnostics) {
diags := diag.Diagnostics{}
req := datadogV1.NewSyntheticsPrivateLocationWithDefaults()

if !state.Description.IsNull() {
req.SetDescription(state.Description.ValueString())
}
if !state.Name.IsNull() {
req.SetName(state.Name.ValueString())
}

if !state.Tags.IsNull() {
var tags []string
diags.Append(state.Tags.ElementsAs(ctx, &tags, false)...)
req.SetTags(tags)
}

if state.Metadata != nil {
var metadata datadogV1.SyntheticsPrivateLocationMetadata

if len(state.Metadata) == 1 && !state.Metadata[0].RestrictedRoles.IsNull() {
var restrictedRoles []string
diags.Append(state.Metadata[0].RestrictedRoles.ElementsAs(ctx, &restrictedRoles, false)...)
metadata.SetRestrictedRoles(restrictedRoles)
}
req.Metadata = &metadata
}

return req, diags
}
3 changes: 1 addition & 2 deletions datadog/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,7 @@ func Provider() *schema.Provider {
"datadog_slo_correction": resourceDatadogSloCorrection(),
"datadog_synthetics_test": resourceDatadogSyntheticsTest(),
"datadog_synthetics_global_variable": resourceDatadogSyntheticsGlobalVariable(),
"datadog_synthetics_private_location": resourceDatadogSyntheticsPrivateLocation(),
"datadog_user": resourceDatadogUser(),
"datadog_user": resourceDatadogUser(),
},

// NEW DATA SOURCES ARE NOT ALLOWED TO BE ADDED HERE
Expand Down
Loading

0 comments on commit b69defb

Please sign in to comment.