Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/validate"

"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/stackitcloud/stackit-sdk-go/services/objectstorage"
objectstorage "github.com/stackitcloud/stackit-sdk-go/services/objectstorage/v2api"
)

// Ensure the implementation satisfies the expected interfaces.
Expand Down Expand Up @@ -129,7 +129,7 @@ func (r *bucketDataSource) Read(ctx context.Context, req datasource.ReadRequest,
ctx = tflog.SetField(ctx, "name", bucketName)
ctx = tflog.SetField(ctx, "region", region)

bucketResp, err := r.client.GetBucket(ctx, projectId, region, bucketName).Execute()
bucketResp, err := r.client.DefaultAPI.GetBucket(ctx, projectId, region, bucketName).Execute()
if err != nil {
utils.LogError(
ctx,
Expand Down
33 changes: 13 additions & 20 deletions stackit/internal/services/objectstorage/bucket/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/objectstorage"
"github.com/stackitcloud/stackit-sdk-go/services/objectstorage/wait"
objectstorage "github.com/stackitcloud/stackit-sdk-go/services/objectstorage/v2api"
"github.com/stackitcloud/stackit-sdk-go/services/objectstorage/v2api/wait"
)

// Ensure the implementation satisfies the expected interfaces.
Expand Down Expand Up @@ -202,14 +202,14 @@ func (r *bucketResource) Create(ctx context.Context, req resource.CreateRequest,
ctx = tflog.SetField(ctx, "region", region)

// Handle project init
err := enableProject(ctx, &model, region, r.client)
err := enableProject(ctx, &model, region, r.client.DefaultAPI)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating bucket", fmt.Sprintf("Enabling object storage project before creation: %v", err))
return
}

// Create new bucket
_, err = r.client.CreateBucket(ctx, projectId, region, bucketName).ObjectLockEnabled(model.ObjectLock.ValueBool()).Execute()
_, err = r.client.DefaultAPI.CreateBucket(ctx, projectId, region, bucketName).ObjectLockEnabled(model.ObjectLock.ValueBool()).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating bucket", fmt.Sprintf("Calling API: %v", err))
return
Expand All @@ -227,7 +227,7 @@ func (r *bucketResource) Create(ctx context.Context, req resource.CreateRequest,
return
}

waitResp, err := wait.CreateBucketWaitHandler(ctx, r.client, projectId, region, bucketName).WaitWithContext(ctx)
waitResp, err := wait.CreateBucketWaitHandler(ctx, r.client.DefaultAPI, projectId, region, bucketName).WaitWithContext(ctx)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating bucket", fmt.Sprintf("Bucket creation waiting: %v", err))
return
Expand Down Expand Up @@ -266,7 +266,7 @@ func (r *bucketResource) Read(ctx context.Context, req resource.ReadRequest, res
ctx = tflog.SetField(ctx, "name", bucketName)
ctx = tflog.SetField(ctx, "region", region)

bucketResp, err := r.client.GetBucket(ctx, projectId, region, bucketName).Execute()
bucketResp, err := r.client.DefaultAPI.GetBucket(ctx, projectId, region, bucketName).Execute()
if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
if ok && oapiErr.StatusCode == http.StatusNotFound {
Expand Down Expand Up @@ -321,7 +321,7 @@ func (r *bucketResource) Delete(ctx context.Context, req resource.DeleteRequest,
ctx = tflog.SetField(ctx, "region", region)

// Delete existing bucket
_, err := r.client.DeleteBucket(ctx, projectId, region, bucketName).Execute()
_, err := r.client.DefaultAPI.DeleteBucket(ctx, projectId, region, bucketName).Execute()
if err != nil {
var oapiErr *oapierror.GenericOpenAPIError
if errors.As(err, &oapiErr) {
Expand All @@ -335,7 +335,7 @@ func (r *bucketResource) Delete(ctx context.Context, req resource.DeleteRequest,

ctx = core.LogResponse(ctx)

_, err = wait.DeleteBucketWaitHandler(ctx, r.client, projectId, region, bucketName).WaitWithContext(ctx)
_, err = wait.DeleteBucketWaitHandler(ctx, r.client.DefaultAPI, projectId, region, bucketName).WaitWithContext(ctx)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting bucket", fmt.Sprintf("Bucket deletion waiting: %v", err))
return
Expand Down Expand Up @@ -368,32 +368,25 @@ func mapFields(bucketResp *objectstorage.GetBucketResponse, model *Model, region
if bucketResp == nil {
return fmt.Errorf("response input is nil")
}
if bucketResp.Bucket == nil {
return fmt.Errorf("response bucket is nil")
}
if model == nil {
return fmt.Errorf("model input is nil")
}
bucket := bucketResp.Bucket

model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), region, model.Name.ValueString())
model.URLPathStyle = types.StringPointerValue(bucket.UrlPathStyle)
model.URLVirtualHostedStyle = types.StringPointerValue(bucket.UrlVirtualHostedStyle)
model.URLPathStyle = types.StringValue(bucket.UrlPathStyle)
model.URLVirtualHostedStyle = types.StringValue(bucket.UrlVirtualHostedStyle)
model.Region = types.StringValue(region)
model.ObjectLock = types.BoolPointerValue(bucket.ObjectLockEnabled)
model.ObjectLock = types.BoolValue(bucket.ObjectLockEnabled)
return nil
}

type objectStorageClient interface {
EnableServiceExecute(ctx context.Context, projectId, region string) (*objectstorage.ProjectStatus, error)
}

// enableProject enables object storage for the specified project. If the project is already enabled, nothing happens
func enableProject(ctx context.Context, model *Model, region string, client objectStorageClient) error {
func enableProject(ctx context.Context, model *Model, region string, client objectstorage.DefaultAPI) error {
projectId := model.ProjectId.ValueString()

// From the object storage OAS: Creation will also be successful if the project is already enabled, but will not create a duplicate
_, err := client.EnableServiceExecute(ctx, projectId, region)
_, err := client.EnableService(ctx, projectId, region).Execute()
if err != nil {
return fmt.Errorf("failed to create object storage project: %w", err)
}
Expand Down
53 changes: 26 additions & 27 deletions stackit/internal/services/objectstorage/bucket/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,23 @@
"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/core/utils"
"github.com/stackitcloud/stackit-sdk-go/services/objectstorage"
objectstorage "github.com/stackitcloud/stackit-sdk-go/services/objectstorage/v2api"
)

type objectStorageClientMocked struct {
type mockSettings struct {
returnError bool
}

func (c *objectStorageClientMocked) EnableServiceExecute(_ context.Context, projectId, _ string) (*objectstorage.ProjectStatus, error) {
if c.returnError {
return nil, fmt.Errorf("create project failed")
}
func newAPIMock(settings *mockSettings) objectstorage.DefaultAPI {
return &objectstorage.DefaultAPIServiceMock{
EnableServiceExecuteMock: utils.Ptr(func(r objectstorage.ApiEnableServiceRequest) (*objectstorage.ProjectStatus, error) {

Check failure on line 21 in stackit/internal/services/objectstorage/bucket/resource_test.go

View workflow job for this annotation

GitHub Actions / CI

unused-parameter: parameter 'r' seems to be unused, consider removing or renaming it as _ (revive)
if settings.returnError {
return nil, fmt.Errorf("create project failed")
}

return &objectstorage.ProjectStatus{
Project: utils.Ptr(projectId),
}, nil
return &objectstorage.ProjectStatus{}, nil
}),
}
}

func TestMapFields(t *testing.T) {
Expand All @@ -38,25 +40,26 @@
{
"default_values",
&objectstorage.GetBucketResponse{
Bucket: &objectstorage.Bucket{},
Bucket: objectstorage.Bucket{},
},
Model{
Id: types.StringValue(id),
Name: types.StringValue("bname"),
ProjectId: types.StringValue("pid"),
URLPathStyle: types.StringNull(),
URLVirtualHostedStyle: types.StringNull(),
URLPathStyle: types.StringValue(""),
URLVirtualHostedStyle: types.StringValue(""),
Region: types.StringValue("eu01"),
ObjectLock: types.BoolValue(false),
},
true,
},
{
"simple_values",
&objectstorage.GetBucketResponse{
Bucket: &objectstorage.Bucket{
UrlPathStyle: utils.Ptr("url/path/style"),
UrlVirtualHostedStyle: utils.Ptr("url/virtual/hosted/style"),
ObjectLockEnabled: utils.Ptr(true),
Bucket: objectstorage.Bucket{
UrlPathStyle: "url/path/style",
UrlVirtualHostedStyle: "url/virtual/hosted/style",
ObjectLockEnabled: true,
},
},
Model{
Expand All @@ -73,9 +76,9 @@
{
"empty_strings",
&objectstorage.GetBucketResponse{
Bucket: &objectstorage.Bucket{
UrlPathStyle: utils.Ptr(""),
UrlVirtualHostedStyle: utils.Ptr(""),
Bucket: objectstorage.Bucket{
UrlPathStyle: "",
UrlVirtualHostedStyle: "",
},
},
Model{
Expand All @@ -85,6 +88,7 @@
URLPathStyle: types.StringValue(""),
URLVirtualHostedStyle: types.StringValue(""),
Region: types.StringValue("eu01"),
ObjectLock: types.BoolValue(false),
},
true,
},
Expand All @@ -94,12 +98,6 @@
Model{},
false,
},
{
"no_bucket",
&objectstorage.GetBucketResponse{},
Model{},
false,
},
}
for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
Expand Down Expand Up @@ -143,9 +141,10 @@
}
for _, tt := range tests {
t.Run(tt.description, func(t *testing.T) {
client := &objectStorageClientMocked{
client := newAPIMock(&mockSettings{
returnError: tt.enableFails,
}
})

err := enableProject(context.Background(), &Model{}, "eu01", client)
if !tt.isValid && err == nil {
t.Fatalf("Should have failed")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/services/objectstorage"
objectstorage "github.com/stackitcloud/stackit-sdk-go/services/objectstorage/v2api"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
objectstorageUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/objectstorage/utils"
Expand Down Expand Up @@ -79,7 +79,7 @@ func (d *compliancelockDataSource) Schema(_ context.Context, _ datasource.Schema
validate.NoSeparator(),
},
},
"max_retention_days": schema.Int64Attribute{
"max_retention_days": schema.Int32Attribute{
Description: descriptions["max_retention_days"],
Computed: true,
},
Expand Down Expand Up @@ -109,7 +109,7 @@ func (d *compliancelockDataSource) Read(ctx context.Context, req datasource.Read
ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "region", region)

complianceResp, err := d.client.GetComplianceLock(ctx, projectId, region).Execute()
complianceResp, err := d.client.DefaultAPI.GetComplianceLock(ctx, projectId, region).Execute()
if err != nil {
utils.LogError(
ctx,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
"github.com/stackitcloud/stackit-sdk-go/services/objectstorage"
objectstorage "github.com/stackitcloud/stackit-sdk-go/services/objectstorage/v2api"
"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/utils"
Expand All @@ -33,7 +33,7 @@ type Model struct {
Id types.String `tfsdk:"id"` // needed by TF
ProjectId types.String `tfsdk:"project_id"`
Region types.String `tfsdk:"region"`
MaxRetentionDays types.Int64 `tfsdk:"max_retention_days"`
MaxRetentionDays types.Int32 `tfsdk:"max_retention_days"`
}

// NewComplianceLockResource is a helper function to simplify the provider implementation.
Expand Down Expand Up @@ -129,7 +129,7 @@ func (r *compliancelockResource) Schema(_ context.Context, _ resource.SchemaRequ
validate.NoSeparator(),
},
},
"max_retention_days": schema.Int64Attribute{
"max_retention_days": schema.Int32Attribute{
Description: descriptions["max_retention_days"],
Computed: true,
},
Expand Down Expand Up @@ -163,7 +163,7 @@ func (r *compliancelockResource) Create(ctx context.Context, req resource.Create
ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "region", region)

complianceResp, err := r.client.CreateComplianceLock(ctx, projectId, region).Execute()
complianceResp, err := r.client.DefaultAPI.CreateComplianceLock(ctx, projectId, region).Execute()
if err != nil {
var oapiErr *oapierror.GenericOpenAPIError
ok := errors.As(err, &oapiErr)
Expand All @@ -174,7 +174,7 @@ func (r *compliancelockResource) Create(ctx context.Context, req resource.Create
}

tflog.Info(ctx, "Compliance lock is already enabled for this project. Please check duplicate resources.")
complianceResp, err = r.client.GetComplianceLock(ctx, projectId, region).Execute()
complianceResp, err = r.client.DefaultAPI.GetComplianceLock(ctx, projectId, region).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading compliance lock", fmt.Sprintf("Calling API: %v", err))
return
Expand Down Expand Up @@ -212,7 +212,7 @@ func (r *compliancelockResource) Read(ctx context.Context, req resource.ReadRequ
ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "region", region)

complianceResp, err := r.client.GetComplianceLock(ctx, projectId, region).Execute()
complianceResp, err := r.client.DefaultAPI.GetComplianceLock(ctx, projectId, region).Execute()
if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
if ok && oapiErr.StatusCode == http.StatusNotFound {
Expand Down Expand Up @@ -264,7 +264,7 @@ func (r *compliancelockResource) Delete(ctx context.Context, req resource.Delete
ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "region", region)

_, err := r.client.DeleteComplianceLock(ctx, projectId, region).Execute()
_, err := r.client.DefaultAPI.DeleteComplianceLock(ctx, projectId, region).Execute()
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting compliance lock", fmt.Sprintf("Calling API: %v", err))
return
Expand All @@ -285,6 +285,6 @@ func mapFields(complianceResp *objectstorage.ComplianceLockResponse, model *Mode

model.Id = utils.BuildInternalTerraformId(model.ProjectId.ValueString(), region)
model.Region = types.StringValue(region)
model.MaxRetentionDays = types.Int64PointerValue(complianceResp.MaxRetentionDays)
model.MaxRetentionDays = types.Int32Value(complianceResp.MaxRetentionDays)
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import (

"github.com/google/go-cmp/cmp"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/stackitcloud/stackit-sdk-go/services/objectstorage"
objectstorage "github.com/stackitcloud/stackit-sdk-go/services/objectstorage/v2api"
)

func TestMapFields(t *testing.T) {
const testRegion = "eu01"
id := fmt.Sprintf("%s,%s", "pid", testRegion)
retentionDays := int64(30)
retentionDays := int32(30)
tests := []struct {
description string
input *objectstorage.ComplianceLockResponse
Expand All @@ -23,22 +23,23 @@ func TestMapFields(t *testing.T) {
"default_values",
&objectstorage.ComplianceLockResponse{},
Model{
Id: types.StringValue(id),
ProjectId: types.StringValue("pid"),
Region: types.StringValue("eu01"),
Id: types.StringValue(id),
ProjectId: types.StringValue("pid"),
Region: types.StringValue("eu01"),
MaxRetentionDays: types.Int32Value(0),
},
true,
},
{
"simple_values",
&objectstorage.ComplianceLockResponse{
MaxRetentionDays: &retentionDays,
MaxRetentionDays: retentionDays,
},
Model{
Id: types.StringValue(id),
ProjectId: types.StringValue("pid"),
Region: types.StringValue("eu01"),
MaxRetentionDays: types.Int64Value(retentionDays),
MaxRetentionDays: types.Int32Value(retentionDays),
},
true,
},
Expand Down
Loading
Loading