Skip to content

Commit ccaf302

Browse files
committed
add import state functionality
1 parent 523cc3c commit ccaf302

File tree

5 files changed

+89
-40
lines changed

5 files changed

+89
-40
lines changed

datadog/fwprovider/resource_datadog_custom_framework.go

Lines changed: 46 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package fwprovider
22

33
import (
44
"context"
5+
"strings"
56

67
"github.com/DataDog/datadog-api-client-go/v2/api/datadogV2"
78
"github.com/hashicorp/terraform-plugin-framework/attr"
@@ -29,13 +30,6 @@ type customFrameworkModel struct {
2930
Requirements types.Set `tfsdk:"requirements"` // have to define requirements as a set to be unordered
3031
}
3132

32-
// the only way I could get the requirements to be unordered was to define them as a set in Terraform :(
33-
// if I could define requirements as a list, I could use the following:
34-
// type requirementModel struct {
35-
// Name types.String `tfsdk:"name"`
36-
// Controls types.Set `tfsdk:"controls"`
37-
// }
38-
3933
func NewCustomFrameworkResource() resource.Resource {
4034
return &customFrameworkResource{}
4135
}
@@ -122,6 +116,7 @@ func (r *customFrameworkResource) Create(ctx context.Context, request resource.C
122116
}
123117

124118
_, _, err := r.Api.CreateCustomFramework(r.Auth, *buildCreateFrameworkRequest(state))
119+
125120
if err != nil {
126121
response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error creating custom framework"))
127122
return
@@ -158,12 +153,37 @@ func (r *customFrameworkResource) Read(ctx context.Context, request resource.Rea
158153
response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error reading custom framework"))
159154
return
160155
}
161-
state.ID = types.StringValue(data.GetData().Attributes.Handle + string('-') + data.GetData().Attributes.Version)
156+
databaseState := readStateFromDatabase(data, state.Handle.ValueString(), state.Version.ValueString())
157+
diags = response.State.Set(ctx, &databaseState)
158+
response.Diagnostics.Append(diags...)
159+
}
160+
161+
func (r *customFrameworkResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) {
162+
var state customFrameworkModel
163+
diags := request.Config.Get(ctx, &state)
164+
response.Diagnostics.Append(diags...)
165+
if response.Diagnostics.HasError() {
166+
return
167+
}
168+
169+
_, _, err := r.Api.UpdateCustomFramework(r.Auth, state.Handle.ValueString(), state.Version.ValueString(), *buildUpdateFrameworkRequest(state))
170+
if err != nil {
171+
response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error updating custom framework"))
172+
return
173+
}
174+
diags = response.State.Set(ctx, &state)
175+
response.Diagnostics.Append(diags...)
176+
}
177+
178+
func readStateFromDatabase(data datadogV2.RetrieveCustomFrameworkResponse, handle string, version string) customFrameworkModel {
179+
// Set the state
180+
var state customFrameworkModel
181+
state.ID = types.StringValue(handle + "-" + version)
182+
state.Handle = types.StringValue(handle)
183+
state.Version = types.StringValue(version)
184+
state.Name = types.StringValue(data.GetData().Attributes.Name)
162185
state.Description = types.StringValue(data.GetData().Attributes.Description)
163186
state.IconURL = types.StringValue(data.GetData().Attributes.IconUrl)
164-
state.Version = types.StringValue(data.GetData().Attributes.Version)
165-
state.Handle = types.StringValue(data.GetData().Attributes.Handle)
166-
state.Name = types.StringValue(data.GetData().Attributes.Name)
167187

168188
// Convert requirements to set
169189
requirements := make([]attr.Value, len(data.GetData().Attributes.Requirements))
@@ -186,7 +206,6 @@ func (r *customFrameworkResource) Read(ctx context.Context, request resource.Rea
186206
},
187207
)
188208
}
189-
// set requirement
190209
requirements[i] = types.ObjectValueMust(
191210
map[string]attr.Type{
192211
"name": types.StringType,
@@ -204,7 +223,6 @@ func (r *customFrameworkResource) Read(ctx context.Context, request resource.Rea
204223
},
205224
)
206225
}
207-
// set state requirements
208226
state.Requirements = types.SetValueMust(
209227
types.ObjectType{AttrTypes: map[string]attr.Type{
210228
"name": types.StringType,
@@ -215,25 +233,29 @@ func (r *customFrameworkResource) Read(ctx context.Context, request resource.Rea
215233
}},
216234
requirements,
217235
)
218-
diags = response.State.Set(ctx, &state)
219-
response.Diagnostics.Append(diags...)
236+
return state
220237
}
221238

222-
func (r *customFrameworkResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) {
223-
var state customFrameworkModel
224-
diags := request.Config.Get(ctx, &state)
225-
response.Diagnostics.Append(diags...)
226-
if response.Diagnostics.HasError() {
239+
// ImportState is used to import a resource from an existing framework so we can update it if it exists in the database and not in terraform
240+
func (r *customFrameworkResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) {
241+
// Split the ID into handle and version
242+
// The last hyphen separates handle and version
243+
lastHyphenIndex := strings.LastIndex(request.ID, "-")
244+
if lastHyphenIndex == -1 {
245+
response.Diagnostics.AddError("Invalid import ID", "Import ID must contain a hyphen to separate handle and version")
227246
return
228247
}
248+
handle := request.ID[:lastHyphenIndex]
249+
version := request.ID[lastHyphenIndex+1:]
229250

230-
_, _, err := r.Api.UpdateCustomFramework(r.Auth, state.Handle.ValueString(), state.Version.ValueString(), *buildUpdateFrameworkRequest(state))
251+
data, _, err := r.Api.RetrieveCustomFramework(r.Auth, handle, version)
231252
if err != nil {
232-
response.Diagnostics.Append(utils.FrameworkErrorDiag(err, "error updating custom framework"))
253+
response.Diagnostics.AddError("Error importing resource", err.Error())
233254
return
234255
}
235-
diags = response.State.Set(ctx, &state)
236-
response.Diagnostics.Append(diags...)
256+
257+
state := readStateFromDatabase(data, handle, version)
258+
response.Diagnostics.Append(response.State.Set(ctx, &state)...)
237259
}
238260

239261
func convertStateRequirementsToFrameworkRequirements(requirements types.Set) []datadogV2.CustomFrameworkRequirement {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
terraform import datadog_custom_framework.example2 "new-terraform-framework-test-2"
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
terraform {
2+
required_providers {
3+
datadog = {
4+
source = "DataDog/datadog"
5+
}
6+
}
7+
}
8+
9+
provider "datadog" {
10+
api_key = var.datadog_api_key
11+
app_key = var.datadog_app_key
12+
}
13+
14+
15+
resource "datadog_custom_framework" "example" {
16+
version = "1.0.0"
17+
handle = "terraform-created-framework-handle"
18+
name = "terraform-created-framework"
19+
icon_url = "https://example.com/icon.png"
20+
description = "This is a test I created this resource through terraform"
21+
requirements {
22+
name = "requirement1"
23+
controls {
24+
name = "changedControlName"
25+
rules_id = ["def-000-cea"]
26+
}
27+
}
28+
}
29+
30+
31+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
variable "datadog_api_key" {
2+
description = "Datadog API key"
3+
type = string
4+
sensitive = true
5+
}
6+
7+
variable "datadog_app_key" {
8+
description = "Datadog APP key"
9+
type = string
10+
sensitive = true
11+
}

examples/resources/datadog_custom_framework_rules/resource.tf

Lines changed: 0 additions & 16 deletions
This file was deleted.

0 commit comments

Comments
 (0)