Skip to content

Commit 147be76

Browse files
committed
feat(resourcemanager): add folder_id to folder resource
Signed-off-by: Mauritz Uphoff <[email protected]>
1 parent 8c8b3a8 commit 147be76

File tree

6 files changed

+78
-31
lines changed

6 files changed

+78
-31
lines changed

docs/data-sources/resourcemanager_folder.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ data "stackit_resourcemanager_folder" "example" {
2828
### Read-Only
2929

3030
- `creation_time` (String) Date-time at which the folder was created.
31+
- `folder_id` (String) Folder UUID identifier. Globally unique folder identifier
3132
- `id` (String) Terraform's internal resource ID. It is structured as "`container_id`".
3233
- `labels` (Map of String) Labels are key-value string pairs which can be attached to a resource container. A label key must match the regex [A-ZÄÜÖa-zäüöß0-9_-]{1,64}. A label value must match the regex ^$|[A-ZÄÜÖa-zäüöß0-9_-]{1,64}.
3334
- `name` (String) The name of the folder.

docs/resources/resourcemanager_folder.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,6 @@ resource "stackit_resourcemanager_folder" "example" {
4040

4141
- `container_id` (String) Folder container ID. Globally unique, user-friendly identifier.
4242
- `creation_time` (String) Date-time at which the folder was created.
43+
- `folder_id` (String) Folder UUID identifier. Globally unique folder identifier
4344
- `id` (String) Terraform's internal resource ID. It is structured as "`container_id`".
4445
- `update_time` (String) Date-time at which the folder was last modified.

stackit/internal/services/resourcemanager/folder/datasource.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ func (d *folderDataSource) Schema(_ context.Context, _ datasource.SchemaRequest,
6767
"main": "Resource Manager folder data source schema. To identify the folder, you need to provider the container_id.",
6868
"id": "Terraform's internal resource ID. It is structured as \"`container_id`\".",
6969
"container_id": "Folder container ID. Globally unique, user-friendly identifier.",
70+
"folder_id": "Folder UUID identifier. Globally unique folder identifier",
7071
"parent_container_id": "Parent resource identifier. Both container ID (user-friendly) and UUID are supported.",
7172
"name": "The name of the folder.",
7273
"labels": "Labels are key-value string pairs which can be attached to a resource container. A label key must match the regex [A-ZÄÜÖa-zäüöß0-9_-]{1,64}. A label value must match the regex ^$|[A-ZÄÜÖa-zäüöß0-9_-]{1,64}.",
@@ -89,6 +90,13 @@ func (d *folderDataSource) Schema(_ context.Context, _ datasource.SchemaRequest,
8990
},
9091
Required: true,
9192
},
93+
"folder_id": schema.StringAttribute{
94+
Description: descriptions["folder_id"],
95+
Computed: true,
96+
Validators: []validator.String{
97+
validate.UUID(),
98+
},
99+
},
92100
"parent_container_id": schema.StringAttribute{
93101
Description: descriptions["parent_container_id"],
94102
Computed: true,

stackit/internal/services/resourcemanager/folder/resource.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ const (
4545

4646
type Model struct {
4747
Id types.String `tfsdk:"id"` // needed by TF
48+
FolderId types.String `tfsdk:"folder_id"`
4849
ContainerId types.String `tfsdk:"container_id"`
4950
ContainerParentId types.String `tfsdk:"parent_container_id"`
5051
Name types.String `tfsdk:"name"`
@@ -99,6 +100,7 @@ func (r *folderResource) Schema(_ context.Context, _ resource.SchemaRequest, res
99100
"main": "Resource Manager folder resource schema.",
100101
"id": "Terraform's internal resource ID. It is structured as \"`container_id`\".",
101102
"container_id": "Folder container ID. Globally unique, user-friendly identifier.",
103+
"folder_id": "Folder UUID identifier. Globally unique folder identifier",
102104
"parent_container_id": "Parent resource identifier. Both container ID (user-friendly) and UUID are supported.",
103105
"name": "The name of the folder.",
104106
"labels": "Labels are key-value string pairs which can be attached to a resource container. A label key must match the regex [A-ZÄÜÖa-zäüöß0-9_-]{1,64}. A label value must match the regex ^$|[A-ZÄÜÖa-zäüöß0-9_-]{1,64}.",
@@ -127,6 +129,16 @@ func (r *folderResource) Schema(_ context.Context, _ resource.SchemaRequest, res
127129
validate.NoSeparator(),
128130
},
129131
},
132+
"folder_id": schema.StringAttribute{
133+
Description: descriptions["folder_id"],
134+
Computed: true,
135+
PlanModifiers: []planmodifier.String{
136+
stringplanmodifier.UseStateForUnknown(),
137+
},
138+
Validators: []validator.String{
139+
validate.UUID(),
140+
},
141+
},
130142
"parent_container_id": schema.StringAttribute{
131143
Description: descriptions["parent_container_id"],
132144
Required: true,
@@ -351,7 +363,7 @@ func (r *folderResource) ImportState(ctx context.Context, req resource.ImportSta
351363
// mapFolderFields maps folder fields from a response into the Terraform model and optionally updates state.
352364
func mapFolderFields(
353365
ctx context.Context,
354-
containerId, name *string,
366+
containerId, name, folderId *string,
355367
labels *map[string]string, //nolint:gocritic
356368
containerParent *resourcemanager.Parent,
357369
creationTime *time.Time,
@@ -388,6 +400,7 @@ func mapFolderFields(
388400
}
389401

390402
model.Id = types.StringValue(*containerId)
403+
model.FolderId = types.StringValue(*folderId)
391404
model.ContainerId = types.StringValue(*containerId)
392405
model.ContainerParentId = containerParentIdTF
393406
model.Name = types.StringPointerValue(name)
@@ -398,8 +411,9 @@ func mapFolderFields(
398411
if state != nil {
399412
diags := diag.Diagnostics{}
400413
diags.Append(state.SetAttribute(ctx, path.Root("id"), model.Id)...)
401-
diags.Append(state.SetAttribute(ctx, path.Root("parent_container_id"), model.ContainerParentId)...)
414+
diags.Append(state.SetAttribute(ctx, path.Root("folder_id"), model.FolderId)...)
402415
diags.Append(state.SetAttribute(ctx, path.Root("container_id"), model.ContainerId)...)
416+
diags.Append(state.SetAttribute(ctx, path.Root("parent_container_id"), model.ContainerParentId)...)
403417
diags.Append(state.SetAttribute(ctx, path.Root("name"), model.Name)...)
404418
diags.Append(state.SetAttribute(ctx, path.Root("labels"), model.Labels)...)
405419
diags.Append(state.SetAttribute(ctx, path.Root("creation_time"), model.CreationTime)...)
@@ -414,12 +428,12 @@ func mapFolderFields(
414428

415429
// mapFolderCreateFields maps the Create Folder API response to the Terraform model and update the Terraform state
416430
func mapFolderCreateFields(ctx context.Context, resp *resourcemanager.FolderResponse, model *Model, state *tfsdk.State) error {
417-
return mapFolderFields(ctx, resp.ContainerId, resp.Name, resp.Labels, resp.Parent, resp.CreationTime, resp.UpdateTime, model, state)
431+
return mapFolderFields(ctx, resp.ContainerId, resp.Name, resp.FolderId, resp.Labels, resp.Parent, resp.CreationTime, resp.UpdateTime, model, state)
418432
}
419433

420434
// mapFolderDetailsFields maps the GetDetails API response to the Terraform model and update the Terraform state
421435
func mapFolderDetailsFields(ctx context.Context, resp *resourcemanager.GetFolderDetailsResponse, model *Model, state *tfsdk.State) error {
422-
return mapFolderFields(ctx, resp.ContainerId, resp.Name, resp.Labels, resp.Parent, resp.CreationTime, resp.UpdateTime, model, state)
436+
return mapFolderFields(ctx, resp.ContainerId, resp.Name, resp.FolderId, resp.Labels, resp.Parent, resp.CreationTime, resp.UpdateTime, model, state)
423437
}
424438

425439
func toMembersPayload(model *ResourceModel) (*[]resourcemanager.Member, error) {

stackit/internal/services/resourcemanager/folder/resource_test.go

Lines changed: 44 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import (
1616
)
1717

1818
func TestMapFolderFields(t *testing.T) {
19-
testUUID := "73b2d741-bddd-471f-8d47-3d1aa677a19c"
19+
parentContainerUUID := uuid.New().String()
20+
folderUUID := uuid.New().String()
2021

2122
// Create base timestamps for reuse
2223
baseTime := time.Now()
@@ -26,6 +27,7 @@ func TestMapFolderFields(t *testing.T) {
2627
tests := []struct {
2728
description string
2829
uuidContainerParentId bool
30+
respFolderId *string
2931
respContainerId *string
3032
respName *string
3133
respCreateTime *time.Time
@@ -39,20 +41,22 @@ func TestMapFolderFields(t *testing.T) {
3941
{
4042
description: "valid input with UUID parent ID",
4143
uuidContainerParentId: true,
42-
respContainerId: utils.Ptr("folder-cid-uuid"),
44+
respFolderId: &folderUUID,
45+
respContainerId: utils.Ptr("folder-human-readable-id"),
4346
respName: utils.Ptr("folder-name"),
4447
respCreateTime: &createTime,
4548
respUpdateTime: &updateTime,
4649
labels: &map[string]string{
4750
"env": "prod",
4851
},
4952
parent: &resourcemanager.Parent{
50-
Id: utils.Ptr(testUUID),
53+
Id: utils.Ptr(parentContainerUUID),
5154
},
5255
expected: Model{
53-
Id: types.StringValue("folder-cid-uuid"),
54-
ContainerId: types.StringValue("folder-cid-uuid"),
55-
ContainerParentId: types.StringValue(testUUID),
56+
Id: types.StringValue("folder-human-readable-id"),
57+
FolderId: types.StringValue(folderUUID),
58+
ContainerId: types.StringValue("folder-human-readable-id"),
59+
ContainerParentId: types.StringValue(parentContainerUUID),
5660
Name: types.StringValue("folder-name"),
5761
CreationTime: types.StringValue(createTime.Format(time.RFC3339)),
5862
UpdateTime: types.StringValue(updateTime.Format(time.RFC3339)),
@@ -65,18 +69,20 @@ func TestMapFolderFields(t *testing.T) {
6569
{
6670
description: "valid input with UUID parent ID no labels",
6771
uuidContainerParentId: true,
68-
respContainerId: utils.Ptr("folder-cid-uuid"),
72+
respFolderId: &folderUUID,
73+
respContainerId: utils.Ptr("folder-human-readable-id"),
6974
respName: utils.Ptr("folder-name"),
7075
respCreateTime: &createTime,
7176
respUpdateTime: &updateTime,
7277
labels: nil,
7378
parent: &resourcemanager.Parent{
74-
Id: utils.Ptr(testUUID),
79+
Id: utils.Ptr(parentContainerUUID),
7580
},
7681
expected: Model{
77-
Id: types.StringValue("folder-cid-uuid"),
78-
ContainerId: types.StringValue("folder-cid-uuid"),
79-
ContainerParentId: types.StringValue(testUUID),
82+
Id: types.StringValue("folder-human-readable-id"),
83+
FolderId: types.StringValue(folderUUID),
84+
ContainerId: types.StringValue("folder-human-readable-id"),
85+
ContainerParentId: types.StringValue(parentContainerUUID),
8086
Name: types.StringValue("folder-name"),
8187
CreationTime: types.StringValue(createTime.Format(time.RFC3339)),
8288
UpdateTime: types.StringValue(updateTime.Format(time.RFC3339)),
@@ -87,7 +93,8 @@ func TestMapFolderFields(t *testing.T) {
8793
{
8894
description: "valid input with ContainerId as parent",
8995
uuidContainerParentId: false,
90-
respContainerId: utils.Ptr("folder-cid"),
96+
respFolderId: &folderUUID,
97+
respContainerId: utils.Ptr("folder-human-readable-id"),
9198
respName: utils.Ptr("folder-name"),
9299
respCreateTime: &createTime,
93100
respUpdateTime: &updateTime,
@@ -98,8 +105,9 @@ func TestMapFolderFields(t *testing.T) {
98105
ContainerId: utils.Ptr("parent-container-id"),
99106
},
100107
expected: Model{
101-
Id: types.StringValue("folder-cid"),
102-
ContainerId: types.StringValue("folder-cid"),
108+
Id: types.StringValue("folder-human-readable-id"),
109+
FolderId: types.StringValue(folderUUID),
110+
ContainerId: types.StringValue("folder-human-readable-id"),
103111
ContainerParentId: types.StringValue("parent-container-id"),
104112
Name: types.StringValue("folder-name"),
105113
CreationTime: types.StringValue(createTime.Format(time.RFC3339)),
@@ -113,7 +121,8 @@ func TestMapFolderFields(t *testing.T) {
113121
{
114122
description: "valid input with ContainerId as parent no labels",
115123
uuidContainerParentId: false,
116-
respContainerId: utils.Ptr("folder-cid"),
124+
respFolderId: &folderUUID,
125+
respContainerId: utils.Ptr("folder-human-readable-id"),
117126
respName: utils.Ptr("folder-name"),
118127
respCreateTime: &createTime,
119128
respUpdateTime: &updateTime,
@@ -122,8 +131,9 @@ func TestMapFolderFields(t *testing.T) {
122131
ContainerId: utils.Ptr("parent-container-id"),
123132
},
124133
expected: Model{
125-
Id: types.StringValue("folder-cid"),
126-
ContainerId: types.StringValue("folder-cid"),
134+
Id: types.StringValue("folder-human-readable-id"),
135+
FolderId: types.StringValue(folderUUID),
136+
ContainerId: types.StringValue("folder-human-readable-id"),
127137
ContainerParentId: types.StringValue("parent-container-id"),
128138
Name: types.StringValue("folder-name"),
129139
CreationTime: types.StringValue(createTime.Format(time.RFC3339)),
@@ -135,15 +145,17 @@ func TestMapFolderFields(t *testing.T) {
135145
{
136146
description: "nil labels",
137147
uuidContainerParentId: false,
138-
respContainerId: utils.Ptr("folder-cid"),
148+
respFolderId: &folderUUID,
149+
respContainerId: utils.Ptr("folder-human-readable-id"),
139150
respName: utils.Ptr("folder-name"),
140151
respCreateTime: &createTime,
141152
respUpdateTime: &updateTime,
142153
labels: nil,
143154
parent: nil,
144155
expected: Model{
145-
Id: types.StringValue("folder-cid"),
146-
ContainerId: types.StringValue("folder-cid"),
156+
Id: types.StringValue("folder-human-readable-id"),
157+
FolderId: types.StringValue(folderUUID),
158+
ContainerId: types.StringValue("folder-human-readable-id"),
147159
ContainerParentId: types.StringNull(),
148160
Name: types.StringValue("folder-name"),
149161
CreationTime: types.StringValue(createTime.Format(time.RFC3339)),
@@ -196,7 +208,7 @@ func TestMapFolderFields(t *testing.T) {
196208
// Simulate ContainerParentId configuration based on UUID detection logic
197209
var containerParentId basetypes.StringValue
198210
if tt.uuidContainerParentId {
199-
containerParentId = types.StringValue(testUUID)
211+
containerParentId = types.StringValue(parentContainerUUID)
200212
} else if tt.parent != nil && tt.parent.ContainerId != nil {
201213
containerParentId = types.StringValue(*tt.parent.ContainerId)
202214
} else {
@@ -212,6 +224,7 @@ func TestMapFolderFields(t *testing.T) {
212224
context.Background(),
213225
tt.respContainerId,
214226
tt.respName,
227+
tt.respFolderId,
215228
tt.labels,
216229
tt.parent,
217230
tt.respCreateTime,
@@ -245,7 +258,8 @@ func TestMapFolderCreateFields(t *testing.T) {
245258
updateTime := baseTime.Add(1 * time.Hour)
246259

247260
resp := &resourcemanager.FolderResponse{
248-
ContainerId: utils.Ptr("folder-id"),
261+
FolderId: utils.Ptr("folder-uuid"),
262+
ContainerId: utils.Ptr("folder-human-readable-id"),
249263
Name: utils.Ptr("my-folder"),
250264
Labels: &labels,
251265
Parent: &resourcemanager.Parent{
@@ -266,8 +280,9 @@ func TestMapFolderCreateFields(t *testing.T) {
266280

267281
cbLabels, _ := conversion.ToTerraformStringMap(context.Background(), labels)
268282
expected := Model{
269-
Id: types.StringValue("folder-id"),
270-
ContainerId: types.StringValue("folder-id"),
283+
Id: types.StringValue("folder-human-readable-id"),
284+
FolderId: types.StringValue("folder-uuid"),
285+
ContainerId: types.StringValue("folder-human-readable-id"),
271286
ContainerParentId: types.StringValue(*resp.Parent.Id),
272287
Name: types.StringValue("my-folder"),
273288
Labels: cbLabels,
@@ -286,7 +301,8 @@ func TestMapFolderDetailsFields(t *testing.T) {
286301
updateTime := baseTime.Add(1 * time.Hour)
287302

288303
resp := &resourcemanager.GetFolderDetailsResponse{
289-
ContainerId: utils.Ptr("folder-id"),
304+
FolderId: utils.Ptr("folder-uuid"),
305+
ContainerId: utils.Ptr("folder-human-readable-id"),
290306
Name: utils.Ptr("details-folder"),
291307
Labels: &map[string]string{
292308
"foo": "bar",
@@ -307,8 +323,9 @@ func TestMapFolderDetailsFields(t *testing.T) {
307323
tfLabels, _ := conversion.ToTerraformStringMap(context.Background(), *resp.Labels)
308324

309325
expected := Model{
310-
Id: types.StringValue("folder-id"),
311-
ContainerId: types.StringValue("folder-id"),
326+
Id: types.StringValue("folder-human-readable-id"),
327+
FolderId: types.StringValue("folder-uuid"),
328+
ContainerId: types.StringValue("folder-human-readable-id"),
312329
ContainerParentId: types.StringValue("parent-container"),
313330
Name: types.StringValue("details-folder"),
314331
Labels: tfLabels,

0 commit comments

Comments
 (0)