Skip to content

Commit 5f1e4ff

Browse files
authored
feat(iaas): onboard iaas project datasource (#955)
* feat: onboard iaas project datasource
1 parent 2558c02 commit 5f1e4ff

File tree

8 files changed

+399
-3
lines changed

8 files changed

+399
-3
lines changed

docs/data-sources/iaas_project.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "stackit_iaas_project Data Source - stackit"
4+
subcategory: ""
5+
description: |-
6+
Project details. Must have a region specified in the provider configuration.
7+
---
8+
9+
# stackit_iaas_project (Data Source)
10+
11+
Project details. Must have a `region` specified in the provider configuration.
12+
13+
## Example Usage
14+
15+
```terraform
16+
data "stackit_iaas_project" "example" {
17+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
18+
}
19+
```
20+
21+
<!-- schema generated by tfplugindocs -->
22+
## Schema
23+
24+
### Required
25+
26+
- `project_id` (String) STACKIT project ID.
27+
28+
### Read-Only
29+
30+
- `area_id` (String) The area ID to which the project belongs to.
31+
- `created_at` (String) Date-time when the project was created.
32+
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`".
33+
- `internet_access` (Boolean) Specifies if the project has internet_access
34+
- `state` (String) Specifies the state of the project.
35+
- `updated_at` (String) Date-time when the project was last updated.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
data "stackit_iaas_project" "example" {
2+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
3+
}

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ require (
1515
github.com/stackitcloud/stackit-sdk-go/services/cdn v1.4.0
1616
github.com/stackitcloud/stackit-sdk-go/services/dns v0.17.1
1717
github.com/stackitcloud/stackit-sdk-go/services/git v0.7.1
18-
github.com/stackitcloud/stackit-sdk-go/services/iaas v0.29.0
18+
github.com/stackitcloud/stackit-sdk-go/services/iaas v0.29.1
1919
github.com/stackitcloud/stackit-sdk-go/services/iaasalpha v0.1.21-alpha
2020
github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v1.5.1
2121
github.com/stackitcloud/stackit-sdk-go/services/logme v0.25.1

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,8 @@ github.com/stackitcloud/stackit-sdk-go/services/dns v0.17.1 h1:CnhAMLql0MNmAeq4r
160160
github.com/stackitcloud/stackit-sdk-go/services/dns v0.17.1/go.mod h1:7Bx85knfNSBxulPdJUFuBePXNee3cO+sOTYnUG6M+iQ=
161161
github.com/stackitcloud/stackit-sdk-go/services/git v0.7.1 h1:hkFixFnBcQzU4BSIZFITc8N0gK0pUYk7mk0wdUu5Ki8=
162162
github.com/stackitcloud/stackit-sdk-go/services/git v0.7.1/go.mod h1:Ng1EzrRndG3iGXGH90AZJz//wfK+2YOyDwTnTLwX3a4=
163-
github.com/stackitcloud/stackit-sdk-go/services/iaas v0.29.0 h1:j4FKFOVkcTot8xNxpvDsPzIFyjADE4GxXF0rFE6/Uo4=
164-
github.com/stackitcloud/stackit-sdk-go/services/iaas v0.29.0/go.mod h1:b/jgJf7QHdRzU2fmZeJJtu5j0TAevDRghzcn5MyRmOI=
163+
github.com/stackitcloud/stackit-sdk-go/services/iaas v0.29.1 h1:GfE+FaeIKSVaKvgzh8Eacum+bQVyRS6ngltkh0qNGtM=
164+
github.com/stackitcloud/stackit-sdk-go/services/iaas v0.29.1/go.mod h1:b/jgJf7QHdRzU2fmZeJJtu5j0TAevDRghzcn5MyRmOI=
165165
github.com/stackitcloud/stackit-sdk-go/services/iaasalpha v0.1.21-alpha h1:m1jq6a8dbUe+suFuUNdHmM/cSehpGLUtDbK1CqLqydg=
166166
github.com/stackitcloud/stackit-sdk-go/services/iaasalpha v0.1.21-alpha/go.mod h1:Nu1b5Phsv8plgZ51+fkxPVsU91ZJ5Ayz+cthilxdmQ8=
167167
github.com/stackitcloud/stackit-sdk-go/services/loadbalancer v1.5.1 h1:OdJEs8eOfrzn9tCBDLxIyP8hX50zPfcXNYnRoQX+chs=

stackit/internal/services/iaas/iaas_acc_test.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4022,6 +4022,38 @@ func TestAccImageMax(t *testing.T) {
40224022
})
40234023
}
40244024

4025+
func TestAccProject(t *testing.T) {
4026+
projectId := testutil.ProjectId
4027+
resource.ParallelTest(t, resource.TestCase{
4028+
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
4029+
Steps: []resource.TestStep{
4030+
// Data source
4031+
{
4032+
ConfigVariables: testConfigKeyPairMin,
4033+
Config: fmt.Sprintf(`
4034+
%s
4035+
4036+
data "stackit_iaas_project" "project" {
4037+
project_id = %q
4038+
}
4039+
`,
4040+
testutil.IaaSProviderConfig(), testutil.ProjectId,
4041+
),
4042+
Check: resource.ComposeAggregateTestCheckFunc(
4043+
// Instance
4044+
resource.TestCheckResourceAttr("data.stackit_iaas_project.project", "project_id", projectId),
4045+
resource.TestCheckResourceAttr("data.stackit_iaas_project.project", "id", projectId),
4046+
resource.TestCheckResourceAttrSet("data.stackit_iaas_project.project", "area_id"),
4047+
resource.TestCheckResourceAttrSet("data.stackit_iaas_project.project", "internet_access"),
4048+
resource.TestCheckResourceAttrSet("data.stackit_iaas_project.project", "state"),
4049+
resource.TestCheckResourceAttrSet("data.stackit_iaas_project.project", "created_at"),
4050+
resource.TestCheckResourceAttrSet("data.stackit_iaas_project.project", "updated_at"),
4051+
),
4052+
},
4053+
},
4054+
})
4055+
}
4056+
40254057
func testAccCheckDestroy(s *terraform.State) error {
40264058
checkFunctions := []func(s *terraform.State) error{
40274059
testAccCheckNetworkV1Destroy,
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
package project
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"github.com/hashicorp/terraform-plugin-framework/datasource"
9+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
10+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
11+
"github.com/hashicorp/terraform-plugin-framework/types"
12+
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
13+
"github.com/hashicorp/terraform-plugin-log/tflog"
14+
"github.com/stackitcloud/stackit-sdk-go/services/iaas"
15+
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
16+
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
17+
iaasUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/iaas/utils"
18+
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
19+
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"
20+
)
21+
22+
var (
23+
_ datasource.DataSourceWithConfigure = &projectDataSource{}
24+
)
25+
26+
type DatasourceModel struct {
27+
Id types.String `tfsdk:"id"` // needed by TF
28+
ProjectId types.String `tfsdk:"project_id"`
29+
AreaId types.String `tfsdk:"area_id"`
30+
InternetAccess types.Bool `tfsdk:"internet_access"`
31+
State types.String `tfsdk:"state"`
32+
CreatedAt types.String `tfsdk:"created_at"`
33+
UpdatedAt types.String `tfsdk:"updated_at"`
34+
}
35+
36+
// NewProjectDataSource is a helper function to simplify the provider implementation.
37+
func NewProjectDataSource() datasource.DataSource {
38+
return &projectDataSource{}
39+
}
40+
41+
// projectDatasource is the data source implementation.
42+
type projectDataSource struct {
43+
client *iaas.APIClient
44+
}
45+
46+
func (d *projectDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
47+
providerData, ok := conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics)
48+
if !ok {
49+
return
50+
}
51+
52+
apiClient := iaasUtils.ConfigureClient(ctx, &providerData, &resp.Diagnostics)
53+
if resp.Diagnostics.HasError() {
54+
return
55+
}
56+
d.client = apiClient
57+
tflog.Info(ctx, "iaas client configured")
58+
}
59+
60+
// Metadata returns the data source type name.
61+
func (d *projectDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
62+
resp.TypeName = req.ProviderTypeName + "_iaas_project"
63+
}
64+
65+
// Schema defines the schema for the datasource.
66+
func (d *projectDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
67+
descriptions := map[string]string{
68+
"main": "Project details. Must have a `region` specified in the provider configuration.",
69+
"id": "Terraform's internal resource ID. It is structured as \"`project_id`\".",
70+
"project_id": "STACKIT project ID.",
71+
"area_id": "The area ID to which the project belongs to.",
72+
"internet_access": "Specifies if the project has internet_access",
73+
"state": "Specifies the state of the project.",
74+
"created_at": "Date-time when the project was created.",
75+
"updated_at": "Date-time when the project was last updated.",
76+
}
77+
resp.Schema = schema.Schema{
78+
MarkdownDescription: descriptions["main"],
79+
Description: descriptions["main"],
80+
Attributes: map[string]schema.Attribute{
81+
"id": schema.StringAttribute{
82+
Description: descriptions["id"],
83+
Computed: true,
84+
},
85+
"project_id": schema.StringAttribute{
86+
Description: descriptions["project_id"],
87+
Required: true,
88+
Validators: []validator.String{
89+
validate.UUID(),
90+
validate.NoSeparator(),
91+
},
92+
},
93+
"area_id": schema.StringAttribute{
94+
Description: descriptions["area_id"],
95+
Computed: true,
96+
},
97+
"internet_access": schema.BoolAttribute{
98+
Description: descriptions["internet_access"],
99+
Computed: true,
100+
},
101+
"state": schema.StringAttribute{
102+
Description: descriptions["state"],
103+
Computed: true,
104+
},
105+
"created_at": schema.StringAttribute{
106+
Description: descriptions["created_at"],
107+
Computed: true,
108+
},
109+
"updated_at": schema.StringAttribute{
110+
Description: descriptions["updated_at"],
111+
Computed: true,
112+
},
113+
},
114+
}
115+
}
116+
117+
// Read refreshes the Terraform state with the latest data.
118+
func (d *projectDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform
119+
var model DatasourceModel
120+
diags := req.Config.Get(ctx, &model)
121+
resp.Diagnostics.Append(diags...)
122+
if resp.Diagnostics.HasError() {
123+
return
124+
}
125+
projectId := model.ProjectId.ValueString()
126+
ctx = tflog.SetField(ctx, "project_id", projectId)
127+
128+
projectResp, err := d.client.GetProjectDetailsExecute(ctx, projectId)
129+
if err != nil {
130+
utils.LogError(
131+
ctx,
132+
&resp.Diagnostics,
133+
err,
134+
"Reading project",
135+
fmt.Sprintf("Project with ID %q does not exists.", projectId),
136+
nil,
137+
)
138+
resp.State.RemoveResource(ctx)
139+
return
140+
}
141+
142+
// Map response body to schema
143+
err = mapDataSourceFields(projectResp, &model)
144+
if err != nil {
145+
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading project", fmt.Sprintf("Process API payload: %v", err))
146+
return
147+
}
148+
// Set refreshed state
149+
diags = resp.State.Set(ctx, &model)
150+
resp.Diagnostics.Append(diags...)
151+
if resp.Diagnostics.HasError() {
152+
return
153+
}
154+
tflog.Info(ctx, "project read")
155+
}
156+
157+
func mapDataSourceFields(projectResp *iaas.Project, model *DatasourceModel) error {
158+
if projectResp == nil {
159+
return fmt.Errorf("response input is nil")
160+
}
161+
if model == nil {
162+
return fmt.Errorf("model input is nil")
163+
}
164+
165+
var projectId string
166+
if model.ProjectId.ValueString() != "" {
167+
projectId = model.ProjectId.ValueString()
168+
} else if projectResp.ProjectId != nil {
169+
projectId = *projectResp.ProjectId
170+
} else {
171+
return fmt.Errorf("project id is not present")
172+
}
173+
174+
model.Id = utils.BuildInternalTerraformId(projectId)
175+
model.ProjectId = types.StringValue(projectId)
176+
177+
var areaId basetypes.StringValue
178+
if projectResp.AreaId != nil {
179+
if projectResp.AreaId.String != nil {
180+
areaId = types.StringPointerValue(projectResp.AreaId.String)
181+
} else if projectResp.AreaId.StaticAreaID != nil {
182+
areaId = types.StringValue(string(*projectResp.AreaId.StaticAreaID))
183+
}
184+
}
185+
186+
var createdAt basetypes.StringValue
187+
if projectResp.CreatedAt != nil {
188+
createdAtValue := *projectResp.CreatedAt
189+
createdAt = types.StringValue(createdAtValue.Format(time.RFC3339))
190+
}
191+
192+
var updatedAt basetypes.StringValue
193+
if projectResp.UpdatedAt != nil {
194+
updatedAtValue := *projectResp.UpdatedAt
195+
updatedAt = types.StringValue(updatedAtValue.Format(time.RFC3339))
196+
}
197+
198+
model.AreaId = areaId
199+
model.InternetAccess = types.BoolPointerValue(projectResp.InternetAccess)
200+
model.State = types.StringPointerValue(projectResp.State)
201+
model.CreatedAt = createdAt
202+
model.UpdatedAt = updatedAt
203+
return nil
204+
}

0 commit comments

Comments
 (0)