Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions docs/data-sources/resourcemanager_folder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackit_resourcemanager_folder Data Source - stackit"
subcategory: ""
description: |-
Resource Manager folder data source schema. To identify the folder, you need to provider the container_id.
---

# stackit_resourcemanager_folder (Data Source)

Resource Manager folder data source schema. To identify the folder, you need to provider the container_id.

## Example Usage

```terraform
data "stackit_resourcemanager_folder" "example" {
container_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `container_id` (String) Folder container ID. Globally unique, user-friendly identifier.

### Read-Only

- `creation_time` (String) Date-time at which the folder was created.
- `folder_id` (String) Folder UUID identifier. Globally unique folder identifier
- `id` (String) Terraform's internal resource ID. It is structured as "`container_id`".
- `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}.
- `name` (String) The name of the folder.
- `parent_container_id` (String) Parent resource identifier. Both container ID (user-friendly) and UUID are supported.
- `update_time` (String) Date-time at which the folder was last modified.
2 changes: 2 additions & 0 deletions docs/data-sources/resourcemanager_project.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ data "stackit_resourcemanager_project" "example" {

### Read-Only

- `creation_time` (String) Date-time at which the project was created.
- `id` (String) Terraform's internal data source. ID. It is structured as "`container_id`".
- `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}
- `name` (String) Project name.
- `parent_container_id` (String) Parent resource identifier. Both container ID (user-friendly) and UUID are supported
- `update_time` (String) Date-time at which the project was last modified.
56 changes: 56 additions & 0 deletions docs/resources/resourcemanager_folder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackit_resourcemanager_folder Resource - stackit"
subcategory: ""
description: |-
Resource Manager folder resource schema.
~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our guide https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources for how to opt-in to use beta resources.
---

# stackit_resourcemanager_folder (Resource)

Resource Manager folder resource schema.

~> This resource is in beta and may be subject to breaking changes in the future. Use with caution. See our [guide](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources) for how to opt-in to use beta resources.

## Example Usage

```terraform
resource "stackit_resourcemanager_folder" "example" {
name = "example-folder"
owner_email = "[email protected]"
parent_container_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

# Note:
# You can add projects under folders.
# However, when deleting a project, be aware:
# - Projects may remain "invisible" for up to 7 days after deletion
# - During this time, deleting the parent folder may fail because the project is still technically linked
resource "stackit_resourcemanager_project" "example_project" {
name = "example-project"
owner_email = "[email protected]"
parent_container_id = stackit_resourcemanager_folder.example.container_id
}
```

<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `name` (String) The name of the folder.
- `owner_email` (String) Email address of the owner of the folder. This value is only considered during creation. Changing it afterwards will have no effect.
- `parent_container_id` (String) Parent resource identifier. Both container ID (user-friendly) and UUID are supported.

### Optional

- `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}.

### Read-Only

- `container_id` (String) Folder container ID. Globally unique, user-friendly identifier.
- `creation_time` (String) Date-time at which the folder was created.
- `folder_id` (String) Folder UUID identifier. Globally unique folder identifier
- `id` (String) Terraform's internal resource ID. It is structured as "`container_id`".
- `update_time` (String) Date-time at which the folder was last modified.
6 changes: 4 additions & 2 deletions docs/resources/resourcemanager_project.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
page_title: "stackit_resourcemanager_project Resource - stackit"
subcategory: ""
description: |-
Resource Manager project resource schema. To use this resource, it is required that you set the service account email in the provider configuration.
Resource Manager project resource schema.
-> In case you're getting started with an empty STACKIT organization and want to use this resource to create projects in it, check out this guide https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/stackit_org_service_account for how to create a service account which you can use for authentication in the STACKIT Terraform provider.
---

# stackit_resourcemanager_project (Resource)

Resource Manager project resource schema. To use this resource, it is required that you set the service account email in the provider configuration.
Resource Manager project resource schema.

-> In case you're getting started with an empty STACKIT organization and want to use this resource to create projects in it, check out [this guide](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/stackit_org_service_account) for how to create a service account which you can use for authentication in the STACKIT Terraform provider.

Expand Down Expand Up @@ -52,5 +52,7 @@ To create a project within a STACKIT Network Area, setting the label `networkAre
### Read-Only

- `container_id` (String) Project container ID. Globally unique, user-friendly identifier.
- `creation_time` (String) Date-time at which the project was created.
- `id` (String) Terraform's internal resource ID. It is structured as "`container_id`".
- `project_id` (String) Project UUID identifier. This is the ID that can be used in most of the other resources to identify the project.
- `update_time` (String) Date-time at which the project was last modified.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
data "stackit_resourcemanager_folder" "example" {
container_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
16 changes: 16 additions & 0 deletions examples/resources/stackit_resourcemanager_folder/resource.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
resource "stackit_resourcemanager_folder" "example" {
name = "example-folder"
owner_email = "[email protected]"
parent_container_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

# Note:
# You can add projects under folders.
# However, when deleting a project, be aware:
# - Projects may remain "invisible" for up to 7 days after deletion
# - During this time, deleting the parent folder may fail because the project is still technically linked
resource "stackit_resourcemanager_project" "example_project" {
name = "example-project"
owner_email = "[email protected]"
parent_container_id = stackit_resourcemanager_folder.example.container_id
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add an example, how to import a folder like we have it for other resources:

# Only use the import statement, if you want to import an existing resourcemanager project
# Note: There will be a conflict which needs to be resolved manually.
# Must set a configuration value for the owner_email attribute as the provider has marked it as required.
import {
to = stackit_resourcemanager_project.import-example
id = var.container_id
}

184 changes: 184 additions & 0 deletions stackit/internal/services/resourcemanager/folder/datasource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
package folder

import (
"context"
"fmt"
"net/http"
"regexp"

"github.com/hashicorp/terraform-plugin-framework-validators/mapvalidator"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/services/resourcemanager"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/features"
resourcemanagerUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/resourcemanager/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
)

// Ensure the implementation satisfies the expected interfaces.
var (
_ datasource.DataSource = &folderDataSource{}
Comment on lines +26 to +27
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick. to ensure the Configure method is always implemented and not changed accidentally

Suggested change
var (
_ datasource.DataSource = &folderDataSource{}
var (
_ datasource.DataSource = &folderDataSource{}
_ datasource.DataSourceWithConfigure = &folderDataSource{}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

)

// NewFolderDataSource is a helper function to simplify the provider implementation.
func NewFolderDataSource() datasource.DataSource {
return &folderDataSource{}
}

// folderDataSource is the data source implementation.
type folderDataSource struct {
client *resourcemanager.APIClient
}

// Metadata returns the data source type name.
func (d *folderDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_resourcemanager_folder"
}

func (d *folderDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
providerData, ok := conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics)
if !ok {
return
}

features.CheckBetaResourcesEnabled(ctx, &providerData, &resp.Diagnostics, "stackit_resourcemanager_folder", "datasource")
if resp.Diagnostics.HasError() {
return
}

apiClient := resourcemanagerUtils.ConfigureClient(ctx, &providerData, &resp.Diagnostics)
if resp.Diagnostics.HasError() {
return
}
d.client = apiClient
tflog.Info(ctx, "Resource Manager client configured")
}

// Schema defines the schema for the data source.
func (d *folderDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
descriptions := map[string]string{
"main": "Resource Manager folder data source schema. To identify the folder, you need to provider the container_id.",
"id": "Terraform's internal resource ID. It is structured as \"`container_id`\".",
"container_id": "Folder container ID. Globally unique, user-friendly identifier.",
"folder_id": "Folder UUID identifier. Globally unique folder identifier",
"parent_container_id": "Parent resource identifier. Both container ID (user-friendly) and UUID are supported.",
"name": "The name of the folder.",
"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}.",
"owner_email": "Email address of the owner of the folder. This value is only considered during creation. Changing it afterwards will have no effect.",
"creation_time": "Date-time at which the folder was created.",
"update_time": "Date-time at which the folder was last modified.",
}

resp.Schema = schema.Schema{
Description: descriptions["main"],
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Description: descriptions["id"],
Computed: true,
},
"container_id": schema.StringAttribute{
Description: descriptions["container_id"],
Validators: []validator.String{
validate.NoSeparator(),
},
Required: true,
},
"folder_id": schema.StringAttribute{
Description: descriptions["folder_id"],
Computed: true,
Validators: []validator.String{
validate.UUID(),
},
},
"parent_container_id": schema.StringAttribute{
Description: descriptions["parent_container_id"],
Computed: true,
Validators: []validator.String{
validate.NoSeparator(),
},
},
"name": schema.StringAttribute{
Description: descriptions["name"],
Computed: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
stringvalidator.LengthAtMost(63),
},
},
"labels": schema.MapAttribute{
Description: descriptions["labels"],
ElementType: types.StringType,
Computed: true,
Validators: []validator.Map{
mapvalidator.KeysAre(
stringvalidator.RegexMatches(
regexp.MustCompile(`[A-ZÄÜÖa-zäüöß0-9_-]{1,64}`),
"must match expression"),
),
mapvalidator.ValueStringsAre(
stringvalidator.RegexMatches(
regexp.MustCompile(`[A-ZÄÜÖa-zäüöß0-9_-]{1,64}`),
"must match expression"),
),
},
},
"creation_time": schema.StringAttribute{
Description: descriptions["creation_time"],
Computed: true,
},
"update_time": schema.StringAttribute{
Description: descriptions["update_time"],
Computed: true,
},
},
}
}

// Read refreshes the Terraform state with the latest data.
func (d *folderDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform
var model Model
diags := req.Config.Get(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

containerId := model.ContainerId.ValueString()
ctx = tflog.SetField(ctx, "container_id", containerId)

folderResp, err := d.client.GetFolderDetails(ctx, containerId).Execute()
if err != nil {
utils.LogError(
ctx,
&resp.Diagnostics,
err,
"Reading folder",
fmt.Sprintf("folder with ID %q does not exist.", containerId),
map[int]string{
http.StatusForbidden: fmt.Sprintf("folder with ID %q not found or forbidden access", containerId),
},
)
resp.State.RemoveResource(ctx)
return
}

err = mapFolderDetailsFields(ctx, folderResp, &model, &resp.State)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading folder", fmt.Sprintf("Processing API response: %v", err))
return
}

diags = resp.State.Set(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "Resource Manager folder read")
}
Loading
Loading