Skip to content

Commit 218b2d7

Browse files
committed
feat(resourcemanager): add folder_id to folder resource
Signed-off-by: Mauritz Uphoff <mauritz.uphoff@stackit.cloud>
1 parent 8c8b3a8 commit 218b2d7

File tree

6 files changed

+53
-10
lines changed

6 files changed

+53
-10
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: 19 additions & 6 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,6 +41,7 @@ func TestMapFolderFields(t *testing.T) {
3941
{
4042
description: "valid input with UUID parent ID",
4143
uuidContainerParentId: true,
44+
respFolderId: &folderUUID,
4245
respContainerId: utils.Ptr("folder-cid-uuid"),
4346
respName: utils.Ptr("folder-name"),
4447
respCreateTime: &createTime,
@@ -47,12 +50,13 @@ func TestMapFolderFields(t *testing.T) {
4750
"env": "prod",
4851
},
4952
parent: &resourcemanager.Parent{
50-
Id: utils.Ptr(testUUID),
53+
Id: utils.Ptr(parentContainerUUID),
5154
},
5255
expected: Model{
5356
Id: types.StringValue("folder-cid-uuid"),
57+
FolderId: types.StringValue(folderUUID),
5458
ContainerId: types.StringValue("folder-cid-uuid"),
55-
ContainerParentId: types.StringValue(testUUID),
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,
72+
respFolderId: &folderUUID,
6873
respContainerId: utils.Ptr("folder-cid-uuid"),
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{
7782
Id: types.StringValue("folder-cid-uuid"),
83+
FolderId: types.StringValue(folderUUID),
7884
ContainerId: types.StringValue("folder-cid-uuid"),
79-
ContainerParentId: types.StringValue(testUUID),
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,6 +93,7 @@ func TestMapFolderFields(t *testing.T) {
8793
{
8894
description: "valid input with ContainerId as parent",
8995
uuidContainerParentId: false,
96+
respFolderId: &folderUUID,
9097
respContainerId: utils.Ptr("folder-cid"),
9198
respName: utils.Ptr("folder-name"),
9299
respCreateTime: &createTime,
@@ -99,6 +106,7 @@ func TestMapFolderFields(t *testing.T) {
99106
},
100107
expected: Model{
101108
Id: types.StringValue("folder-cid"),
109+
FolderId: types.StringValue(folderUUID),
102110
ContainerId: types.StringValue("folder-cid"),
103111
ContainerParentId: types.StringValue("parent-container-id"),
104112
Name: types.StringValue("folder-name"),
@@ -113,6 +121,7 @@ func TestMapFolderFields(t *testing.T) {
113121
{
114122
description: "valid input with ContainerId as parent no labels",
115123
uuidContainerParentId: false,
124+
respFolderId: &folderUUID,
116125
respContainerId: utils.Ptr("folder-cid"),
117126
respName: utils.Ptr("folder-name"),
118127
respCreateTime: &createTime,
@@ -123,6 +132,7 @@ func TestMapFolderFields(t *testing.T) {
123132
},
124133
expected: Model{
125134
Id: types.StringValue("folder-cid"),
135+
FolderId: types.StringValue(folderUUID),
126136
ContainerId: types.StringValue("folder-cid"),
127137
ContainerParentId: types.StringValue("parent-container-id"),
128138
Name: types.StringValue("folder-name"),
@@ -135,6 +145,7 @@ func TestMapFolderFields(t *testing.T) {
135145
{
136146
description: "nil labels",
137147
uuidContainerParentId: false,
148+
respFolderId: &folderUUID,
138149
respContainerId: utils.Ptr("folder-cid"),
139150
respName: utils.Ptr("folder-name"),
140151
respCreateTime: &createTime,
@@ -143,6 +154,7 @@ func TestMapFolderFields(t *testing.T) {
143154
parent: nil,
144155
expected: Model{
145156
Id: types.StringValue("folder-cid"),
157+
FolderId: types.StringValue(folderUUID),
146158
ContainerId: types.StringValue("folder-cid"),
147159
ContainerParentId: types.StringNull(),
148160
Name: types.StringValue("folder-name"),
@@ -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,

stackit/internal/services/resourcemanager/resourcemanager_acc_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ func TestAccResourceManagerFolderContainerId(t *testing.T) {
281281
resource.TestCheckResourceAttr("stackit_resourcemanager_folder.example", "labels.%", "1"),
282282
resource.TestCheckResourceAttr("stackit_resourcemanager_folder.example", "labels.env", "prod"),
283283
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "container_id"),
284+
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "folder_id"),
284285
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "id"),
285286
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "creation_time"),
286287
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "update_time"),
@@ -302,6 +303,7 @@ func TestAccResourceManagerFolderContainerId(t *testing.T) {
302303
resource.TestCheckResourceAttr("data.stackit_resourcemanager_folder.example", "labels.%", "1"),
303304
resource.TestCheckResourceAttr("data.stackit_resourcemanager_folder.example", "labels.env", "prod"),
304305
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_folder.example", "parent_container_id"),
306+
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_folder.example", "folder_id"),
305307
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_folder.example", "container_id"),
306308
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_folder.example", "id"),
307309
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_folder.example", "creation_time"),
@@ -330,6 +332,7 @@ func TestAccResourceManagerFolderContainerId(t *testing.T) {
330332
resource.TestCheckResourceAttr("stackit_resourcemanager_folder.example", "labels.%", "1"),
331333
resource.TestCheckResourceAttr("stackit_resourcemanager_folder.example", "labels.env", "prod"),
332334
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "container_id"),
335+
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "folder_id"),
333336
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "id"),
334337
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "owner_email"),
335338
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "creation_time"),
@@ -357,6 +360,7 @@ func TestAccResourceManagerFolderParentUUID(t *testing.T) {
357360
resource.TestCheckResourceAttr("stackit_resourcemanager_folder.example", "labels.%", "1"),
358361
resource.TestCheckResourceAttr("stackit_resourcemanager_folder.example", "labels.env", "prod"),
359362
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "container_id"),
363+
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "folder_id"),
360364
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "id"),
361365
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "creation_time"),
362366
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "update_time"),
@@ -378,6 +382,7 @@ func TestAccResourceManagerFolderParentUUID(t *testing.T) {
378382
resource.TestCheckResourceAttr("data.stackit_resourcemanager_folder.example", "labels.%", "1"),
379383
resource.TestCheckResourceAttr("data.stackit_resourcemanager_folder.example", "labels.env", "prod"),
380384
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_folder.example", "parent_container_id"),
385+
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_folder.example", "folder_id"),
381386
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_folder.example", "container_id"),
382387
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_folder.example", "id"),
383388
resource.TestCheckResourceAttrSet("data.stackit_resourcemanager_folder.example", "creation_time"),
@@ -406,6 +411,7 @@ func TestAccResourceManagerFolderParentUUID(t *testing.T) {
406411
resource.TestCheckResourceAttr("stackit_resourcemanager_folder.example", "labels.%", "1"),
407412
resource.TestCheckResourceAttr("stackit_resourcemanager_folder.example", "labels.env", "prod"),
408413
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "container_id"),
414+
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "folder_id"),
409415
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "id"),
410416
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "owner_email"),
411417
resource.TestCheckResourceAttrSet("stackit_resourcemanager_folder.example", "creation_time"),

0 commit comments

Comments
 (0)