diff --git a/docs/data-sources/objectstorage_bucket.md b/docs/data-sources/objectstorage_bucket.md index 81b8479c..bdf4fee2 100644 --- a/docs/data-sources/objectstorage_bucket.md +++ b/docs/data-sources/objectstorage_bucket.md @@ -33,6 +33,6 @@ data "stackit_objectstorage_bucket" "example" { ### Read-Only -- `id` (String) Terraform's internal data source identifier. It is structured as "`project_id`,`name`". +- `id` (String) Terraform's internal data source identifier. It is structured as "`project_id`,`region`,`name`". - `url_path_style` (String) - `url_virtual_hosted_style` (String) diff --git a/docs/data-sources/objectstorage_credential.md b/docs/data-sources/objectstorage_credential.md index aa682ca6..e7bfb035 100644 --- a/docs/data-sources/objectstorage_credential.md +++ b/docs/data-sources/objectstorage_credential.md @@ -36,5 +36,5 @@ data "stackit_objectstorage_credential" "example" { ### Read-Only - `expiration_timestamp` (String) -- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`credentials_group_id`,`credential_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`region`,`credentials_group_id`,`credential_id`". - `name` (String) diff --git a/docs/data-sources/objectstorage_credentials_group.md b/docs/data-sources/objectstorage_credentials_group.md index c49c0924..e5934d3b 100644 --- a/docs/data-sources/objectstorage_credentials_group.md +++ b/docs/data-sources/objectstorage_credentials_group.md @@ -24,15 +24,15 @@ data "stackit_objectstorage_credentials_group" "example" { ### Required +- `credentials_group_id` (String) The credentials group ID. - `project_id` (String) Object Storage Project ID to which the credentials group is associated. ### Optional -- `credentials_group_id` (String) The credentials group ID. -- `name` (String) The credentials group's display name. - `region` (String) The resource region. If not defined, the provider region is used. ### Read-Only -- `id` (String) Terraform's internal data source identifier. It is structured as "`project_id`,`credentials_group_id`". +- `id` (String) Terraform's internal data source identifier. It is structured as "`project_id`,`region`,`credentials_group_id`". +- `name` (String) The credentials group's display name. - `urn` (String) Credentials group uniform resource name (URN) diff --git a/docs/resources/objectstorage_bucket.md b/docs/resources/objectstorage_bucket.md index 0ec6b087..9298ffc5 100644 --- a/docs/resources/objectstorage_bucket.md +++ b/docs/resources/objectstorage_bucket.md @@ -33,6 +33,6 @@ resource "stackit_objectstorage_bucket" "example" { ### Read-Only -- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`name`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`region`,`name`". - `url_path_style` (String) - `url_virtual_hosted_style` (String) diff --git a/docs/resources/objectstorage_credential.md b/docs/resources/objectstorage_credential.md index b702a62b..9d9f5980 100644 --- a/docs/resources/objectstorage_credential.md +++ b/docs/resources/objectstorage_credential.md @@ -37,6 +37,6 @@ resource "stackit_objectstorage_credential" "example" { - `access_key` (String) - `credential_id` (String) The credential ID. -- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`credentials_group_id`,`credential_id`". +- `id` (String) Terraform's internal resource identifier. It is structured as "`project_id`,`region`,`credentials_group_id`,`credential_id`". - `name` (String) - `secret_access_key` (String, Sensitive) diff --git a/docs/resources/objectstorage_credentials_group.md b/docs/resources/objectstorage_credentials_group.md index 170655f8..67ec71a6 100644 --- a/docs/resources/objectstorage_credentials_group.md +++ b/docs/resources/objectstorage_credentials_group.md @@ -34,5 +34,5 @@ resource "stackit_objectstorage_credentials_group" "example" { ### Read-Only - `credentials_group_id` (String) The credentials group ID -- `id` (String) Terraform's internal data source identifier. It is structured as "`project_id`,`credentials_group_id`". +- `id` (String) Terraform's internal data source identifier. It is structured as "`project_id`,`region`,`credentials_group_id`". - `urn` (String) Credentials group uniform resource name (URN) diff --git a/stackit/internal/services/objectstorage/bucket/datasource.go b/stackit/internal/services/objectstorage/bucket/datasource.go index e99bcf41..3b5d71d7 100644 --- a/stackit/internal/services/objectstorage/bucket/datasource.go +++ b/stackit/internal/services/objectstorage/bucket/datasource.go @@ -60,7 +60,7 @@ func (r *bucketDataSource) Configure(ctx context.Context, req datasource.Configu func (r *bucketDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ "main": "ObjectStorage bucket data source schema. Must have a `region` specified in the provider configuration.", - "id": "Terraform's internal data source identifier. It is structured as \"`project_id`,`name`\".", + "id": "Terraform's internal data source identifier. It is structured as \"`project_id`,`region`,`name`\".", "name": "The bucket name. It must be DNS conform.", "project_id": "STACKIT Project ID to which the bucket is associated.", "url_path_style": "URL in path style.", diff --git a/stackit/internal/services/objectstorage/bucket/resource.go b/stackit/internal/services/objectstorage/bucket/resource.go index 110813df..1d11f8d5 100644 --- a/stackit/internal/services/objectstorage/bucket/resource.go +++ b/stackit/internal/services/objectstorage/bucket/resource.go @@ -109,7 +109,7 @@ func (r *bucketResource) Configure(ctx context.Context, req resource.ConfigureRe func (r *bucketResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "ObjectStorage bucket resource schema. Must have a `region` specified in the provider configuration. If you are creating `credentialsgroup` and `bucket` resources simultaneously, please include the `depends_on` field so that they are created sequentially. This prevents errors from concurrent calls to the service enablement that is done in the background.", - "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`name`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`region`,`name`\".", "name": "The bucket name. It must be DNS conform.", "project_id": "STACKIT Project ID to which the bucket is associated.", "url_path_style": "URL in path style.", @@ -304,16 +304,17 @@ func (r *bucketResource) Delete(ctx context.Context, req resource.DeleteRequest, // The expected format of the resource import identifier is: project_id,name func (r *bucketResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) - if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { + if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, "Error importing bucket", - fmt.Sprintf("Expected import identifier with format [project_id],[name], got %q", req.ID), + fmt.Sprintf("Expected import identifier with format [project_id],[region],[name], got %q", req.ID), ) return } resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("name"), idParts[1])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("name"), idParts[2])...) tflog.Info(ctx, "ObjectStorage bucket state imported") } @@ -331,6 +332,7 @@ func mapFields(bucketResp *objectstorage.GetBucketResponse, model *Model, region idParts := []string{ model.ProjectId.ValueString(), + region, model.Name.ValueString(), } model.Id = types.StringValue( diff --git a/stackit/internal/services/objectstorage/bucket/resource_test.go b/stackit/internal/services/objectstorage/bucket/resource_test.go index 45b130ae..876e2fd5 100644 --- a/stackit/internal/services/objectstorage/bucket/resource_test.go +++ b/stackit/internal/services/objectstorage/bucket/resource_test.go @@ -27,6 +27,8 @@ func (c *objectStorageClientMocked) EnableServiceExecute(_ context.Context, proj } func TestMapFields(t *testing.T) { + const testRegion = "eu01" + id := fmt.Sprintf("%s,%s,%s", "pid", testRegion, "bname") tests := []struct { description string input *objectstorage.GetBucketResponse @@ -39,7 +41,7 @@ func TestMapFields(t *testing.T) { Bucket: &objectstorage.Bucket{}, }, Model{ - Id: types.StringValue("pid,bname"), + Id: types.StringValue(id), Name: types.StringValue("bname"), ProjectId: types.StringValue("pid"), URLPathStyle: types.StringNull(), @@ -57,7 +59,7 @@ func TestMapFields(t *testing.T) { }, }, Model{ - Id: types.StringValue("pid,bname"), + Id: types.StringValue(id), Name: types.StringValue("bname"), ProjectId: types.StringValue("pid"), URLPathStyle: types.StringValue("url/path/style"), @@ -75,7 +77,7 @@ func TestMapFields(t *testing.T) { }, }, Model{ - Id: types.StringValue("pid,bname"), + Id: types.StringValue(id), Name: types.StringValue("bname"), ProjectId: types.StringValue("pid"), URLPathStyle: types.StringValue(""), diff --git a/stackit/internal/services/objectstorage/credential/datasource.go b/stackit/internal/services/objectstorage/credential/datasource.go index 3ed3b4c9..85f3e95d 100644 --- a/stackit/internal/services/objectstorage/credential/datasource.go +++ b/stackit/internal/services/objectstorage/credential/datasource.go @@ -71,7 +71,7 @@ func (r *credentialDataSource) Configure(ctx context.Context, req datasource.Con func (r *credentialDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ "main": "ObjectStorage credential data source schema. Must have a `region` specified in the provider configuration.", - "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`credentials_group_id`,`credential_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`region`,`credentials_group_id`,`credential_id`\".", "credential_id": "The credential ID.", "credentials_group_id": "The credential group ID.", "project_id": "STACKIT Project ID to which the credential group is associated.", @@ -208,6 +208,7 @@ func mapDataSourceFields(credentialResp *objectstorage.AccessKey, model *DataSou idParts := []string{ model.ProjectId.ValueString(), + region, model.CredentialsGroupId.ValueString(), credentialId, } diff --git a/stackit/internal/services/objectstorage/credential/datasource_test.go b/stackit/internal/services/objectstorage/credential/datasource_test.go index d7ec8c9f..e6ba0539 100644 --- a/stackit/internal/services/objectstorage/credential/datasource_test.go +++ b/stackit/internal/services/objectstorage/credential/datasource_test.go @@ -1,6 +1,7 @@ package objectstorage import ( + "fmt" "testing" "time" @@ -13,6 +14,8 @@ import ( func TestMapDatasourceFields(t *testing.T) { now := time.Now() + const testRegion = "eu01" + id := fmt.Sprintf("%s,%s,%s", "pid", testRegion, "cgid,cid") tests := []struct { description string input *objectstorage.AccessKey @@ -23,7 +26,7 @@ func TestMapDatasourceFields(t *testing.T) { "default_values", &objectstorage.AccessKey{}, DataSourceModel{ - Id: types.StringValue("pid,cgid,cid"), + Id: types.StringValue(id), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cgid"), CredentialId: types.StringValue("cid"), @@ -40,7 +43,7 @@ func TestMapDatasourceFields(t *testing.T) { Expires: utils.Ptr(now.Format(time.RFC3339)), }, DataSourceModel{ - Id: types.StringValue("pid,cgid,cid"), + Id: types.StringValue(id), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cgid"), CredentialId: types.StringValue("cid"), @@ -56,7 +59,7 @@ func TestMapDatasourceFields(t *testing.T) { DisplayName: utils.Ptr(""), }, DataSourceModel{ - Id: types.StringValue("pid,cgid,cid"), + Id: types.StringValue(id), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cgid"), CredentialId: types.StringValue("cid"), @@ -72,7 +75,7 @@ func TestMapDatasourceFields(t *testing.T) { Expires: utils.Ptr(now.Format(time.RFC3339Nano)), }, DataSourceModel{ - Id: types.StringValue("pid,cgid,cid"), + Id: types.StringValue(id), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cgid"), CredentialId: types.StringValue("cid"), diff --git a/stackit/internal/services/objectstorage/credential/resource.go b/stackit/internal/services/objectstorage/credential/resource.go index c34daae3..967736c6 100644 --- a/stackit/internal/services/objectstorage/credential/resource.go +++ b/stackit/internal/services/objectstorage/credential/resource.go @@ -152,7 +152,7 @@ func (r *credentialResource) Configure(ctx context.Context, req resource.Configu func (r *credentialResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "ObjectStorage credential resource schema. Must have a `region` specified in the provider configuration.", - "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`credentials_group_id`,`credential_id`\".", + "id": "Terraform's internal resource identifier. It is structured as \"`project_id`,`region`,`credentials_group_id`,`credential_id`\".", "credential_id": "The credential ID.", "credentials_group_id": "The credential group ID.", "project_id": "STACKIT Project ID to which the credential group is associated.", @@ -424,17 +424,18 @@ func (r *credentialResource) Delete(ctx context.Context, req resource.DeleteRequ // The expected format of the resource import identifier is: project_id,credentials_group_id,credential_id func (r *credentialResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) - if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { + if len(idParts) != 4 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || idParts[3] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, "Error importing credential", - fmt.Sprintf("Expected import identifier with format [project_id],[credentials_group_id],[credential_id], got %q", req.ID), + fmt.Sprintf("Expected import identifier with format [project_id],[region],[credentials_group_id],[credential_id], got %q", req.ID), ) return } resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("credentials_group_id"), idParts[1])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("credential_id"), idParts[2])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("credentials_group_id"), idParts[2])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("credential_id"), idParts[3])...) tflog.Info(ctx, "ObjectStorage credential state imported") } @@ -507,6 +508,7 @@ func mapFields(credentialResp *objectstorage.CreateAccessKeyResponse, model *Mod idParts := []string{ model.ProjectId.ValueString(), + region, model.CredentialsGroupId.ValueString(), credentialId, } @@ -551,6 +553,7 @@ func readCredentials(ctx context.Context, model *Model, region string, client *o idParts := []string{ projectId, + region, credentialsGroupId, credentialId, } diff --git a/stackit/internal/services/objectstorage/credential/resource_test.go b/stackit/internal/services/objectstorage/credential/resource_test.go index c8028e2b..8728922f 100644 --- a/stackit/internal/services/objectstorage/credential/resource_test.go +++ b/stackit/internal/services/objectstorage/credential/resource_test.go @@ -32,7 +32,8 @@ func (c *objectStorageClientMocked) EnableServiceExecute(_ context.Context, proj func TestMapFields(t *testing.T) { now := time.Now() - + const testRegion = "eu01" + id := fmt.Sprintf("%s,%s,%s", "pid", testRegion, "cgid,cid") tests := []struct { description string input *objectstorage.CreateAccessKeyResponse @@ -43,7 +44,7 @@ func TestMapFields(t *testing.T) { "default_values", &objectstorage.CreateAccessKeyResponse{}, Model{ - Id: types.StringValue("pid,cgid,cid"), + Id: types.StringValue(id), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cgid"), CredentialId: types.StringValue("cid"), @@ -64,7 +65,7 @@ func TestMapFields(t *testing.T) { SecretAccessKey: utils.Ptr("secret-key"), }, Model{ - Id: types.StringValue("pid,cgid,cid"), + Id: types.StringValue(id), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cgid"), CredentialId: types.StringValue("cid"), @@ -84,7 +85,7 @@ func TestMapFields(t *testing.T) { SecretAccessKey: utils.Ptr(""), }, Model{ - Id: types.StringValue("pid,cgid,cid"), + Id: types.StringValue(id), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cgid"), CredentialId: types.StringValue("cid"), @@ -102,7 +103,7 @@ func TestMapFields(t *testing.T) { Expires: utils.Ptr(now.Format(time.RFC3339Nano)), }, Model{ - Id: types.StringValue("pid,cgid,cid"), + Id: types.StringValue(id), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cgid"), CredentialId: types.StringValue("cid"), @@ -153,6 +154,8 @@ func TestMapFields(t *testing.T) { } func TestEnableProject(t *testing.T) { + const testRegion = "eu01" + id := fmt.Sprintf("%s,%s,%s", "pid", testRegion, "cgid,cid") tests := []struct { description string expected Model @@ -162,7 +165,7 @@ func TestEnableProject(t *testing.T) { { "default_values", Model{ - Id: types.StringValue("pid,cgid,cid"), + Id: types.StringValue(id), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cgid"), CredentialId: types.StringValue("cid"), @@ -177,7 +180,7 @@ func TestEnableProject(t *testing.T) { { "error_response", Model{ - Id: types.StringValue("pid,cgid,cid"), + Id: types.StringValue(id), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cgid"), CredentialId: types.StringValue("cid"), @@ -213,7 +216,8 @@ func TestEnableProject(t *testing.T) { func TestReadCredentials(t *testing.T) { now := time.Now() - + const testRegion = "eu01" + id := fmt.Sprintf("%s,%s,%s", "pid", testRegion, "cgid,cid") tests := []struct { description string mockedResp *objectstorage.ListAccessKeysResponse @@ -238,7 +242,7 @@ func TestReadCredentials(t *testing.T) { }, }, Model{ - Id: types.StringValue("pid,cgid,cid"), + Id: types.StringValue(id), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cgid"), CredentialId: types.StringValue("cid"), @@ -274,7 +278,7 @@ func TestReadCredentials(t *testing.T) { }, }, Model{ - Id: types.StringValue("pid,cgid,cid"), + Id: types.StringValue(id), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cgid"), CredentialId: types.StringValue("cid"), @@ -310,7 +314,7 @@ func TestReadCredentials(t *testing.T) { }, }, Model{ - Id: types.StringValue("pid,cgid,cid"), + Id: types.StringValue(id), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cgid"), CredentialId: types.StringValue("cid"), diff --git a/stackit/internal/services/objectstorage/credentialsgroup/datasource.go b/stackit/internal/services/objectstorage/credentialsgroup/datasource.go index f7c9b582..24c0bc30 100644 --- a/stackit/internal/services/objectstorage/credentialsgroup/datasource.go +++ b/stackit/internal/services/objectstorage/credentialsgroup/datasource.go @@ -60,7 +60,7 @@ func (r *credentialsGroupDataSource) Configure(ctx context.Context, req datasour func (r *credentialsGroupDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { descriptions := map[string]string{ "main": "ObjectStorage credentials group data source schema. Must have a `region` specified in the provider configuration.", - "id": "Terraform's internal data source identifier. It is structured as \"`project_id`,`credentials_group_id`\".", + "id": "Terraform's internal data source identifier. It is structured as \"`project_id`,`region`,`credentials_group_id`\".", "credentials_group_id": "The credentials group ID.", "name": "The credentials group's display name.", "project_id": "Object Storage Project ID to which the credentials group is associated.", @@ -77,8 +77,7 @@ func (r *credentialsGroupDataSource) Schema(_ context.Context, _ datasource.Sche }, "credentials_group_id": schema.StringAttribute{ Description: descriptions["credentials_group_id"], - Optional: true, - Computed: true, + Required: true, }, "project_id": schema.StringAttribute{ Description: descriptions["project_id"], @@ -90,7 +89,6 @@ func (r *credentialsGroupDataSource) Schema(_ context.Context, _ datasource.Sche }, "name": schema.StringAttribute{ Description: descriptions["name"], - Optional: true, Computed: true, }, "urn": schema.StringAttribute{ diff --git a/stackit/internal/services/objectstorage/credentialsgroup/resource.go b/stackit/internal/services/objectstorage/credentialsgroup/resource.go index 11c80cb0..efb66ec8 100644 --- a/stackit/internal/services/objectstorage/credentialsgroup/resource.go +++ b/stackit/internal/services/objectstorage/credentialsgroup/resource.go @@ -109,7 +109,7 @@ func (r *credentialsGroupResource) Configure(ctx context.Context, req resource.C func (r *credentialsGroupResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { descriptions := map[string]string{ "main": "ObjectStorage credentials group resource schema. Must have a `region` specified in the provider configuration. If you are creating `credentialsgroup` and `bucket` resources simultaneously, please include the `depends_on` field so that they are created sequentially. This prevents errors from concurrent calls to the service enablement that is done in the background.", - "id": "Terraform's internal data source identifier. It is structured as \"`project_id`,`credentials_group_id`\".", + "id": "Terraform's internal data source identifier. It is structured as \"`project_id`,`region`,`credentials_group_id`\".", "credentials_group_id": "The credentials group ID", "name": "The credentials group's display name.", "project_id": "Project ID to which the credentials group is associated.", @@ -291,16 +291,17 @@ func (r *credentialsGroupResource) Delete(ctx context.Context, req resource.Dele // The expected format of the resource import identifier is: project_id, credentials_group_id func (r *credentialsGroupResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { idParts := strings.Split(req.ID, core.Separator) - if len(idParts) != 2 || idParts[0] == "" || idParts[1] == "" { + if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { core.LogAndAddError(ctx, &resp.Diagnostics, "Error importing credentialsGroup", - fmt.Sprintf("Expected import identifier with format [project_id],[credentials_group_id], got %q", req.ID), + fmt.Sprintf("Expected import identifier with format [project_id],[region],[credentials_group_id], got %q", req.ID), ) return } resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...) - resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("credentials_group_id"), idParts[1])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("credentials_group_id"), idParts[2])...) tflog.Info(ctx, "ObjectStorage credentials group state imported") } @@ -316,7 +317,7 @@ func mapFields(credentialsGroupResp *objectstorage.CreateCredentialsGroupRespons } credentialsGroup := credentialsGroupResp.CredentialsGroup - err := mapCredentialsGroup(*credentialsGroup, model) + err := mapCredentialsGroup(*credentialsGroup, model, region) if err != nil { return err } @@ -324,7 +325,7 @@ func mapFields(credentialsGroupResp *objectstorage.CreateCredentialsGroupRespons return nil } -func mapCredentialsGroup(credentialsGroup objectstorage.CredentialsGroup, model *Model) error { +func mapCredentialsGroup(credentialsGroup objectstorage.CredentialsGroup, model *Model, region string) error { var credentialsGroupId string if !coreutils.IsUndefined(model.CredentialsGroupId) { credentialsGroupId = model.CredentialsGroupId.ValueString() @@ -336,6 +337,7 @@ func mapCredentialsGroup(credentialsGroup objectstorage.CredentialsGroup, model idParts := []string{ model.ProjectId.ValueString(), + region, credentialsGroupId, } model.Id = types.StringValue( @@ -392,7 +394,7 @@ func readCredentialsGroups(ctx context.Context, model *Model, region string, cli continue } found = true - err = mapCredentialsGroup(credentialsGroup, model) + err = mapCredentialsGroup(credentialsGroup, model, region) if err != nil { return found, err } diff --git a/stackit/internal/services/objectstorage/credentialsgroup/resource_test.go b/stackit/internal/services/objectstorage/credentialsgroup/resource_test.go index 893bc801..37b0dae8 100644 --- a/stackit/internal/services/objectstorage/credentialsgroup/resource_test.go +++ b/stackit/internal/services/objectstorage/credentialsgroup/resource_test.go @@ -35,6 +35,8 @@ func (c *objectStorageClientMocked) ListCredentialsGroupsExecute(_ context.Conte } func TestMapFields(t *testing.T) { + const testRegion = "eu01" + id := fmt.Sprintf("%s,%s,%s", "pid", testRegion, "cid") tests := []struct { description string input *objectstorage.CreateCredentialsGroupResponse @@ -47,7 +49,7 @@ func TestMapFields(t *testing.T) { CredentialsGroup: &objectstorage.CredentialsGroup{}, }, Model{ - Id: types.StringValue("pid,cid"), + Id: types.StringValue(id), Name: types.StringNull(), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cid"), @@ -65,7 +67,7 @@ func TestMapFields(t *testing.T) { }, }, Model{ - Id: types.StringValue("pid,cid"), + Id: types.StringValue(id), Name: types.StringValue("name"), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cid"), @@ -83,7 +85,7 @@ func TestMapFields(t *testing.T) { }, }, Model{ - Id: types.StringValue("pid,cid"), + Id: types.StringValue(id), Name: types.StringValue(""), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cid"), @@ -162,6 +164,8 @@ func TestEnableProject(t *testing.T) { } func TestReadCredentialsGroups(t *testing.T) { + const testRegion = "eu01" + id := fmt.Sprintf("%s,%s,%s", "pid", testRegion, "cid") tests := []struct { description string mockedResp *objectstorage.ListCredentialsGroupsResponse @@ -183,7 +187,7 @@ func TestReadCredentialsGroups(t *testing.T) { }, }, Model{ - Id: types.StringValue("pid,cid"), + Id: types.StringValue(id), Name: types.StringNull(), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cid"), @@ -210,7 +214,7 @@ func TestReadCredentialsGroups(t *testing.T) { }, }, Model{ - Id: types.StringValue("pid,cid"), + Id: types.StringValue(id), Name: types.StringValue("name"), ProjectId: types.StringValue("pid"), CredentialsGroupId: types.StringValue("cid"), diff --git a/stackit/internal/services/objectstorage/objectstorage_acc_test.go b/stackit/internal/services/objectstorage/objectstorage_acc_test.go index 0d7aace7..4fd11725 100644 --- a/stackit/internal/services/objectstorage/objectstorage_acc_test.go +++ b/stackit/internal/services/objectstorage/objectstorage_acc_test.go @@ -2,14 +2,18 @@ package objectstorage_test import ( "context" + _ "embed" "fmt" "strings" "testing" + "time" + "github.com/hashicorp/terraform-plugin-testing/config" "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" - "github.com/stackitcloud/stackit-sdk-go/core/config" + + stackitSdkConfig "github.com/stackitcloud/stackit-sdk-go/core/config" "github.com/stackitcloud/stackit-sdk-go/core/utils" "github.com/stackitcloud/stackit-sdk-go/services/objectstorage" "github.com/stackitcloud/stackit-sdk-go/services/objectstorage/wait" @@ -17,71 +21,35 @@ import ( "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/testutil" ) -// Bucket resource data -var bucketResource = map[string]string{ - "project_id": testutil.ProjectId, - "name": fmt.Sprintf("acc-test-%s", acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)), +//go:embed testfiles/resource-min.tf +var resourceMinConfig string + +var testConfigVarsMin = config.Variables{ + "project_id": config.StringVariable(testutil.ProjectId), + "objectstorage_bucket_name": config.StringVariable(fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(20, acctest.CharSetAlpha))), + "objectstorage_credentials_group_name": config.StringVariable(fmt.Sprintf("tf-acc-test-%s", acctest.RandStringFromCharSet(20, acctest.CharSetAlpha))), + "expiration_timestamp": config.StringVariable(fmt.Sprintf("%d-01-02T03:04:05Z", time.Now().Year()+1)), } -// Credentials group resource data -var credentialsGroupResource = map[string]string{ - "project_id": testutil.ProjectId, - "name": fmt.Sprintf("acc-test-%s", acctest.RandStringFromCharSet(20, acctest.CharSetAlpha)), -} - -// Credential resource data -var credentialResource = map[string]string{ - "expiration_timestamp": "2027-01-02T03:04:05Z", -} - -func resourceConfig() string { - return fmt.Sprintf(` - %s - - resource "stackit_objectstorage_bucket" "bucket" { - project_id = "%s" - name = "%s" - } - - resource "stackit_objectstorage_credentials_group" "credentials_group" { - project_id = "%s" - name = "%s" - } - - resource "stackit_objectstorage_credential" "credential" { - project_id = stackit_objectstorage_credentials_group.credentials_group.project_id - credentials_group_id = stackit_objectstorage_credentials_group.credentials_group.credentials_group_id - expiration_timestamp = "%s" - } - `, - testutil.ObjectStorageProviderConfig(), - bucketResource["project_id"], - bucketResource["name"], - credentialsGroupResource["project_id"], - credentialsGroupResource["name"], - credentialResource["expiration_timestamp"], - ) -} - -func TestAccObjectStorageResource(t *testing.T) { +func TestAccObjectStorageResourceMin(t *testing.T) { resource.Test(t, resource.TestCase{ ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories, CheckDestroy: testAccCheckObjectStorageDestroy, Steps: []resource.TestStep{ - // Creation { - Config: resourceConfig(), + ConfigVariables: testConfigVarsMin, + Config: testutil.ObjectStorageProviderConfig() + resourceMinConfig, Check: resource.ComposeAggregateTestCheckFunc( // Bucket data - resource.TestCheckResourceAttr("stackit_objectstorage_bucket.bucket", "project_id", bucketResource["project_id"]), - resource.TestCheckResourceAttr("stackit_objectstorage_bucket.bucket", "name", bucketResource["name"]), + resource.TestCheckResourceAttr("stackit_objectstorage_bucket.bucket", "project_id", testutil.ConvertConfigVariable(testConfigVarsMin["project_id"])), + resource.TestCheckResourceAttr("stackit_objectstorage_bucket.bucket", "name", testutil.ConvertConfigVariable(testConfigVarsMin["objectstorage_bucket_name"])), resource.TestCheckResourceAttrSet("stackit_objectstorage_bucket.bucket", "url_path_style"), resource.TestCheckResourceAttrSet("stackit_objectstorage_bucket.bucket", "url_virtual_hosted_style"), // Credentials group data - resource.TestCheckResourceAttr("stackit_objectstorage_credentials_group.credentials_group", "project_id", credentialsGroupResource["project_id"]), - resource.TestCheckResourceAttr("stackit_objectstorage_credentials_group.credentials_group", "name", credentialsGroupResource["name"]), + resource.TestCheckResourceAttr("stackit_objectstorage_credentials_group.credentials_group", "project_id", testutil.ConvertConfigVariable(testConfigVarsMin["project_id"])), + resource.TestCheckResourceAttr("stackit_objectstorage_credentials_group.credentials_group", "name", testutil.ConvertConfigVariable(testConfigVarsMin["objectstorage_credentials_group_name"])), resource.TestCheckResourceAttrSet("stackit_objectstorage_credentials_group.credentials_group", "credentials_group_id"), resource.TestCheckResourceAttrSet("stackit_objectstorage_credentials_group.credentials_group", "urn"), @@ -95,37 +63,58 @@ func TestAccObjectStorageResource(t *testing.T) { "stackit_objectstorage_credentials_group.credentials_group", "credentials_group_id", ), resource.TestCheckResourceAttrSet("stackit_objectstorage_credential.credential", "credential_id"), - resource.TestCheckResourceAttr("stackit_objectstorage_credential.credential", "expiration_timestamp", credentialResource["expiration_timestamp"]), resource.TestCheckResourceAttrSet("stackit_objectstorage_credential.credential", "name"), resource.TestCheckResourceAttrSet("stackit_objectstorage_credential.credential", "access_key"), resource.TestCheckResourceAttrSet("stackit_objectstorage_credential.credential", "secret_access_key"), + + // credential_time data + resource.TestCheckResourceAttrPair( + "stackit_objectstorage_credential.credential_time", "project_id", + "stackit_objectstorage_credentials_group.credentials_group", "project_id", + ), + resource.TestCheckResourceAttrPair( + "stackit_objectstorage_credential.credential_time", "credentials_group_id", + "stackit_objectstorage_credentials_group.credentials_group", "credentials_group_id", + ), + resource.TestCheckResourceAttrSet("stackit_objectstorage_credential.credential_time", "credential_id"), + resource.TestCheckResourceAttr("stackit_objectstorage_credential.credential_time", "expiration_timestamp", testutil.ConvertConfigVariable(testConfigVarsMin["expiration_timestamp"])), + resource.TestCheckResourceAttrSet("stackit_objectstorage_credential.credential_time", "name"), + resource.TestCheckResourceAttrSet("stackit_objectstorage_credential.credential_time", "access_key"), + resource.TestCheckResourceAttrSet("stackit_objectstorage_credential.credential_time", "secret_access_key"), ), }, // Data source { + ConfigVariables: testConfigVarsMin, Config: fmt.Sprintf(` - %s + %s - data "stackit_objectstorage_bucket" "bucket" { - project_id = stackit_objectstorage_bucket.bucket.project_id - name = stackit_objectstorage_bucket.bucket.name - } - - data "stackit_objectstorage_credentials_group" "credentials_group" { - project_id = stackit_objectstorage_credentials_group.credentials_group.project_id - credentials_group_id = stackit_objectstorage_credentials_group.credentials_group.credentials_group_id - } - - data "stackit_objectstorage_credential" "credential" { - project_id = stackit_objectstorage_credential.credential.project_id - credentials_group_id = stackit_objectstorage_credential.credential.credentials_group_id - credential_id = stackit_objectstorage_credential.credential.credential_id - }`, - resourceConfig(), + data "stackit_objectstorage_bucket" "bucket" { + project_id = stackit_objectstorage_bucket.bucket.project_id + name = stackit_objectstorage_bucket.bucket.name + } + + data "stackit_objectstorage_credentials_group" "credentials_group" { + project_id = stackit_objectstorage_credentials_group.credentials_group.project_id + credentials_group_id = stackit_objectstorage_credentials_group.credentials_group.credentials_group_id + } + + data "stackit_objectstorage_credential" "credential" { + project_id = stackit_objectstorage_credential.credential.project_id + credentials_group_id = stackit_objectstorage_credential.credential.credentials_group_id + credential_id = stackit_objectstorage_credential.credential.credential_id + } + + data "stackit_objectstorage_credential" "credential_time" { + project_id = stackit_objectstorage_credential.credential_time.project_id + credentials_group_id = stackit_objectstorage_credential.credential_time.credentials_group_id + credential_id = stackit_objectstorage_credential.credential_time.credential_id + }`, + testutil.ObjectStorageProviderConfig()+resourceMinConfig, ), Check: resource.ComposeAggregateTestCheckFunc( // Bucket data - resource.TestCheckResourceAttr("data.stackit_objectstorage_bucket.bucket", "project_id", bucketResource["project_id"]), + resource.TestCheckResourceAttr("data.stackit_objectstorage_bucket.bucket", "project_id", testutil.ConvertConfigVariable(testConfigVarsMin["project_id"])), resource.TestCheckResourceAttrPair( "stackit_objectstorage_bucket.bucket", "name", "data.stackit_objectstorage_bucket.bucket", "name", @@ -140,7 +129,7 @@ func TestAccObjectStorageResource(t *testing.T) { ), // Credentials group data - resource.TestCheckResourceAttr("data.stackit_objectstorage_credentials_group.credentials_group", "project_id", credentialsGroupResource["project_id"]), + resource.TestCheckResourceAttr("data.stackit_objectstorage_credentials_group.credentials_group", "project_id", testutil.ConvertConfigVariable(testConfigVarsMin["project_id"])), resource.TestCheckResourceAttrPair( "stackit_objectstorage_credentials_group.credentials_group", "credentials_group_id", "data.stackit_objectstorage_credentials_group.credentials_group", "credentials_group_id", @@ -175,11 +164,34 @@ func TestAccObjectStorageResource(t *testing.T) { "stackit_objectstorage_credential.credential", "expiration_timestamp", "data.stackit_objectstorage_credential.credential", "expiration_timestamp", ), + + // Credential_time data + resource.TestCheckResourceAttrPair( + "stackit_objectstorage_credential.credential_time", "project_id", + "data.stackit_objectstorage_credential.credential_time", "project_id", + ), + resource.TestCheckResourceAttrPair( + "stackit_objectstorage_credential.credential_time", "credentials_group_id", + "data.stackit_objectstorage_credential.credential_time", "credentials_group_id", + ), + resource.TestCheckResourceAttrPair( + "stackit_objectstorage_credential.credential_time", "credential_id", + "data.stackit_objectstorage_credential.credential_time", "credential_id", + ), + resource.TestCheckResourceAttrPair( + "stackit_objectstorage_credential.credential_time", "name", + "data.stackit_objectstorage_credential.credential_time", "name", + ), + resource.TestCheckResourceAttrPair( + "stackit_objectstorage_credential.credential_time", "expiration_timestamp", + "data.stackit_objectstorage_credential.credential_time", "expiration_timestamp", + ), ), }, // Import { - ResourceName: "stackit_objectstorage_credentials_group.credentials_group", + ConfigVariables: testConfigVarsMin, + ResourceName: "stackit_objectstorage_credentials_group.credentials_group", ImportStateIdFunc: func(s *terraform.State) (string, error) { r, ok := s.RootModule().Resources["stackit_objectstorage_credentials_group.credentials_group"] if !ok { @@ -190,14 +202,14 @@ func TestAccObjectStorageResource(t *testing.T) { return "", fmt.Errorf("couldn't find attribute credentials_group_id") } - return fmt.Sprintf("%s,%s", testutil.ProjectId, credentialsGroupId), nil + return fmt.Sprintf("%s,%s,%s", testutil.ProjectId, testutil.Region, credentialsGroupId), nil }, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"region"}, + ImportState: true, + ImportStateVerify: true, }, { - ResourceName: "stackit_objectstorage_credential.credential", + ConfigVariables: testConfigVarsMin, + ResourceName: "stackit_objectstorage_credential.credential", ImportStateIdFunc: func(s *terraform.State) (string, error) { r, ok := s.RootModule().Resources["stackit_objectstorage_credential.credential"] if !ok { @@ -211,11 +223,11 @@ func TestAccObjectStorageResource(t *testing.T) { if !ok { return "", fmt.Errorf("couldn't find attribute credential_id") } - return fmt.Sprintf("%s,%s,%s", testutil.ProjectId, credentialsGroupId, credentialId), nil + return fmt.Sprintf("%s,%s,%s,%s", testutil.ProjectId, testutil.Region, credentialsGroupId, credentialId), nil }, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"access_key", "secret_access_key", "region"}, + ImportStateVerifyIgnore: []string{"access_key", "secret_access_key"}, }, // Deletion is done by the framework implicitly }, @@ -228,11 +240,11 @@ func testAccCheckObjectStorageDestroy(s *terraform.State) error { var err error if testutil.ObjectStorageCustomEndpoint == "" { client, err = objectstorage.NewAPIClient( - config.WithRegion("eu01"), + stackitSdkConfig.WithRegion("eu01"), ) } else { client, err = objectstorage.NewAPIClient( - config.WithEndpoint(testutil.ObjectStorageCustomEndpoint), + stackitSdkConfig.WithEndpoint(testutil.ObjectStorageCustomEndpoint), ) } if err != nil { diff --git a/stackit/internal/services/objectstorage/testfiles/resource-min.tf b/stackit/internal/services/objectstorage/testfiles/resource-min.tf new file mode 100644 index 00000000..db9b28fa --- /dev/null +++ b/stackit/internal/services/objectstorage/testfiles/resource-min.tf @@ -0,0 +1,26 @@ + +variable "project_id" {} +variable "objectstorage_bucket_name" {} +variable "objectstorage_credentials_group_name" {} +variable "expiration_timestamp" {} + +resource "stackit_objectstorage_bucket" "bucket" { + project_id = var.project_id + name = var.objectstorage_bucket_name +} + +resource "stackit_objectstorage_credentials_group" "credentials_group" { + project_id = var.project_id + name = var.objectstorage_credentials_group_name +} + +resource "stackit_objectstorage_credential" "credential" { + project_id = stackit_objectstorage_credentials_group.credentials_group.project_id + credentials_group_id = stackit_objectstorage_credentials_group.credentials_group.credentials_group_id +} + +resource "stackit_objectstorage_credential" "credential_time" { + project_id = stackit_objectstorage_credentials_group.credentials_group.project_id + credentials_group_id = stackit_objectstorage_credentials_group.credentials_group.credentials_group_id + expiration_timestamp = var.expiration_timestamp +}