Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
35 changes: 35 additions & 0 deletions docs/data-sources/iaas_project.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "stackit_iaas_project Data Source - stackit"
subcategory: ""
description: |-
Project details. Must have a region specified in the provider configuration.
---

# stackit_iaas_project (Data Source)

Project details. Must have a `region` specified in the provider configuration.

## Example Usage

```terraform
data "stackit_iaas_project" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
```

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

### Required

- `project_id` (String) STACKIT project ID.

### Read-Only

- `area_id` (String) The area ID to which the project belongs to.
- `created_at` (String) Date-time when the project was created.
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`".
- `internet_access` (Boolean) Specifies if the project has internet_access
- `state` (String) Specifies the state of the project.
- `updated_at` (String) Date-time when the project was last updated.
3 changes: 3 additions & 0 deletions examples/data-sources/stackit_iaas_project/data-source.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
data "stackit_iaas_project" "example" {
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
32 changes: 32 additions & 0 deletions stackit/internal/services/iaas/iaas_acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4022,6 +4022,38 @@ func TestAccImageMax(t *testing.T) {
})
}

func TestAccProject(t *testing.T) {
projectId := testutil.ProjectId
resource.ParallelTest(t, resource.TestCase{
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
// Data source
{
ConfigVariables: testConfigKeyPairMin,
Config: fmt.Sprintf(`
%s

data "stackit_iaas_project" "project" {
project_id = %q
}
`,
testutil.IaaSProviderConfig(), testutil.ProjectId,
),
Check: resource.ComposeAggregateTestCheckFunc(
// Instance
resource.TestCheckResourceAttr("data.stackit_iaas_project.project", "project_id", projectId),
resource.TestCheckResourceAttr("data.stackit_iaas_project.project", "id", projectId),
resource.TestCheckResourceAttrSet("data.stackit_iaas_project.project", "area_id"),
resource.TestCheckResourceAttrSet("data.stackit_iaas_project.project", "internet_access"),
resource.TestCheckResourceAttrSet("data.stackit_iaas_project.project", "state"),
resource.TestCheckResourceAttrSet("data.stackit_iaas_project.project", "created_at"),
resource.TestCheckResourceAttrSet("data.stackit_iaas_project.project", "updated_at"),
),
},
},
})
}

func testAccCheckDestroy(s *terraform.State) error {
checkFunctions := []func(s *terraform.State) error{
testAccCheckNetworkV1Destroy,
Expand Down
204 changes: 204 additions & 0 deletions stackit/internal/services/iaas/project/datasource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
package project

import (
"context"
"fmt"
"time"

"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-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/services/iaas"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
iaasUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
)

var (
_ datasource.DataSourceWithConfigure = &projectDataSource{}
)

type DatasourceModel struct {
Id types.String `tfsdk:"id"` // needed by TF
ProjectId types.String `tfsdk:"project_id"`
AreaId types.String `tfsdk:"area_id"`
InternetAccess types.Bool `tfsdk:"internet_access"`
State types.String `tfsdk:"state"`
CreatedAt types.String `tfsdk:"created_at"`
UpdatedAt types.String `tfsdk:"updated_at"`
}

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

// projectDatasource is the data source implementation.
type projectDataSource struct {
client *iaas.APIClient
}

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

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

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

// Schema defines the schema for the datasource.
func (d *projectDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
descriptions := map[string]string{
"main": "Project details. Must have a `region` specified in the provider configuration.",
"id": "Terraform's internal resource ID. It is structured as \"`project_id`\".",
"project_id": "STACKIT project ID.",
"area_id": "The area ID to which the project belongs to.",
"internet_access": "Specifies if the project has internet_access",
"state": "Specifies the state of the project.",
"created_at": "Date-time when the project was created.",
"updated_at": "Date-time when the project was last updated.",
}
resp.Schema = schema.Schema{
MarkdownDescription: descriptions["main"],
Description: descriptions["main"],
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Description: descriptions["id"],
Computed: true,
},
"project_id": schema.StringAttribute{
Description: descriptions["project_id"],
Required: true,
Validators: []validator.String{
validate.UUID(),
validate.NoSeparator(),
},
},
"area_id": schema.StringAttribute{
Description: descriptions["area_id"],
Computed: true,
},
"internet_access": schema.BoolAttribute{
Description: descriptions["internet_access"],
Computed: true,
},
"state": schema.StringAttribute{
Description: descriptions["state"],
Computed: true,
},
"created_at": schema.StringAttribute{
Description: descriptions["created_at"],
Computed: true,
},
"updated_at": schema.StringAttribute{
Description: descriptions["updated_at"],
Computed: true,
},
},
}
}

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

projectResp, err := d.client.GetProjectDetailsExecute(ctx, projectId)
if err != nil {
utils.LogError(
ctx,
&resp.Diagnostics,
err,
"Reading project",
fmt.Sprintf("Project with ID %q does not exists.", projectId),
nil,
)
resp.State.RemoveResource(ctx)
return
}

// Map response body to schema
err = mapDataSourceFields(projectResp, &model)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading project", fmt.Sprintf("Process API payload: %v", err))
return
}
// Set refreshed state
diags = resp.State.Set(ctx, &model)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "project read")
}

func mapDataSourceFields(projectResp *iaas.Project, model *DatasourceModel) error {
if projectResp == nil {
return fmt.Errorf("response input is nil")
}
if model == nil {
return fmt.Errorf("model input is nil")
}

var projectId string
if model.ProjectId.ValueString() != "" {
projectId = model.ProjectId.ValueString()
} else if projectResp.ProjectId != nil {
projectId = *projectResp.ProjectId
} else {
return fmt.Errorf("project id is not present")
}

model.Id = utils.BuildInternalTerraformId(projectId)
model.ProjectId = types.StringValue(projectId)

var areaId basetypes.StringValue
if projectResp.AreaId != nil {
if projectResp.AreaId.String != nil {
areaId = types.StringPointerValue(projectResp.AreaId.String)
} else if projectResp.AreaId.StaticAreaID != nil {
areaId = types.StringValue(string(*projectResp.AreaId.StaticAreaID))
}
}

var createdAt basetypes.StringValue
if projectResp.CreatedAt != nil {
createdAtValue := *projectResp.CreatedAt
createdAt = types.StringValue(createdAtValue.Format(time.RFC3339))
}

var updatedAt basetypes.StringValue
if projectResp.UpdatedAt != nil {
updatedAtValue := *projectResp.UpdatedAt
updatedAt = types.StringValue(updatedAtValue.Format(time.RFC3339))
}

model.AreaId = areaId
model.InternetAccess = types.BoolPointerValue(projectResp.InternetAccess)
model.State = types.StringPointerValue(projectResp.State)
model.CreatedAt = createdAt
model.UpdatedAt = updatedAt
return nil
}
Loading
Loading