feat: more_tests #85
20 changed files with 570 additions and 581 deletions
|
|
@ -28,6 +28,9 @@ data "stackitprivatepreview_postgresflexalpha_database" "example" {
|
||||||
- `database_id` (Number) The ID of the database.
|
- `database_id` (Number) The ID of the database.
|
||||||
- `instance_id` (String) The ID of the instance.
|
- `instance_id` (String) The ID of the instance.
|
||||||
- `project_id` (String) The STACKIT project ID.
|
- `project_id` (String) The STACKIT project ID.
|
||||||
|
|
||||||
|
### Optional
|
||||||
|
|
||||||
- `region` (String) The region which should be addressed
|
- `region` (String) The region which should be addressed
|
||||||
|
|
||||||
### Read-Only
|
### Read-Only
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ data "stackitprivatepreview_postgresflexalpha_instance" "example" {
|
||||||
|
|
||||||
- `instance_id` (String) The ID of the instance.
|
- `instance_id` (String) The ID of the instance.
|
||||||
- `project_id` (String) The STACKIT project ID.
|
- `project_id` (String) The STACKIT project ID.
|
||||||
|
|
||||||
|
### Optional
|
||||||
|
|
||||||
- `region` (String) The region which should be addressed
|
- `region` (String) The region which should be addressed
|
||||||
|
|
||||||
### Read-Only
|
### Read-Only
|
||||||
|
|
@ -37,6 +40,7 @@ data "stackitprivatepreview_postgresflexalpha_instance" "example" {
|
||||||
|
|
||||||
⚠ **Note:** This feature is in private preview. Supplying this object is only permitted for enabled accounts. If your account does not have access, the request will be rejected. (see [below for nested schema](#nestedatt--encryption))
|
⚠ **Note:** This feature is in private preview. Supplying this object is only permitted for enabled accounts. If your account does not have access, the request will be rejected. (see [below for nested schema](#nestedatt--encryption))
|
||||||
- `flavor_id` (String) The id of the instance flavor.
|
- `flavor_id` (String) The id of the instance flavor.
|
||||||
|
- `id` (String) internal ID
|
||||||
- `is_deletable` (Boolean) Whether the instance can be deleted or not.
|
- `is_deletable` (Boolean) Whether the instance can be deleted or not.
|
||||||
- `name` (String) The name of the instance.
|
- `name` (String) The name of the instance.
|
||||||
- `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network))
|
- `network` (Attributes) The access configuration of the instance (see [below for nested schema](#nestedatt--network))
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,12 @@ data "stackitprivatepreview_postgresflexalpha_user" "example" {
|
||||||
|
|
||||||
- `instance_id` (String) The ID of the instance.
|
- `instance_id` (String) The ID of the instance.
|
||||||
- `project_id` (String) The STACKIT project ID.
|
- `project_id` (String) The STACKIT project ID.
|
||||||
- `region` (String) The region which should be addressed
|
|
||||||
- `user_id` (Number) The ID of the user.
|
- `user_id` (Number) The ID of the user.
|
||||||
|
|
||||||
### Optional
|
### Optional
|
||||||
|
|
||||||
- `id` (String) Terraform's internal resource ID. It is structured as \"`project_id`,`region`,`instance_id`,`user_id`\".",
|
- `id` (String) Terraform's internal resource ID. It is structured as \"`project_id`,`region`,`instance_id`,`user_id`\".",
|
||||||
|
- `region` (String) The region which should be addressed
|
||||||
|
|
||||||
### Read-Only
|
### Read-Only
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,4 +54,4 @@ import {
|
||||||
|
|
||||||
### Read-Only
|
### Read-Only
|
||||||
|
|
||||||
- `id` (Number) The id of the database.
|
- `id` (String) The id of the database.
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,6 @@ import {
|
||||||
|
|
||||||
### Read-Only
|
### Read-Only
|
||||||
|
|
||||||
- `id` (Number) The ID of the user.
|
- `id` (String) The ID of the user.
|
||||||
- `password` (String) The password for the user.
|
- `password` (String) The password for the user.
|
||||||
- `status` (String) The current status of the user.
|
- `status` (String) The current status of the user.
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ func DatabaseDataSourceSchema(ctx context.Context) schema.Schema {
|
||||||
MarkdownDescription: "The STACKIT project ID.",
|
MarkdownDescription: "The STACKIT project ID.",
|
||||||
},
|
},
|
||||||
"region": schema.StringAttribute{
|
"region": schema.StringAttribute{
|
||||||
Required: true,
|
Optional: true,
|
||||||
Description: "The region which should be addressed",
|
Description: "The region which should be addressed",
|
||||||
MarkdownDescription: "The region which should be addressed",
|
MarkdownDescription: "The region which should be addressed",
|
||||||
Validators: []validator.String{
|
Validators: []validator.String{
|
||||||
|
|
|
||||||
|
|
@ -65,15 +65,19 @@ func mapResourceFields(source *v3alpha1api.GetDatabaseResponse, model *resourceM
|
||||||
}
|
}
|
||||||
|
|
||||||
var databaseId int64
|
var databaseId int64
|
||||||
if model.Id.ValueInt64() != 0 {
|
if model.DatabaseId.ValueInt64() != 0 {
|
||||||
databaseId = model.Id.ValueInt64()
|
if source.Id != 0 {
|
||||||
|
if model.DatabaseId.ValueInt64() != int64(source.Id) {
|
||||||
|
return fmt.Errorf("retrieved ID does not match known ID")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
databaseId = model.DatabaseId.ValueInt64()
|
||||||
} else if source.Id != 0 {
|
} else if source.Id != 0 {
|
||||||
databaseId = int64(source.Id)
|
databaseId = int64(source.Id)
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("database id not present")
|
return fmt.Errorf("database id not present")
|
||||||
}
|
}
|
||||||
|
|
||||||
model.Id = types.Int64Value(databaseId)
|
|
||||||
model.DatabaseId = types.Int64Value(databaseId)
|
model.DatabaseId = types.Int64Value(databaseId)
|
||||||
model.Name = types.StringValue(source.GetName())
|
model.Name = types.StringValue(source.GetName())
|
||||||
model.Owner = types.StringValue(cleanString(source.Owner))
|
model.Owner = types.StringValue(cleanString(source.Owner))
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ import (
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/identityschema"
|
|
||||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||||
|
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
|
||||||
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api"
|
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api"
|
||||||
|
|
||||||
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/conversion"
|
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/conversion"
|
||||||
|
|
@ -30,7 +30,6 @@ var (
|
||||||
_ resource.ResourceWithConfigure = &databaseResource{}
|
_ resource.ResourceWithConfigure = &databaseResource{}
|
||||||
_ resource.ResourceWithImportState = &databaseResource{}
|
_ resource.ResourceWithImportState = &databaseResource{}
|
||||||
_ resource.ResourceWithModifyPlan = &databaseResource{}
|
_ resource.ResourceWithModifyPlan = &databaseResource{}
|
||||||
_ resource.ResourceWithIdentity = &databaseResource{}
|
|
||||||
|
|
||||||
// Error message constants
|
// Error message constants
|
||||||
extractErrorSummary = "extracting failed"
|
extractErrorSummary = "extracting failed"
|
||||||
|
|
@ -45,14 +44,6 @@ func NewDatabaseResource() resource.Resource {
|
||||||
// resourceModel describes the resource data model.
|
// resourceModel describes the resource data model.
|
||||||
type resourceModel = postgresflexalphaResGen.DatabaseModel
|
type resourceModel = postgresflexalphaResGen.DatabaseModel
|
||||||
|
|
||||||
// DatabaseResourceIdentityModel describes the resource's identity attributes.
|
|
||||||
type DatabaseResourceIdentityModel struct {
|
|
||||||
ProjectID types.String `tfsdk:"project_id"`
|
|
||||||
Region types.String `tfsdk:"region"`
|
|
||||||
InstanceID types.String `tfsdk:"instance_id"`
|
|
||||||
DatabaseID types.Int64 `tfsdk:"database_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// databaseResource is the resource implementation.
|
// databaseResource is the resource implementation.
|
||||||
type databaseResource struct {
|
type databaseResource struct {
|
||||||
client *v3alpha1api.APIClient
|
client *v3alpha1api.APIClient
|
||||||
|
|
@ -138,30 +129,6 @@ func (r *databaseResource) Schema(ctx context.Context, _ resource.SchemaRequest,
|
||||||
resp.Schema = s
|
resp.Schema = s
|
||||||
}
|
}
|
||||||
|
|
||||||
// IdentitySchema defines the schema for the resource's identity attributes.
|
|
||||||
func (r *databaseResource) IdentitySchema(
|
|
||||||
_ context.Context,
|
|
||||||
_ resource.IdentitySchemaRequest,
|
|
||||||
response *resource.IdentitySchemaResponse,
|
|
||||||
) {
|
|
||||||
response.IdentitySchema = identityschema.Schema{
|
|
||||||
Attributes: map[string]identityschema.Attribute{
|
|
||||||
"project_id": identityschema.StringAttribute{
|
|
||||||
RequiredForImport: true,
|
|
||||||
},
|
|
||||||
"region": identityschema.StringAttribute{
|
|
||||||
RequiredForImport: true,
|
|
||||||
},
|
|
||||||
"instance_id": identityschema.StringAttribute{
|
|
||||||
RequiredForImport: true,
|
|
||||||
},
|
|
||||||
"database_id": identityschema.Int64Attribute{
|
|
||||||
RequiredForImport: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create creates the resource and sets the initial Terraform state.
|
// Create creates the resource and sets the initial Terraform state.
|
||||||
func (r *databaseResource) Create(
|
func (r *databaseResource) Create(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
|
|
@ -178,12 +145,12 @@ func (r *databaseResource) Create(
|
||||||
|
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
projectId := model.ProjectId.ValueString()
|
projectID := model.ProjectId.ValueString()
|
||||||
region := model.Region.ValueString()
|
region := model.Region.ValueString()
|
||||||
instanceId := model.InstanceId.ValueString()
|
instanceID := model.InstanceId.ValueString()
|
||||||
|
|
||||||
ctx = tflog.SetField(ctx, "project_id", projectId)
|
ctx = tflog.SetField(ctx, "project_id", projectID)
|
||||||
ctx = tflog.SetField(ctx, "instance_id", instanceId)
|
ctx = tflog.SetField(ctx, "instance_id", instanceID)
|
||||||
ctx = tflog.SetField(ctx, "region", region)
|
ctx = tflog.SetField(ctx, "region", region)
|
||||||
|
|
||||||
// Generate API request body from model
|
// Generate API request body from model
|
||||||
|
|
@ -200,9 +167,9 @@ func (r *databaseResource) Create(
|
||||||
// Create new database
|
// Create new database
|
||||||
databaseResp, err := r.client.DefaultAPI.CreateDatabaseRequest(
|
databaseResp, err := r.client.DefaultAPI.CreateDatabaseRequest(
|
||||||
ctx,
|
ctx,
|
||||||
projectId,
|
projectID,
|
||||||
region,
|
region,
|
||||||
instanceId,
|
instanceID,
|
||||||
).CreateDatabaseRequestPayload(*payload).Execute()
|
).CreateDatabaseRequestPayload(*payload).Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, funcErrorSummary, fmt.Sprintf("Calling API: %v", err))
|
core.LogAndAddError(ctx, &resp.Diagnostics, funcErrorSummary, fmt.Sprintf("Calling API: %v", err))
|
||||||
|
|
@ -219,23 +186,33 @@ func (r *databaseResource) Create(
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
databaseId := int64(*dbID)
|
databaseID := int64(*dbID)
|
||||||
ctx = tflog.SetField(ctx, "database_id", databaseId)
|
databaseIDString := strconv.Itoa(int(*dbID))
|
||||||
|
|
||||||
|
ctx = tflog.SetField(ctx, "database_id", databaseID)
|
||||||
ctx = core.LogResponse(ctx)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
// Save identity into Terraform state
|
model.DatabaseId = types.Int64Value(databaseID)
|
||||||
identity := DatabaseResourceIdentityModel{
|
model.Id = utils.BuildInternalTerraformId(projectID, region, instanceID, databaseIDString)
|
||||||
ProjectID: types.StringValue(projectId),
|
|
||||||
Region: types.StringValue(region),
|
|
||||||
InstanceID: types.StringValue(instanceId),
|
|
||||||
DatabaseID: types.Int64Value(databaseId),
|
|
||||||
}
|
|
||||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
|
||||||
if resp.Diagnostics.HasError() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
database, err := postgresflexalphaWait.GetDatabaseByIdWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, region, databaseId).
|
// Set data returned by API in id
|
||||||
|
resp.Diagnostics.Append(
|
||||||
|
resp.State.SetAttribute(
|
||||||
|
ctx,
|
||||||
|
path.Root("database_id"),
|
||||||
|
databaseID,
|
||||||
|
)...,
|
||||||
|
)
|
||||||
|
// Set data returned by API in id
|
||||||
|
resp.Diagnostics.Append(
|
||||||
|
resp.State.SetAttribute(
|
||||||
|
ctx,
|
||||||
|
path.Root("id"),
|
||||||
|
model.Id,
|
||||||
|
)...,
|
||||||
|
)
|
||||||
|
|
||||||
|
database, err := postgresflexalphaWait.GetDatabaseByIdWaitHandler(ctx, r.client.DefaultAPI, projectID, instanceID, region, databaseID).
|
||||||
SetTimeout(15 * time.Minute).
|
SetTimeout(15 * time.Minute).
|
||||||
SetSleepBeforeWait(15 * time.Second).
|
SetSleepBeforeWait(15 * time.Second).
|
||||||
WaitWithContext(ctx)
|
WaitWithContext(ctx)
|
||||||
|
|
@ -284,17 +261,28 @@ func (r *databaseResource) Read(
|
||||||
|
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
projectId := model.ProjectId.ValueString()
|
projectID := model.ProjectId.ValueString()
|
||||||
instanceId := model.InstanceId.ValueString()
|
instanceID := model.InstanceId.ValueString()
|
||||||
region := model.Region.ValueString()
|
region := model.Region.ValueString()
|
||||||
databaseId := model.DatabaseId.ValueInt64()
|
databaseID := model.DatabaseId.ValueInt64()
|
||||||
|
|
||||||
ctx = tflog.SetField(ctx, "project_id", projectId)
|
databaseIDString := strconv.Itoa(int(databaseID))
|
||||||
ctx = tflog.SetField(ctx, "instance_id", instanceId)
|
|
||||||
|
ctx = tflog.SetField(ctx, "project_id", projectID)
|
||||||
|
ctx = tflog.SetField(ctx, "instance_id", instanceID)
|
||||||
ctx = tflog.SetField(ctx, "region", region)
|
ctx = tflog.SetField(ctx, "region", region)
|
||||||
ctx = tflog.SetField(ctx, "database_id", databaseId)
|
ctx = tflog.SetField(ctx, "database_id", databaseID)
|
||||||
|
|
||||||
databaseResp, err := postgresflexalphaWait.GetDatabaseByIdWaitHandler(ctx, r.client.DefaultAPI, projectId, instanceId, region, databaseId).
|
// Set data returned by API in id
|
||||||
|
resp.Diagnostics.Append(
|
||||||
|
resp.State.SetAttribute(
|
||||||
|
ctx,
|
||||||
|
path.Root("id"),
|
||||||
|
utils.BuildInternalTerraformId(projectID, region, instanceID, databaseIDString),
|
||||||
|
)...,
|
||||||
|
)
|
||||||
|
|
||||||
|
databaseResp, err := postgresflexalphaWait.GetDatabaseByIdWaitHandler(ctx, r.client.DefaultAPI, projectID, instanceID, region, databaseID).
|
||||||
SetTimeout(15 * time.Minute).
|
SetTimeout(15 * time.Minute).
|
||||||
SetSleepBeforeWait(15 * time.Second).
|
SetSleepBeforeWait(15 * time.Second).
|
||||||
WaitWithContext(ctx)
|
WaitWithContext(ctx)
|
||||||
|
|
@ -322,18 +310,6 @@ func (r *databaseResource) Read(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save identity into Terraform state
|
|
||||||
identity := DatabaseResourceIdentityModel{
|
|
||||||
ProjectID: types.StringValue(projectId),
|
|
||||||
Region: types.StringValue(region),
|
|
||||||
InstanceID: types.StringValue(instanceId),
|
|
||||||
DatabaseID: types.Int64Value(int64(databaseResp.GetId())),
|
|
||||||
}
|
|
||||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
|
||||||
if resp.Diagnostics.HasError() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set refreshed state
|
// Set refreshed state
|
||||||
diags = resp.State.Set(ctx, model)
|
diags = resp.State.Set(ctx, model)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
|
|
@ -436,18 +412,6 @@ func (r *databaseResource) Update(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save identity into Terraform state
|
|
||||||
identity := DatabaseResourceIdentityModel{
|
|
||||||
ProjectID: types.StringValue(projectId),
|
|
||||||
Region: types.StringValue(region),
|
|
||||||
InstanceID: types.StringValue(instanceId),
|
|
||||||
DatabaseID: types.Int64Value(databaseId),
|
|
||||||
}
|
|
||||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
|
||||||
if resp.Diagnostics.HasError() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set state to fully populated data
|
// Set state to fully populated data
|
||||||
resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
|
resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
|
|
@ -469,38 +433,33 @@ func (r *databaseResource) Delete(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read identity data
|
|
||||||
var identityData DatabaseResourceIdentityModel
|
|
||||||
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
|
||||||
if resp.Diagnostics.HasError() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
projectId, region, instanceId, databaseId64, errExt := r.extractIdentityData(model, identityData)
|
projectID := model.ProjectId.ValueString()
|
||||||
if errExt != nil {
|
instanceID := model.InstanceId.ValueString()
|
||||||
core.LogAndAddError(
|
region := model.Region.ValueString()
|
||||||
ctx,
|
databaseID64 := model.DatabaseId.ValueInt64()
|
||||||
&resp.Diagnostics,
|
|
||||||
extractErrorSummary,
|
|
||||||
fmt.Sprintf(extractErrorMessage, errExt),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if databaseId64 > math.MaxInt32 {
|
if databaseID64 > math.MaxInt32 {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error in type conversion", "int value too large (databaseId)")
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error in type conversion", "int value too large (databaseId)")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
databaseId := int32(databaseId64) // nolint:gosec // check is performed above
|
databaseID := int32(databaseID64) // nolint:gosec // check is performed above
|
||||||
ctx = tflog.SetField(ctx, "project_id", projectId)
|
ctx = tflog.SetField(ctx, "project_id", projectID)
|
||||||
ctx = tflog.SetField(ctx, "instance_id", instanceId)
|
ctx = tflog.SetField(ctx, "instance_id", instanceID)
|
||||||
ctx = tflog.SetField(ctx, "region", region)
|
ctx = tflog.SetField(ctx, "region", region)
|
||||||
ctx = tflog.SetField(ctx, "database_id", databaseId)
|
ctx = tflog.SetField(ctx, "database_id", databaseID)
|
||||||
|
|
||||||
// Delete existing record set
|
// Delete existing record set
|
||||||
err := r.client.DefaultAPI.DeleteDatabaseRequest(ctx, projectId, region, instanceId, databaseId).Execute()
|
err := r.client.DefaultAPI.DeleteDatabaseRequest(ctx, projectID, region, instanceID, databaseID).Execute()
|
||||||
if err != nil {
|
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 {
|
||||||
|
if oapiErr.StatusCode == 404 {
|
||||||
|
resp.State.RemoveResource(ctx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting database", fmt.Sprintf("Calling API: %v", err))
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting database", fmt.Sprintf("Calling API: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -517,109 +476,44 @@ func (r *databaseResource) ImportState(
|
||||||
resp *resource.ImportStateResponse,
|
resp *resource.ImportStateResponse,
|
||||||
) {
|
) {
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
idParts := strings.Split(req.ID, core.Separator)
|
||||||
|
|
||||||
if req.ID != "" {
|
if len(idParts) != 4 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || idParts[3] == "" {
|
||||||
idParts := strings.Split(req.ID, core.Separator)
|
core.LogAndAddError(
|
||||||
|
ctx, &resp.Diagnostics,
|
||||||
|
"Error importing database",
|
||||||
|
fmt.Sprintf(
|
||||||
|
"Expected import identifier with format [project_id],[region],[instance_id],[database_id], got %q",
|
||||||
|
req.ID,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if len(idParts) != 4 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || idParts[3] == "" {
|
databaseID, err := strconv.ParseInt(idParts[3], 10, 64)
|
||||||
core.LogAndAddError(
|
if err != nil {
|
||||||
ctx, &resp.Diagnostics,
|
core.LogAndAddError(
|
||||||
"Error importing database",
|
|
||||||
fmt.Sprintf(
|
|
||||||
"Expected import identifier with format [project_id],[region],[instance_id],[database_id], got %q",
|
|
||||||
req.ID,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
databaseId, err := strconv.ParseInt(idParts[3], 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
core.LogAndAddError(
|
|
||||||
ctx,
|
|
||||||
&resp.Diagnostics,
|
|
||||||
"Error importing database",
|
|
||||||
fmt.Sprintf("Invalid database_id format: %q. It must be a valid integer.", idParts[3]),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...)
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...)
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...)
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("database_id"), databaseId)...)
|
|
||||||
|
|
||||||
core.LogAndAddWarning(
|
|
||||||
ctx,
|
ctx,
|
||||||
&resp.Diagnostics,
|
&resp.Diagnostics,
|
||||||
"Postgresflex database imported with empty password",
|
"Error importing database",
|
||||||
"The database password is not imported as it is only available upon creation of a new database. The password field will be empty.",
|
fmt.Sprintf("Invalid database_id format: %q. It must be a valid integer.", idParts[3]),
|
||||||
)
|
)
|
||||||
|
|
||||||
tflog.Info(ctx, "Postgres Flex database state imported")
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no ID is provided, attempt to read identity attributes from the import configuration
|
tfIDString := utils.BuildInternalTerraformId(idParts...).ValueString()
|
||||||
var identityData DatabaseResourceIdentityModel
|
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), tfIDString)...)
|
||||||
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...)
|
||||||
if resp.Diagnostics.HasError() {
|
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...)
|
||||||
return
|
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...)
|
||||||
}
|
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("database_id"), databaseID)...)
|
||||||
|
|
||||||
projectId := identityData.ProjectID.ValueString()
|
core.LogAndAddWarning(
|
||||||
region := identityData.Region.ValueString()
|
ctx,
|
||||||
instanceId := identityData.InstanceID.ValueString()
|
&resp.Diagnostics,
|
||||||
databaseId := identityData.DatabaseID.ValueInt64()
|
"Postgresflex database imported with empty password",
|
||||||
|
"The database password is not imported as it is only available upon creation of a new database. The password field will be empty.",
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), projectId)...)
|
)
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), region)...)
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), instanceId)...)
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("database_id"), databaseId)...)
|
|
||||||
|
|
||||||
tflog.Info(ctx, "Postgres Flex database state imported")
|
tflog.Info(ctx, "Postgres Flex database state imported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractIdentityData extracts essential identifiers from the resource model, falling back to the identity model.
|
|
||||||
func (r *databaseResource) extractIdentityData(
|
|
||||||
model resourceModel,
|
|
||||||
identity DatabaseResourceIdentityModel,
|
|
||||||
) (projectId, region, instanceId string, databaseId int64, err error) {
|
|
||||||
if !model.DatabaseId.IsNull() && !model.DatabaseId.IsUnknown() {
|
|
||||||
databaseId = model.DatabaseId.ValueInt64()
|
|
||||||
} else {
|
|
||||||
if identity.DatabaseID.IsNull() || identity.DatabaseID.IsUnknown() {
|
|
||||||
return "", "", "", 0, fmt.Errorf("database_id not found in config")
|
|
||||||
}
|
|
||||||
databaseId = identity.DatabaseID.ValueInt64()
|
|
||||||
}
|
|
||||||
|
|
||||||
if !model.ProjectId.IsNull() && !model.ProjectId.IsUnknown() {
|
|
||||||
projectId = model.ProjectId.ValueString()
|
|
||||||
} else {
|
|
||||||
if identity.ProjectID.IsNull() || identity.ProjectID.IsUnknown() {
|
|
||||||
return "", "", "", 0, fmt.Errorf("project_id not found in config")
|
|
||||||
}
|
|
||||||
projectId = identity.ProjectID.ValueString()
|
|
||||||
}
|
|
||||||
|
|
||||||
if !model.Region.IsNull() && !model.Region.IsUnknown() {
|
|
||||||
region = r.providerData.GetRegionWithOverride(model.Region)
|
|
||||||
} else {
|
|
||||||
if identity.Region.IsNull() || identity.Region.IsUnknown() {
|
|
||||||
return "", "", "", 0, fmt.Errorf("region not found in config")
|
|
||||||
}
|
|
||||||
region = r.providerData.GetRegionWithOverride(identity.Region)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !model.InstanceId.IsNull() && !model.InstanceId.IsUnknown() {
|
|
||||||
instanceId = model.InstanceId.ValueString()
|
|
||||||
} else {
|
|
||||||
if identity.InstanceID.IsNull() || identity.InstanceID.IsUnknown() {
|
|
||||||
return "", "", "", 0, fmt.Errorf("instance_id not found in config")
|
|
||||||
}
|
|
||||||
instanceId = identity.InstanceID.ValueString()
|
|
||||||
}
|
|
||||||
return projectId, region, instanceId, databaseId, nil
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ func DatabaseResourceSchema(ctx context.Context) schema.Schema {
|
||||||
Description: "The ID of the database.",
|
Description: "The ID of the database.",
|
||||||
MarkdownDescription: "The ID of the database.",
|
MarkdownDescription: "The ID of the database.",
|
||||||
},
|
},
|
||||||
"id": schema.Int64Attribute{
|
"id": schema.StringAttribute{
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Description: "The id of the database.",
|
Description: "The id of the database.",
|
||||||
MarkdownDescription: "The id of the database.",
|
MarkdownDescription: "The id of the database.",
|
||||||
|
|
@ -65,7 +65,7 @@ func DatabaseResourceSchema(ctx context.Context) schema.Schema {
|
||||||
|
|
||||||
type DatabaseModel struct {
|
type DatabaseModel struct {
|
||||||
DatabaseId types.Int64 `tfsdk:"database_id"`
|
DatabaseId types.Int64 `tfsdk:"database_id"`
|
||||||
Id types.Int64 `tfsdk:"id"`
|
Id types.String `tfsdk:"id"`
|
||||||
InstanceId types.String `tfsdk:"instance_id"`
|
InstanceId types.String `tfsdk:"instance_id"`
|
||||||
Name types.String `tfsdk:"name"`
|
Name types.String `tfsdk:"name"`
|
||||||
Owner types.String `tfsdk:"owner"`
|
Owner types.String `tfsdk:"owner"`
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
||||||
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api"
|
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api"
|
||||||
|
|
||||||
|
|
@ -72,7 +73,13 @@ func (r *instanceDataSource) Configure(
|
||||||
|
|
||||||
// Schema defines the schema for the data source.
|
// Schema defines the schema for the data source.
|
||||||
func (r *instanceDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
func (r *instanceDataSource) Schema(ctx context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
||||||
resp.Schema = postgresflexalpha2.InstanceDataSourceSchema(ctx)
|
sch := postgresflexalpha2.InstanceDataSourceSchema(ctx)
|
||||||
|
sch.Attributes["id"] = schema.StringAttribute{
|
||||||
|
Computed: true,
|
||||||
|
Description: "internal ID",
|
||||||
|
MarkdownDescription: "internal ID",
|
||||||
|
}
|
||||||
|
resp.Schema = sch
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read refreshes the Terraform state with the latest data.
|
// Read refreshes the Terraform state with the latest data.
|
||||||
|
|
@ -90,22 +97,22 @@ func (r *instanceDataSource) Read(
|
||||||
|
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
projectId := model.ProjectId.ValueString()
|
projectID := model.ProjectId.ValueString()
|
||||||
instanceId := model.InstanceId.ValueString()
|
instanceID := model.InstanceId.ValueString()
|
||||||
region := r.providerData.GetRegionWithOverride(model.Region)
|
region := r.providerData.GetRegionWithOverride(model.Region)
|
||||||
ctx = tflog.SetField(ctx, "project_id", projectId)
|
ctx = tflog.SetField(ctx, "project_id", projectID)
|
||||||
ctx = tflog.SetField(ctx, "instance_id", instanceId)
|
ctx = tflog.SetField(ctx, "instance_id", instanceID)
|
||||||
ctx = tflog.SetField(ctx, "region", region)
|
ctx = tflog.SetField(ctx, "region", region)
|
||||||
instanceResp, err := r.client.DefaultAPI.GetInstanceRequest(ctx, projectId, region, instanceId).Execute()
|
instanceResp, err := r.client.DefaultAPI.GetInstanceRequest(ctx, projectID, region, instanceID).Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utils.LogError(
|
utils.LogError(
|
||||||
ctx,
|
ctx,
|
||||||
&resp.Diagnostics,
|
&resp.Diagnostics,
|
||||||
err,
|
err,
|
||||||
"Reading instance",
|
"Reading instance",
|
||||||
fmt.Sprintf("Instance with ID %q does not exist in project %q.", instanceId, projectId),
|
fmt.Sprintf("Instance with ID %q does not exist in project %q.", instanceID, projectID),
|
||||||
map[int]string{
|
map[int]string{
|
||||||
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectId),
|
http.StatusForbidden: fmt.Sprintf("Project with ID %q not found or forbidden access", projectID),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
resp.State.RemoveResource(ctx)
|
resp.State.RemoveResource(ctx)
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@ func InstanceDataSourceSchema(ctx context.Context) schema.Schema {
|
||||||
MarkdownDescription: "The STACKIT project ID.",
|
MarkdownDescription: "The STACKIT project ID.",
|
||||||
},
|
},
|
||||||
"region": schema.StringAttribute{
|
"region": schema.StringAttribute{
|
||||||
Required: true,
|
Optional: true,
|
||||||
Description: "The region which should be addressed",
|
Description: "The region which should be addressed",
|
||||||
MarkdownDescription: "The region which should be addressed",
|
MarkdownDescription: "The region which should be addressed",
|
||||||
Validators: []validator.String{
|
Validators: []validator.String{
|
||||||
|
|
|
||||||
|
|
@ -66,12 +66,12 @@ func mapGetInstanceResponseToModel(
|
||||||
|
|
||||||
m.IsDeletable = types.BoolValue(resp.GetIsDeletable())
|
m.IsDeletable = types.BoolValue(resp.GetIsDeletable())
|
||||||
|
|
||||||
netAcl, diags := types.ListValueFrom(ctx, types.StringType, resp.Network.GetAcl())
|
netACL, diags := types.ListValueFrom(ctx, types.StringType, resp.Network.GetAcl())
|
||||||
if diags.HasError() {
|
if diags.HasError() {
|
||||||
return fmt.Errorf("failed converting network acl from response")
|
return fmt.Errorf("failed converting network acl from response")
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Acl = netAcl
|
m.Acl = netACL
|
||||||
|
|
||||||
netInstAdd := types.StringValue("")
|
netInstAdd := types.StringValue("")
|
||||||
if instAdd, ok := resp.Network.GetInstanceAddressOk(); ok {
|
if instAdd, ok := resp.Network.GetInstanceAddressOk(); ok {
|
||||||
|
|
@ -87,7 +87,7 @@ func mapGetInstanceResponseToModel(
|
||||||
postgresflexalpharesource.NetworkValue{}.AttributeTypes(ctx),
|
postgresflexalpharesource.NetworkValue{}.AttributeTypes(ctx),
|
||||||
map[string]attr.Value{
|
map[string]attr.Value{
|
||||||
"access_scope": basetypes.NewStringValue(string(resp.Network.GetAccessScope())),
|
"access_scope": basetypes.NewStringValue(string(resp.Network.GetAccessScope())),
|
||||||
"acl": netAcl,
|
"acl": netACL,
|
||||||
"instance_address": netInstAdd,
|
"instance_address": netInstAdd,
|
||||||
"router_address": netRtrAdd,
|
"router_address": netRtrAdd,
|
||||||
},
|
},
|
||||||
|
|
@ -130,7 +130,8 @@ func mapGetDataInstanceResponseToModel(
|
||||||
handleConnectionInfo(ctx, m, resp)
|
handleConnectionInfo(ctx, m, resp)
|
||||||
|
|
||||||
m.FlavorId = types.StringValue(resp.GetFlavorId())
|
m.FlavorId = types.StringValue(resp.GetFlavorId())
|
||||||
m.Id = utils.BuildInternalTerraformId(m.ProjectId.ValueString(), m.Region.ValueString(), m.InstanceId.ValueString())
|
m.Id = types.StringValue(resp.Id)
|
||||||
|
m.TerraformID = utils.BuildInternalTerraformId(m.ProjectId.ValueString(), m.Region.ValueString(), m.InstanceId.ValueString())
|
||||||
m.InstanceId = types.StringValue(resp.Id)
|
m.InstanceId = types.StringValue(resp.Id)
|
||||||
m.IsDeletable = types.BoolValue(resp.GetIsDeletable())
|
m.IsDeletable = types.BoolValue(resp.GetIsDeletable())
|
||||||
m.Name = types.StringValue(resp.GetName())
|
m.Name = types.StringValue(resp.GetName())
|
||||||
|
|
@ -212,14 +213,14 @@ func handleNetwork(ctx context.Context, m *dataSourceModel, resp *postgresflex.G
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleEncryption(m *dataSourceModel, resp *postgresflex.GetInstanceResponse) {
|
func handleEncryption(m *dataSourceModel, resp *postgresflex.GetInstanceResponse) {
|
||||||
keyId := ""
|
keyID := ""
|
||||||
if keyIdVal, ok := resp.Encryption.GetKekKeyIdOk(); ok {
|
if keyIDVal, ok := resp.Encryption.GetKekKeyIdOk(); ok {
|
||||||
keyId = *keyIdVal
|
keyID = *keyIDVal
|
||||||
}
|
}
|
||||||
|
|
||||||
keyRingId := ""
|
keyRingID := ""
|
||||||
if keyRingIdVal, ok := resp.Encryption.GetKekKeyRingIdOk(); ok {
|
if keyRingIDVal, ok := resp.Encryption.GetKekKeyRingIdOk(); ok {
|
||||||
keyRingId = *keyRingIdVal
|
keyRingID = *keyRingIDVal
|
||||||
}
|
}
|
||||||
|
|
||||||
keyVersion := ""
|
keyVersion := ""
|
||||||
|
|
@ -233,8 +234,8 @@ func handleEncryption(m *dataSourceModel, resp *postgresflex.GetInstanceResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
m.Encryption = postgresflexalphadatasource.EncryptionValue{
|
m.Encryption = postgresflexalphadatasource.EncryptionValue{
|
||||||
KekKeyId: types.StringValue(keyId),
|
KekKeyId: types.StringValue(keyID),
|
||||||
KekKeyRingId: types.StringValue(keyRingId),
|
KekKeyRingId: types.StringValue(keyRingID),
|
||||||
KekKeyVersion: types.StringValue(keyVersion),
|
KekKeyVersion: types.StringValue(keyVersion),
|
||||||
ServiceAccount: types.StringValue(svcAcc),
|
ServiceAccount: types.StringValue(svcAcc),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,6 @@ import (
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-framework/path"
|
"github.com/hashicorp/terraform-plugin-framework/path"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource"
|
"github.com/hashicorp/terraform-plugin-framework/resource"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/identityschema"
|
|
||||||
"github.com/hashicorp/terraform-plugin-framework/types"
|
|
||||||
"github.com/hashicorp/terraform-plugin-log/tflog"
|
"github.com/hashicorp/terraform-plugin-log/tflog"
|
||||||
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
|
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
|
||||||
coreUtils "github.com/stackitcloud/stackit-sdk-go/core/utils"
|
coreUtils "github.com/stackitcloud/stackit-sdk-go/core/utils"
|
||||||
|
|
@ -33,7 +31,6 @@ var (
|
||||||
_ resource.ResourceWithImportState = &instanceResource{}
|
_ resource.ResourceWithImportState = &instanceResource{}
|
||||||
_ resource.ResourceWithModifyPlan = &instanceResource{}
|
_ resource.ResourceWithModifyPlan = &instanceResource{}
|
||||||
_ resource.ResourceWithValidateConfig = &instanceResource{}
|
_ resource.ResourceWithValidateConfig = &instanceResource{}
|
||||||
_ resource.ResourceWithIdentity = &instanceResource{}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewInstanceResource is a helper function to simplify the provider implementation.
|
// NewInstanceResource is a helper function to simplify the provider implementation.
|
||||||
|
|
@ -41,15 +38,6 @@ func NewInstanceResource() resource.Resource {
|
||||||
return &instanceResource{}
|
return &instanceResource{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// resourceModel describes the resource data model.
|
|
||||||
type resourceModel = postgresflexalpha.InstanceModel
|
|
||||||
|
|
||||||
type InstanceResourceIdentityModel struct {
|
|
||||||
ProjectID types.String `tfsdk:"project_id"`
|
|
||||||
Region types.String `tfsdk:"region"`
|
|
||||||
InstanceID types.String `tfsdk:"instance_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// instanceResource is the resource implementation.
|
// instanceResource is the resource implementation.
|
||||||
type instanceResource struct {
|
type instanceResource struct {
|
||||||
client *v3alpha1api.APIClient
|
client *v3alpha1api.APIClient
|
||||||
|
|
@ -61,7 +49,7 @@ func (r *instanceResource) ValidateConfig(
|
||||||
req resource.ValidateConfigRequest,
|
req resource.ValidateConfigRequest,
|
||||||
resp *resource.ValidateConfigResponse,
|
resp *resource.ValidateConfigResponse,
|
||||||
) {
|
) {
|
||||||
var data resourceModel
|
var data postgresflexalpha.InstanceModel
|
||||||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
|
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
|
||||||
|
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
|
|
@ -85,7 +73,7 @@ func (r *instanceResource) ModifyPlan(
|
||||||
req resource.ModifyPlanRequest,
|
req resource.ModifyPlanRequest,
|
||||||
resp *resource.ModifyPlanResponse,
|
resp *resource.ModifyPlanResponse,
|
||||||
) { // nolint:gocritic // function signature required by Terraform
|
) { // nolint:gocritic // function signature required by Terraform
|
||||||
var configModel resourceModel
|
var configModel postgresflexalpha.InstanceModel
|
||||||
// skip initial empty configuration to avoid follow-up errors
|
// skip initial empty configuration to avoid follow-up errors
|
||||||
if req.Config.Raw.IsNull() {
|
if req.Config.Raw.IsNull() {
|
||||||
return
|
return
|
||||||
|
|
@ -95,7 +83,7 @@ func (r *instanceResource) ModifyPlan(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var planModel resourceModel
|
var planModel postgresflexalpha.InstanceModel
|
||||||
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
|
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
return
|
return
|
||||||
|
|
@ -161,33 +149,13 @@ func (r *instanceResource) Schema(ctx context.Context, _ resource.SchemaRequest,
|
||||||
resp.Schema = schema
|
resp.Schema = schema
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *instanceResource) IdentitySchema(
|
|
||||||
_ context.Context,
|
|
||||||
_ resource.IdentitySchemaRequest,
|
|
||||||
resp *resource.IdentitySchemaResponse,
|
|
||||||
) {
|
|
||||||
resp.IdentitySchema = identityschema.Schema{
|
|
||||||
Attributes: map[string]identityschema.Attribute{
|
|
||||||
"project_id": identityschema.StringAttribute{
|
|
||||||
RequiredForImport: true, // must be set during import by the practitioner
|
|
||||||
},
|
|
||||||
"region": identityschema.StringAttribute{
|
|
||||||
RequiredForImport: true, // can be defaulted by the provider configuration
|
|
||||||
},
|
|
||||||
"instance_id": identityschema.StringAttribute{
|
|
||||||
RequiredForImport: true, // can be defaulted by the provider configuration
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create creates the resource and sets the initial Terraform state.
|
// Create creates the resource and sets the initial Terraform state.
|
||||||
func (r *instanceResource) Create(
|
func (r *instanceResource) Create(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
req resource.CreateRequest,
|
req resource.CreateRequest,
|
||||||
resp *resource.CreateResponse,
|
resp *resource.CreateResponse,
|
||||||
) { // nolint:gocritic // function signature required by Terraform
|
) { // nolint:gocritic // function signature required by Terraform
|
||||||
var model resourceModel
|
var model postgresflexalpha.InstanceModel
|
||||||
|
|
||||||
diags := req.Plan.Get(ctx, &model)
|
diags := req.Plan.Get(ctx, &model)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
|
|
@ -202,15 +170,15 @@ func (r *instanceResource) Create(
|
||||||
ctx = tflog.SetField(ctx, "project_id", projectID)
|
ctx = tflog.SetField(ctx, "project_id", projectID)
|
||||||
ctx = tflog.SetField(ctx, "region", region)
|
ctx = tflog.SetField(ctx, "region", region)
|
||||||
|
|
||||||
var netAcl []string
|
var netACL []string
|
||||||
diag := model.Network.Acl.ElementsAs(ctx, &netAcl, false)
|
diag := model.Network.Acl.ElementsAs(ctx, &netACL, false)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
if diag.HasError() {
|
if diag.HasError() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
replVal := model.Replicas.ValueInt64() // nolint:gosec // check is performed above
|
replVal := model.Replicas.ValueInt64() // nolint:gosec // check is performed above
|
||||||
payload := modelToCreateInstancePayload(netAcl, model, replVal)
|
payload := modelToCreateInstancePayload(netACL, model, replVal)
|
||||||
|
|
||||||
// Create new instance
|
// Create new instance
|
||||||
createResp, err := r.client.DefaultAPI.CreateInstanceRequest(
|
createResp, err := r.client.DefaultAPI.CreateInstanceRequest(
|
||||||
|
|
@ -230,16 +198,14 @@ func (r *instanceResource) Create(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set data returned by API in identity
|
// Set data returned by API in id
|
||||||
identity := InstanceResourceIdentityModel{
|
resp.Diagnostics.Append(
|
||||||
ProjectID: types.StringValue(projectID),
|
resp.State.SetAttribute(
|
||||||
Region: types.StringValue(region),
|
ctx,
|
||||||
InstanceID: types.StringPointerValue(instanceID),
|
path.Root("id"),
|
||||||
}
|
utils.BuildInternalTerraformId(projectID, region, *instanceID),
|
||||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
)...,
|
||||||
if resp.Diagnostics.HasError() {
|
)
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectID, region, *instanceID).
|
waitResp, err := wait.CreateInstanceWaitHandler(ctx, r.client.DefaultAPI, projectID, region, *instanceID).
|
||||||
SetTimeout(30 * time.Minute).
|
SetTimeout(30 * time.Minute).
|
||||||
|
|
@ -317,7 +283,7 @@ func (r *instanceResource) Read(
|
||||||
) { // nolint:gocritic // function signature required by Terraform
|
) { // nolint:gocritic // function signature required by Terraform
|
||||||
functionErrorSummary := "read instance failed"
|
functionErrorSummary := "read instance failed"
|
||||||
|
|
||||||
var model resourceModel
|
var model postgresflexalpha.InstanceModel
|
||||||
diags := req.State.Get(ctx, &model)
|
diags := req.State.Get(ctx, &model)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
|
|
@ -326,9 +292,9 @@ func (r *instanceResource) Read(
|
||||||
|
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
var projectId string
|
var projectID string
|
||||||
if !model.ProjectId.IsNull() && !model.ProjectId.IsUnknown() {
|
if !model.ProjectId.IsNull() && !model.ProjectId.IsUnknown() {
|
||||||
projectId = model.ProjectId.ValueString()
|
projectID = model.ProjectId.ValueString()
|
||||||
}
|
}
|
||||||
|
|
||||||
var region string
|
var region string
|
||||||
|
|
@ -336,16 +302,16 @@ func (r *instanceResource) Read(
|
||||||
region = r.providerData.GetRegionWithOverride(model.Region)
|
region = r.providerData.GetRegionWithOverride(model.Region)
|
||||||
}
|
}
|
||||||
|
|
||||||
var instanceId string
|
var instanceID string
|
||||||
if !model.InstanceId.IsNull() && !model.InstanceId.IsUnknown() {
|
if !model.InstanceId.IsNull() && !model.InstanceId.IsUnknown() {
|
||||||
instanceId = model.InstanceId.ValueString()
|
instanceID = model.InstanceId.ValueString()
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = tflog.SetField(ctx, "project_id", projectId)
|
ctx = tflog.SetField(ctx, "project_id", projectID)
|
||||||
ctx = tflog.SetField(ctx, "instance_id", instanceId)
|
ctx = tflog.SetField(ctx, "instance_id", instanceID)
|
||||||
ctx = tflog.SetField(ctx, "region", region)
|
ctx = tflog.SetField(ctx, "region", region)
|
||||||
|
|
||||||
instanceResp, err := r.client.DefaultAPI.GetInstanceRequest(ctx, projectId, region, instanceId).Execute()
|
instanceResp, err := r.client.DefaultAPI.GetInstanceRequest(ctx, projectID, region, instanceID).Execute()
|
||||||
if err != nil {
|
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
|
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 {
|
if ok && oapiErr.StatusCode == http.StatusNotFound {
|
||||||
|
|
@ -364,7 +330,7 @@ func (r *instanceResource) Read(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !model.InstanceId.IsUnknown() && !model.InstanceId.IsNull() {
|
if !model.InstanceId.IsUnknown() && !model.InstanceId.IsNull() {
|
||||||
if *respInstanceID != instanceId {
|
if *respInstanceID != instanceID {
|
||||||
core.LogAndAddError(
|
core.LogAndAddError(
|
||||||
ctx,
|
ctx,
|
||||||
&resp.Diagnostics,
|
&resp.Diagnostics,
|
||||||
|
|
@ -375,6 +341,10 @@ func (r *instanceResource) Read(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !model.Id.IsUnknown() && !model.Id.IsNull() {
|
||||||
|
model.Id = utils.BuildInternalTerraformId(projectID, region, instanceID)
|
||||||
|
}
|
||||||
|
|
||||||
err = mapGetInstanceResponseToModel(ctx, &model, instanceResp)
|
err = mapGetInstanceResponseToModel(ctx, &model, instanceResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(
|
core.LogAndAddError(
|
||||||
|
|
@ -392,17 +362,6 @@ func (r *instanceResource) Read(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set data returned by API in identity
|
|
||||||
identity := InstanceResourceIdentityModel{
|
|
||||||
ProjectID: types.StringValue(projectId),
|
|
||||||
Region: types.StringValue(region),
|
|
||||||
InstanceID: types.StringValue(instanceId),
|
|
||||||
}
|
|
||||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
|
||||||
if resp.Diagnostics.HasError() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tflog.Info(ctx, "Postgres Flex instance read")
|
tflog.Info(ctx, "Postgres Flex instance read")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -412,7 +371,7 @@ func (r *instanceResource) Update(
|
||||||
req resource.UpdateRequest,
|
req resource.UpdateRequest,
|
||||||
resp *resource.UpdateResponse,
|
resp *resource.UpdateResponse,
|
||||||
) { // nolint:gocritic // function signature required by Terraform
|
) { // nolint:gocritic // function signature required by Terraform
|
||||||
var model resourceModel
|
var model postgresflexalpha.InstanceModel
|
||||||
|
|
||||||
diags := req.Plan.Get(ctx, &model)
|
diags := req.Plan.Get(ctx, &model)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
|
|
@ -422,15 +381,8 @@ func (r *instanceResource) Update(
|
||||||
|
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
// Read identity data
|
projectID := model.ProjectId.ValueString()
|
||||||
var identityData InstanceResourceIdentityModel
|
instanceID := model.InstanceId.ValueString()
|
||||||
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
|
||||||
if resp.Diagnostics.HasError() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
projectID := identityData.ProjectID.ValueString()
|
|
||||||
instanceID := identityData.InstanceID.ValueString()
|
|
||||||
region := model.Region.ValueString()
|
region := model.Region.ValueString()
|
||||||
ctx = tflog.SetField(ctx, "project_id", projectID)
|
ctx = tflog.SetField(ctx, "project_id", projectID)
|
||||||
ctx = tflog.SetField(ctx, "instance_id", instanceID)
|
ctx = tflog.SetField(ctx, "instance_id", instanceID)
|
||||||
|
|
@ -532,7 +484,7 @@ func (r *instanceResource) Delete(
|
||||||
req resource.DeleteRequest,
|
req resource.DeleteRequest,
|
||||||
resp *resource.DeleteResponse,
|
resp *resource.DeleteResponse,
|
||||||
) { // nolint:gocritic // function signature required by Terraform
|
) { // nolint:gocritic // function signature required by Terraform
|
||||||
var model resourceModel
|
var model postgresflexalpha.InstanceModel
|
||||||
|
|
||||||
diags := req.State.Get(ctx, &model)
|
diags := req.State.Get(ctx, &model)
|
||||||
resp.Diagnostics.Append(diags...)
|
resp.Diagnostics.Append(diags...)
|
||||||
|
|
@ -542,15 +494,15 @@ func (r *instanceResource) Delete(
|
||||||
|
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
projectId := model.ProjectId.ValueString()
|
projectID := model.ProjectId.ValueString()
|
||||||
instanceId := model.InstanceId.ValueString()
|
instanceID := model.InstanceId.ValueString()
|
||||||
region := model.Region.ValueString()
|
region := model.Region.ValueString()
|
||||||
ctx = tflog.SetField(ctx, "project_id", projectId)
|
ctx = tflog.SetField(ctx, "project_id", projectID)
|
||||||
ctx = tflog.SetField(ctx, "instance_id", instanceId)
|
ctx = tflog.SetField(ctx, "instance_id", instanceID)
|
||||||
ctx = tflog.SetField(ctx, "region", region)
|
ctx = tflog.SetField(ctx, "region", region)
|
||||||
|
|
||||||
// Delete existing instance
|
// Delete existing instance
|
||||||
err := r.client.DefaultAPI.DeleteInstanceRequest(ctx, projectId, region, instanceId).Execute()
|
err := r.client.DefaultAPI.DeleteInstanceRequest(ctx, projectID, region, instanceID).Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Calling API: %v", err))
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting instance", fmt.Sprintf("Calling API: %v", err))
|
||||||
return
|
return
|
||||||
|
|
@ -558,7 +510,7 @@ func (r *instanceResource) Delete(
|
||||||
|
|
||||||
ctx = core.LogResponse(ctx)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
_, err = r.client.DefaultAPI.GetInstanceRequest(ctx, projectId, region, instanceId).Execute()
|
_, err = r.client.DefaultAPI.GetInstanceRequest(ctx, projectID, region, instanceID).Execute()
|
||||||
if err != nil {
|
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
|
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 {
|
if ok && oapiErr.StatusCode != http.StatusNotFound {
|
||||||
|
|
@ -580,41 +532,30 @@ func (r *instanceResource) ImportState(
|
||||||
) {
|
) {
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
if req.ID != "" {
|
idParts := strings.Split(req.ID, core.Separator)
|
||||||
idParts := strings.Split(req.ID, core.Separator)
|
|
||||||
|
|
||||||
if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" {
|
if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" {
|
||||||
core.LogAndAddError(
|
core.LogAndAddError(
|
||||||
ctx, &resp.Diagnostics,
|
ctx, &resp.Diagnostics,
|
||||||
"Error importing instance",
|
"Error importing instance",
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"Expected import identifier with format [project_id],[region],[instance_id] Got: %q",
|
"Expected import identifier with format [project_id],[region],[instance_id] Got: %q",
|
||||||
req.ID,
|
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("region"), idParts[1])...)
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no ID is provided, attempt to read identity attributes from the import configuration
|
resp.Diagnostics.Append(
|
||||||
var identityData InstanceResourceIdentityModel
|
resp.State.SetAttribute(
|
||||||
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
ctx,
|
||||||
if resp.Diagnostics.HasError() {
|
path.Root("id"),
|
||||||
return
|
utils.BuildInternalTerraformId(idParts...),
|
||||||
}
|
)...,
|
||||||
|
)
|
||||||
projectId := identityData.ProjectID.ValueString()
|
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...)
|
||||||
region := identityData.Region.ValueString()
|
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...)
|
||||||
instanceId := identityData.InstanceID.ValueString()
|
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...)
|
||||||
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), projectId)...)
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), region)...)
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), instanceId)...)
|
|
||||||
|
|
||||||
tflog.Info(ctx, "Postgres Flex instance state imported")
|
tflog.Info(ctx, "Postgres Flex instance state imported")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
pfx = "stackitprivatepreview_postgresflexalpha"
|
pfx = "stackitprivatepreview_postgresflexalpha"
|
||||||
|
dataPfx = "data.stackitprivatepreview_postgresflexalpha"
|
||||||
|
|
||||||
singleFlavorID = "2.4"
|
singleFlavorID = "2.4"
|
||||||
replicasFlavorID = "2.4-replica"
|
replicasFlavorID = "2.4-replica"
|
||||||
|
|
@ -100,6 +101,7 @@ type resData struct {
|
||||||
Version string
|
Version string
|
||||||
Users []User
|
Users []User
|
||||||
Databases []Database
|
Databases []Database
|
||||||
|
DataSourceTest bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
|
|
@ -137,6 +139,7 @@ func getExample() resData {
|
||||||
|
|
||||||
func TestAccInstance(t *testing.T) {
|
func TestAccInstance(t *testing.T) {
|
||||||
exData := getExample()
|
exData := getExample()
|
||||||
|
exData.Version = "16"
|
||||||
|
|
||||||
updNameData := exData
|
updNameData := exData
|
||||||
updNameData.Name = "name-updated"
|
updNameData.Name = "name-updated"
|
||||||
|
|
@ -151,6 +154,9 @@ func TestAccInstance(t *testing.T) {
|
||||||
updNetACL := updBackupSched
|
updNetACL := updBackupSched
|
||||||
updNetACL.ACLStrings = append(updNetACL.ACLStrings, "192.168.0.0/24")
|
updNetACL.ACLStrings = append(updNetACL.ACLStrings, "192.168.0.0/24")
|
||||||
|
|
||||||
|
updVersion := updNetACL
|
||||||
|
updVersion.Version = "17"
|
||||||
|
|
||||||
testItemID := testutils.ResStr(pfx, "instance", exData.TfName)
|
testItemID := testutils.ResStr(pfx, "instance", exData.TfName)
|
||||||
compareValuesSame := statecheck.CompareValue(compare.ValuesSame())
|
compareValuesSame := statecheck.CompareValue(compare.ValuesSame())
|
||||||
resource.ParallelTest(
|
resource.ParallelTest(
|
||||||
|
|
@ -299,19 +305,31 @@ func TestAccInstance(t *testing.T) {
|
||||||
resource.TestCheckResourceAttr(testItemID, "network.acl.#", "2"),
|
resource.TestCheckResourceAttr(testItemID, "network.acl.#", "2"),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
// Update version
|
||||||
|
{
|
||||||
|
Config: testutils.StringFromTemplateMust(
|
||||||
|
"testdata/instance_template.gompl",
|
||||||
|
updVersion,
|
||||||
|
),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
testItemID,
|
||||||
|
"version",
|
||||||
|
updVersion.Version,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
// Import test
|
// Import test
|
||||||
/*
|
// test instance imports
|
||||||
{
|
{
|
||||||
ImportState: true,
|
ResourceName: testItemID,
|
||||||
ImportStateKind: resource.ImportBlockWithResourceIdentity,
|
// ImportStateIdPrefix: "",
|
||||||
ResourceName: testItemID,
|
// ImportStateVerifyIdentifierAttribute: "id",
|
||||||
},
|
ImportStateIdFunc: getInstanceTestID(exData.TfName),
|
||||||
{
|
ImportStateKind: resource.ImportCommandWithID,
|
||||||
ImportState: true,
|
ImportState: true,
|
||||||
ImportStateKind: resource.ImportCommandWithID,
|
ImportStateVerify: true,
|
||||||
ResourceName: testItemID,
|
},
|
||||||
},
|
|
||||||
*/
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -410,6 +428,7 @@ func TestAccInstanceWithDatabases(t *testing.T) {
|
||||||
Owner: userName,
|
Owner: userName,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
data.DataSourceTest = true
|
||||||
|
|
||||||
testItemID := testutils.ResStr(pfx, "instance", data.TfName)
|
testItemID := testutils.ResStr(pfx, "instance", data.TfName)
|
||||||
resource.ParallelTest(
|
resource.ParallelTest(
|
||||||
|
|
@ -432,11 +451,145 @@ func TestAccInstanceWithDatabases(t *testing.T) {
|
||||||
|
|
||||||
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "user", userName), "name", userName),
|
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "user", userName), "name", userName),
|
||||||
resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "user", userName), "id"),
|
resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "user", userName), "id"),
|
||||||
|
resource.TestCheckResourceAttrPair(
|
||||||
|
testItemID, "project_id",
|
||||||
|
testutils.ResStr(pfx, "user", userName), "project_id",
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttrPair(
|
||||||
|
testItemID, "instance_id",
|
||||||
|
testutils.ResStr(pfx, "user", userName), "instance_id",
|
||||||
|
),
|
||||||
|
|
||||||
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "name", dbName),
|
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "name", dbName),
|
||||||
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "owner", userName),
|
resource.TestCheckResourceAttr(testutils.ResStr(pfx, "database", dbName), "owner", userName),
|
||||||
resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "database", dbName), "id"),
|
resource.TestCheckResourceAttrSet(testutils.ResStr(pfx, "database", dbName), "id"),
|
||||||
|
resource.TestCheckResourceAttrPair(
|
||||||
|
testItemID, "project_id",
|
||||||
|
testutils.ResStr(pfx, "database", dbName), "project_id",
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttrPair(
|
||||||
|
testItemID, "instance_id",
|
||||||
|
testutils.ResStr(pfx, "database", dbName), "instance_id",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
// data source
|
||||||
|
{
|
||||||
|
Config: testutils.StringFromTemplateMust(
|
||||||
|
"testdata/instance_template.gompl",
|
||||||
|
data,
|
||||||
|
),
|
||||||
|
Check: resource.ComposeAggregateTestCheckFunc(
|
||||||
|
// Instance data
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
testutils.ResStr(dataPfx, "instance", data.TfName),
|
||||||
|
"project_id",
|
||||||
|
data.ProjectID,
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
testutils.ResStr(dataPfx, "instance", data.TfName),
|
||||||
|
"name",
|
||||||
|
data.Name,
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttrPair(
|
||||||
|
testutils.ResStr(dataPfx, "instance", data.TfName), "project_id",
|
||||||
|
testutils.ResStr(pfx, "instance", data.TfName), "project_id",
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttrPair(
|
||||||
|
testutils.ResStr(dataPfx, "database", dbName), "instance_id",
|
||||||
|
testutils.ResStr(pfx, "instance", data.TfName), "instance_id",
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttrPair(
|
||||||
|
testutils.ResStr(dataPfx, "user", userName), "instance_id",
|
||||||
|
testutils.ResStr(pfx, "instance", data.TfName), "instance_id",
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttrPair(
|
||||||
|
testutils.ResStr(dataPfx, "user", userName), "instance_id",
|
||||||
|
testutils.ResStr(pfx, "user", userName), "instance_id",
|
||||||
|
),
|
||||||
|
|
||||||
|
// User data
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
testutils.ResStr(dataPfx, "user", userName),
|
||||||
|
"project_id",
|
||||||
|
data.ProjectID,
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttrSet(
|
||||||
|
testutils.ResStr(dataPfx, "user", userName),
|
||||||
|
"user_id",
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
testutils.ResStr(dataPfx, "user", userName),
|
||||||
|
"name",
|
||||||
|
data.Users[0].Name,
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
testutils.ResStr(dataPfx, "user", userName),
|
||||||
|
"roles.#",
|
||||||
|
"1",
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
testutils.ResStr(dataPfx, "user", userName),
|
||||||
|
"roles.0",
|
||||||
|
data.Users[0].Roles[0],
|
||||||
|
),
|
||||||
|
|
||||||
|
// Database data
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
testutils.ResStr(dataPfx, "database", dbName),
|
||||||
|
"project_id",
|
||||||
|
data.ProjectID,
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
testutils.ResStr(dataPfx, "database", dbName),
|
||||||
|
"name",
|
||||||
|
dbName,
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttrPair(
|
||||||
|
testutils.ResStr(dataPfx, "database", dbName),
|
||||||
|
"instance_id",
|
||||||
|
testutils.ResStr(pfx, "database", dbName),
|
||||||
|
"instance_id",
|
||||||
|
),
|
||||||
|
resource.TestCheckResourceAttrPair(
|
||||||
|
testutils.ResStr(dataPfx, "database", dbName),
|
||||||
|
"owner",
|
||||||
|
testutils.ResStr(dataPfx, "user", userName),
|
||||||
|
"name",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
// test instance imports
|
||||||
|
{
|
||||||
|
ResourceName: testItemID,
|
||||||
|
// ImportStateIdPrefix: "",
|
||||||
|
ImportStateVerifyIdentifierAttribute: "id",
|
||||||
|
ImportStateIdFunc: getInstanceTestID(data.TfName),
|
||||||
|
ImportStateKind: resource.ImportCommandWithID,
|
||||||
|
ImportState: true,
|
||||||
|
ImportStateVerify: true,
|
||||||
|
},
|
||||||
|
// test database imports
|
||||||
|
{
|
||||||
|
ResourceName: testutils.ResStr(pfx, "database", dbName),
|
||||||
|
// ImportStateIdPrefix: "",
|
||||||
|
// ImportStateVerifyIdentifierAttribute: "id",
|
||||||
|
ImportStateIdFunc: getDatabaseTestID(dbName),
|
||||||
|
ImportStateKind: resource.ImportCommandWithID,
|
||||||
|
ImportState: true,
|
||||||
|
ImportStateVerify: true,
|
||||||
|
},
|
||||||
|
// test user imports
|
||||||
|
{
|
||||||
|
ResourceName: testutils.ResStr(pfx, "user", userName),
|
||||||
|
// ImportStateIdPrefix: "",
|
||||||
|
// ImportStateVerifyIdentifierAttribute: "id",
|
||||||
|
ImportStateIdFunc: getUserTestID(userName),
|
||||||
|
ImportStateKind: resource.ImportCommandWithID,
|
||||||
|
ImportState: true,
|
||||||
|
ImportStateVerify: true,
|
||||||
|
ImportStateVerifyIgnore: []string{"password"},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -614,10 +767,6 @@ func defaultNoEncInstanceTestChecks(testItemID string, data resData) resource.Te
|
||||||
return resource.ComposeAggregateTestCheckFunc(
|
return resource.ComposeAggregateTestCheckFunc(
|
||||||
defaultInstanceTestChecks(testItemID, data),
|
defaultInstanceTestChecks(testItemID, data),
|
||||||
|
|
||||||
// on unencrypted instances we expect this to be empty
|
|
||||||
resource.TestCheckResourceAttr(testItemID, "network.instance_address", ""),
|
|
||||||
resource.TestCheckResourceAttr(testItemID, "network.router_address", ""),
|
|
||||||
|
|
||||||
// check absent attr
|
// check absent attr
|
||||||
resource.TestCheckNoResourceAttr(testItemID, "encryption"),
|
resource.TestCheckNoResourceAttr(testItemID, "encryption"),
|
||||||
resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_id"),
|
resource.TestCheckNoResourceAttr(testItemID, "encryption.kek_key_id"),
|
||||||
|
|
@ -631,10 +780,6 @@ func defaultEncInstanceTestChecks(testItemID string, data resData) resource.Test
|
||||||
return resource.ComposeAggregateTestCheckFunc(
|
return resource.ComposeAggregateTestCheckFunc(
|
||||||
defaultInstanceTestChecks(testItemID, data),
|
defaultInstanceTestChecks(testItemID, data),
|
||||||
|
|
||||||
// on unencrypted instances we expect this to be empty
|
|
||||||
resource.TestCheckResourceAttrSet(testItemID, "network.instance_address"),
|
|
||||||
resource.TestCheckResourceAttrSet(testItemID, "network.router_address"),
|
|
||||||
|
|
||||||
// check absent attr
|
// check absent attr
|
||||||
resource.TestCheckResourceAttr(testItemID, "encryption.%", "4"),
|
resource.TestCheckResourceAttr(testItemID, "encryption.%", "4"),
|
||||||
resource.TestCheckResourceAttrSet(testItemID, "encryption.kek_key_id"),
|
resource.TestCheckResourceAttrSet(testItemID, "encryption.kek_key_id"),
|
||||||
|
|
@ -649,6 +794,24 @@ func defaultEncInstanceTestChecks(testItemID string, data resData) resource.Test
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc {
|
func defaultInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc {
|
||||||
|
// if AccessScope == SNA these are set
|
||||||
|
if data.AccessScope == "SNA" {
|
||||||
|
return resource.ComposeAggregateTestCheckFunc(
|
||||||
|
basicInstanceTestChecks(testItemID, data),
|
||||||
|
resource.TestCheckResourceAttrSet(testItemID, "network.instance_address"),
|
||||||
|
resource.TestCheckResourceAttrSet(testItemID, "network.router_address"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if AccessScope == PUBLIC these are empty - but they are set
|
||||||
|
return resource.ComposeAggregateTestCheckFunc(
|
||||||
|
basicInstanceTestChecks(testItemID, data),
|
||||||
|
resource.TestCheckResourceAttr(testItemID, "network.instance_address", ""),
|
||||||
|
resource.TestCheckResourceAttr(testItemID, "network.router_address", ""),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func basicInstanceTestChecks(testItemID string, data resData) resource.TestCheckFunc {
|
||||||
return resource.ComposeAggregateTestCheckFunc(
|
return resource.ComposeAggregateTestCheckFunc(
|
||||||
resource.TestCheckResourceAttrSet(testItemID, "backup_schedule"),
|
resource.TestCheckResourceAttrSet(testItemID, "backup_schedule"),
|
||||||
resource.TestCheckResourceAttr(testItemID, "backup_schedule", data.BackupSchedule),
|
resource.TestCheckResourceAttr(testItemID, "backup_schedule", data.BackupSchedule),
|
||||||
|
|
@ -704,3 +867,77 @@ func defaultInstanceTestChecks(testItemID string, data resData) resource.TestChe
|
||||||
resource.TestCheckResourceAttr(testItemID, "version", data.Version),
|
resource.TestCheckResourceAttr(testItemID, "version", data.Version),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getInstanceTestID(name string) func(s *terraform.State) (string, error) {
|
||||||
|
return func(s *terraform.State) (string, error) {
|
||||||
|
r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "instance", name)]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name)
|
||||||
|
}
|
||||||
|
projectID, ok := r.Primary.Attributes["project_id"]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't find attribute project_id")
|
||||||
|
}
|
||||||
|
region, ok := r.Primary.Attributes["region"]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't find attribute region")
|
||||||
|
}
|
||||||
|
instanceID, ok := r.Primary.Attributes["instance_id"]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't find attribute instance_id")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s,%s,%s", projectID, region, instanceID), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDatabaseTestID(name string) func(s *terraform.State) (string, error) {
|
||||||
|
return func(s *terraform.State) (string, error) {
|
||||||
|
r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "database", name)]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name)
|
||||||
|
}
|
||||||
|
projectID, ok := r.Primary.Attributes["project_id"]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't find attribute project_id")
|
||||||
|
}
|
||||||
|
region, ok := r.Primary.Attributes["region"]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't find attribute region")
|
||||||
|
}
|
||||||
|
instanceID, ok := r.Primary.Attributes["instance_id"]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't find attribute instance_id")
|
||||||
|
}
|
||||||
|
databaseID, ok := r.Primary.Attributes["database_id"]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't find attribute database_id")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s,%s,%s,%s", projectID, region, instanceID, databaseID), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getUserTestID(name string) func(s *terraform.State) (string, error) {
|
||||||
|
return func(s *terraform.State) (string, error) {
|
||||||
|
r, ok := s.RootModule().Resources[testutils.ResStr(pfx, "user", name)]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't find resource stackitprivatepreview_postgresflexalpha_instance.%s", name)
|
||||||
|
}
|
||||||
|
projectID, ok := r.Primary.Attributes["project_id"]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't find attribute project_id")
|
||||||
|
}
|
||||||
|
region, ok := r.Primary.Attributes["region"]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't find attribute region")
|
||||||
|
}
|
||||||
|
instanceID, ok := r.Primary.Attributes["instance_id"]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't find attribute instance_id")
|
||||||
|
}
|
||||||
|
userID, ok := r.Primary.Attributes["user_id"]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("couldn't find attribute user_id")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s,%s,%s,%s", projectID, region, instanceID, userID), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,9 @@ resource "stackitprivatepreview_postgresflexalpha_instance" "{{ .TfName }}" {
|
||||||
{{ $tfName := .TfName }}
|
{{ $tfName := .TfName }}
|
||||||
{{ range $user := .Users }}
|
{{ range $user := .Users }}
|
||||||
resource "stackitprivatepreview_postgresflexalpha_user" "{{ $user.Name }}" {
|
resource "stackitprivatepreview_postgresflexalpha_user" "{{ $user.Name }}" {
|
||||||
|
depends_on = [
|
||||||
|
stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}
|
||||||
|
]
|
||||||
project_id = "{{ $user.ProjectID }}"
|
project_id = "{{ $user.ProjectID }}"
|
||||||
instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.instance_id
|
instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.instance_id
|
||||||
name = "{{ $user.Name }}"
|
name = "{{ $user.Name }}"
|
||||||
|
|
@ -45,6 +48,10 @@ resource "stackitprivatepreview_postgresflexalpha_user" "{{ $user.Name }}" {
|
||||||
{{ $tfName := .TfName }}
|
{{ $tfName := .TfName }}
|
||||||
{{ range $db := .Databases }}
|
{{ range $db := .Databases }}
|
||||||
resource "stackitprivatepreview_postgresflexalpha_database" "{{ $db.Name }}" {
|
resource "stackitprivatepreview_postgresflexalpha_database" "{{ $db.Name }}" {
|
||||||
|
depends_on = [
|
||||||
|
stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }},
|
||||||
|
stackitprivatepreview_postgresflexalpha_user.{{ $db.Owner }}
|
||||||
|
]
|
||||||
project_id = "{{ $db.ProjectID }}"
|
project_id = "{{ $db.ProjectID }}"
|
||||||
instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.instance_id
|
instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.instance_id
|
||||||
name = "{{ $db.Name }}"
|
name = "{{ $db.Name }}"
|
||||||
|
|
@ -52,3 +59,32 @@ resource "stackitprivatepreview_postgresflexalpha_database" "{{ $db.Name }}" {
|
||||||
}
|
}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if .DataSourceTest }}
|
||||||
|
data "stackitprivatepreview_postgresflexalpha_instance" "{{ .TfName }}" {
|
||||||
|
project_id = stackitprivatepreview_postgresflexalpha_instance.{{ .TfName }}.project_id
|
||||||
|
instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ .TfName }}.instance_id
|
||||||
|
}
|
||||||
|
|
||||||
|
{{ if .Users }}
|
||||||
|
{{ $tfName := .TfName }}
|
||||||
|
{{ range $user := .Users }}
|
||||||
|
data "stackitprivatepreview_postgresflexalpha_user" "{{ $user.Name }}" {
|
||||||
|
project_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.project_id
|
||||||
|
instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.instance_id
|
||||||
|
user_id = stackitprivatepreview_postgresflexalpha_user.{{ $user.Name }}.user_id
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if .Databases }}
|
||||||
|
{{ $tfName := .TfName }}
|
||||||
|
{{ range $db := .Databases }}
|
||||||
|
data "stackitprivatepreview_postgresflexalpha_database" "{{ $db.Name }}" {
|
||||||
|
project_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.project_id
|
||||||
|
instance_id = stackitprivatepreview_postgresflexalpha_instance.{{ $tfName }}.instance_id
|
||||||
|
database_id = stackitprivatepreview_postgresflexalpha_database.{{ $db.Name }}.database_id
|
||||||
|
}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ func UserDataSourceSchema(ctx context.Context) schema.Schema {
|
||||||
MarkdownDescription: "The STACKIT project ID.",
|
MarkdownDescription: "The STACKIT project ID.",
|
||||||
},
|
},
|
||||||
"region": schema.StringAttribute{
|
"region": schema.StringAttribute{
|
||||||
Required: true,
|
Optional: true,
|
||||||
Description: "The region which should be addressed",
|
Description: "The region which should be addressed",
|
||||||
MarkdownDescription: "The region which should be addressed",
|
MarkdownDescription: "The region which should be addressed",
|
||||||
Validators: []validator.String{
|
Validators: []validator.String{
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,12 @@ func mapResourceFields(userResp *v3alpha1api.GetUserResponse, model *resourceMod
|
||||||
return fmt.Errorf("user id not present")
|
return fmt.Errorf("user id not present")
|
||||||
}
|
}
|
||||||
|
|
||||||
model.Id = types.Int64Value(userID)
|
model.Id = utils.BuildInternalTerraformId(
|
||||||
|
model.ProjectId.ValueString(),
|
||||||
|
model.Region.ValueString(),
|
||||||
|
model.InstanceId.ValueString(),
|
||||||
|
strconv.FormatInt(userID, 10),
|
||||||
|
)
|
||||||
model.UserId = types.Int64Value(userID)
|
model.UserId = types.Int64Value(userID)
|
||||||
model.Name = types.StringValue(user.Name)
|
model.Name = types.StringValue(user.Name)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform-plugin-framework/diag"
|
"github.com/hashicorp/terraform-plugin-framework/diag"
|
||||||
"github.com/hashicorp/terraform-plugin-framework/resource/identityschema"
|
"github.com/stackitcloud/stackit-sdk-go/core/oapierror"
|
||||||
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api"
|
"github.com/stackitcloud/stackit-sdk-go/services/postgresflex/v3alpha1api"
|
||||||
|
|
||||||
postgresflexalpha "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/user/resources_gen"
|
postgresflexalpha "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit/internal/services/postgresflexalpha/user/resources_gen"
|
||||||
|
|
@ -34,7 +34,6 @@ var (
|
||||||
_ resource.ResourceWithConfigure = &userResource{}
|
_ resource.ResourceWithConfigure = &userResource{}
|
||||||
_ resource.ResourceWithImportState = &userResource{}
|
_ resource.ResourceWithImportState = &userResource{}
|
||||||
_ resource.ResourceWithModifyPlan = &userResource{}
|
_ resource.ResourceWithModifyPlan = &userResource{}
|
||||||
_ resource.ResourceWithIdentity = &userResource{}
|
|
||||||
_ resource.ResourceWithValidateConfig = &userResource{}
|
_ resource.ResourceWithValidateConfig = &userResource{}
|
||||||
|
|
||||||
// Error message constants
|
// Error message constants
|
||||||
|
|
@ -50,14 +49,6 @@ func NewUserResource() resource.Resource {
|
||||||
// resourceModel represents the Terraform resource state for a PostgreSQL Flex user.
|
// resourceModel represents the Terraform resource state for a PostgreSQL Flex user.
|
||||||
type resourceModel = postgresflexalpha.UserModel
|
type resourceModel = postgresflexalpha.UserModel
|
||||||
|
|
||||||
// UserResourceIdentityModel describes the resource's identity attributes.
|
|
||||||
type UserResourceIdentityModel struct {
|
|
||||||
ProjectID types.String `tfsdk:"project_id"`
|
|
||||||
Region types.String `tfsdk:"region"`
|
|
||||||
InstanceID types.String `tfsdk:"instance_id"`
|
|
||||||
UserID types.Int64 `tfsdk:"user_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// userResource implements the resource handling for a PostgreSQL Flex user.
|
// userResource implements the resource handling for a PostgreSQL Flex user.
|
||||||
type userResource struct {
|
type userResource struct {
|
||||||
client *v3alpha1api.APIClient
|
client *v3alpha1api.APIClient
|
||||||
|
|
@ -232,23 +223,14 @@ func (r *userResource) Create(
|
||||||
}
|
}
|
||||||
arg.userID = int64(*id)
|
arg.userID = int64(*id)
|
||||||
|
|
||||||
|
model.Id = utils.BuildInternalTerraformId(arg.projectID, arg.region, arg.instanceID, strconv.FormatInt(arg.userID, 10))
|
||||||
|
|
||||||
|
ctx = tflog.SetField(ctx, "id", model.Id.ValueString())
|
||||||
ctx = tflog.SetField(ctx, "user_id", id)
|
ctx = tflog.SetField(ctx, "user_id", id)
|
||||||
|
|
||||||
ctx = core.LogResponse(ctx)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
// Set data returned by API in identity
|
model.Id = utils.BuildInternalTerraformId(arg.projectID, arg.region, arg.instanceID, strconv.FormatInt(arg.userID, 10))
|
||||||
identity := UserResourceIdentityModel{
|
|
||||||
ProjectID: types.StringValue(arg.projectID),
|
|
||||||
Region: types.StringValue(arg.region),
|
|
||||||
InstanceID: types.StringValue(arg.instanceID),
|
|
||||||
UserID: types.Int64Value(int64(*id)),
|
|
||||||
}
|
|
||||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
|
||||||
if resp.Diagnostics.HasError() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
model.Id = types.Int64Value(int64(*id))
|
|
||||||
model.UserId = types.Int64Value(int64(*id))
|
model.UserId = types.Int64Value(int64(*id))
|
||||||
model.Password = types.StringValue(userResp.GetPassword())
|
model.Password = types.StringValue(userResp.GetPassword())
|
||||||
model.Status = types.StringValue(userResp.GetStatus())
|
model.Status = types.StringValue(userResp.GetStatus())
|
||||||
|
|
@ -370,15 +352,14 @@ func (r *userResource) Read(
|
||||||
|
|
||||||
ctx = core.LogResponse(ctx)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
// Set data returned by API in identity
|
err = mapResourceFields(waitResp, &model, model.Region.ValueString())
|
||||||
identity := UserResourceIdentityModel{
|
if err != nil {
|
||||||
ProjectID: types.StringValue(arg.projectID),
|
core.LogAndAddError(
|
||||||
Region: types.StringValue(arg.region),
|
ctx,
|
||||||
InstanceID: types.StringValue(arg.instanceID),
|
&resp.Diagnostics,
|
||||||
UserID: types.Int64Value(arg.userID),
|
"read user",
|
||||||
}
|
fmt.Sprintf("Wait response mapping: %v", err),
|
||||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
)
|
||||||
if resp.Diagnostics.HasError() {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -457,18 +438,6 @@ func (r *userResource) Update(
|
||||||
|
|
||||||
ctx = core.LogResponse(ctx)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
||||||
// Set data returned by API in identity
|
|
||||||
identity := UserResourceIdentityModel{
|
|
||||||
ProjectID: types.StringValue(arg.projectID),
|
|
||||||
Region: types.StringValue(arg.region),
|
|
||||||
InstanceID: types.StringValue(arg.instanceID),
|
|
||||||
UserID: types.Int64Value(userID64),
|
|
||||||
}
|
|
||||||
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
|
|
||||||
if resp.Diagnostics.HasError() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify update
|
// Verify update
|
||||||
waitResp, err := postgresflexalphaWait.GetUserByIdWaitHandler(
|
waitResp, err := postgresflexalphaWait.GetUserByIdWaitHandler(
|
||||||
ctx,
|
ctx,
|
||||||
|
|
@ -525,26 +494,17 @@ func (r *userResource) Delete(
|
||||||
if resp.Diagnostics.HasError() {
|
if resp.Diagnostics.HasError() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Read identity data
|
|
||||||
var identityData UserResourceIdentityModel
|
|
||||||
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
|
||||||
if resp.Diagnostics.HasError() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
arg, errExt := r.extractIdentityData(model, identityData)
|
arg := clientArg{
|
||||||
if errExt != nil {
|
projectID: model.ProjectId.ValueString(),
|
||||||
core.LogAndAddError(
|
instanceID: model.InstanceId.ValueString(),
|
||||||
ctx,
|
region: model.Region.ValueString(),
|
||||||
&resp.Diagnostics,
|
userID: model.UserId.ValueInt64(),
|
||||||
extractErrorSummary,
|
|
||||||
fmt.Sprintf(extractErrorMessage, errExt),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = r.setTFLogFields(ctx, arg)
|
ctx = r.setTFLogFields(ctx, &arg)
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
userID64 := arg.userID
|
userID64 := arg.userID
|
||||||
|
|
@ -557,7 +517,14 @@ func (r *userResource) Delete(
|
||||||
// Delete existing record set
|
// Delete existing record set
|
||||||
err := r.client.DefaultAPI.DeleteUserRequest(ctx, arg.projectID, arg.region, arg.instanceID, userID).Execute()
|
err := r.client.DefaultAPI.DeleteUserRequest(ctx, arg.projectID, arg.region, arg.instanceID, userID).Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting user", fmt.Sprintf("Calling API: %v", err))
|
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 {
|
||||||
|
if oapiErr.StatusCode == 404 {
|
||||||
|
resp.State.RemoveResource(ctx)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
core.LogAndAddError(ctx, &resp.Diagnostics, "Error deleting user", fmt.Sprintf("error from API: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = core.LogResponse(ctx)
|
ctx = core.LogResponse(ctx)
|
||||||
|
|
@ -581,30 +548,6 @@ func (r *userResource) Delete(
|
||||||
tflog.Info(ctx, "Postgres Flex user deleted")
|
tflog.Info(ctx, "Postgres Flex user deleted")
|
||||||
}
|
}
|
||||||
|
|
||||||
// IdentitySchema defines the fields that are required to uniquely identify a resource.
|
|
||||||
func (r *userResource) IdentitySchema(
|
|
||||||
_ context.Context,
|
|
||||||
_ resource.IdentitySchemaRequest,
|
|
||||||
response *resource.IdentitySchemaResponse,
|
|
||||||
) {
|
|
||||||
response.IdentitySchema = identityschema.Schema{
|
|
||||||
Attributes: map[string]identityschema.Attribute{
|
|
||||||
"project_id": identityschema.StringAttribute{
|
|
||||||
RequiredForImport: true,
|
|
||||||
},
|
|
||||||
"region": identityschema.StringAttribute{
|
|
||||||
RequiredForImport: true,
|
|
||||||
},
|
|
||||||
"instance_id": identityschema.StringAttribute{
|
|
||||||
RequiredForImport: true,
|
|
||||||
},
|
|
||||||
"user_id": identityschema.Int64Attribute{
|
|
||||||
RequiredForImport: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// clientArg holds the arguments for API calls.
|
// clientArg holds the arguments for API calls.
|
||||||
type clientArg struct {
|
type clientArg struct {
|
||||||
projectID string
|
projectID string
|
||||||
|
|
@ -622,112 +565,41 @@ func (r *userResource) ImportState(
|
||||||
) {
|
) {
|
||||||
ctx = core.InitProviderContext(ctx)
|
ctx = core.InitProviderContext(ctx)
|
||||||
|
|
||||||
if req.ID != "" {
|
idParts := strings.Split(req.ID, core.Separator)
|
||||||
idParts := strings.Split(req.ID, core.Separator)
|
|
||||||
|
|
||||||
if len(idParts) != 4 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || idParts[3] == "" {
|
|
||||||
core.LogAndAddError(
|
|
||||||
ctx, &resp.Diagnostics,
|
|
||||||
"Error importing user",
|
|
||||||
fmt.Sprintf(
|
|
||||||
"Expected import identifier with format [project_id],[region],[instance_id],[user_id], got %q",
|
|
||||||
req.ID,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
userID, err := strconv.ParseInt(idParts[3], 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
core.LogAndAddError(
|
|
||||||
ctx,
|
|
||||||
&resp.Diagnostics,
|
|
||||||
"Error importing user",
|
|
||||||
fmt.Sprintf("Invalid user_id format: %q. It must be a valid integer.", idParts[3]),
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...)
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...)
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...)
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("user_id"), userID)...)
|
|
||||||
|
|
||||||
tflog.Info(ctx, "Postgres Flex user state imported")
|
|
||||||
|
|
||||||
|
if len(idParts) != 4 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || idParts[3] == "" {
|
||||||
|
core.LogAndAddError(
|
||||||
|
ctx, &resp.Diagnostics,
|
||||||
|
"Error importing user",
|
||||||
|
fmt.Sprintf(
|
||||||
|
"Expected import identifier with format [project_id],[region],[instance_id],[user_id], got %q",
|
||||||
|
req.ID,
|
||||||
|
),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no ID is provided, attempt to read identity attributes from the import configuration
|
userID, err := strconv.ParseInt(idParts[3], 10, 64)
|
||||||
var identityData UserResourceIdentityModel
|
if err != nil {
|
||||||
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
|
core.LogAndAddError(
|
||||||
if resp.Diagnostics.HasError() {
|
ctx,
|
||||||
|
&resp.Diagnostics,
|
||||||
|
"Error importing user",
|
||||||
|
fmt.Sprintf("Invalid user_id format: %q. It must be a valid integer.", idParts[3]),
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
projectID := identityData.ProjectID.ValueString()
|
idString := utils.BuildInternalTerraformId(idParts...)
|
||||||
region := identityData.Region.ValueString()
|
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("id"), idString)...)
|
||||||
instanceID := identityData.InstanceID.ValueString()
|
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), idParts[0])...)
|
||||||
userID := identityData.UserID.ValueInt64()
|
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), idParts[1])...)
|
||||||
|
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), idParts[2])...)
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_id"), projectID)...)
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("region"), region)...)
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("instance_id"), instanceID)...)
|
|
||||||
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("user_id"), userID)...)
|
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("user_id"), userID)...)
|
||||||
|
|
||||||
tflog.Info(ctx, "Postgres Flex user state imported")
|
tflog.Info(ctx, "Postgres Flex user state imported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// extractIdentityData extracts essential identifiers from the resource model, falling back to the identity model.
|
|
||||||
func (r *userResource) extractIdentityData(
|
|
||||||
model resourceModel,
|
|
||||||
identity UserResourceIdentityModel,
|
|
||||||
) (*clientArg, error) {
|
|
||||||
var projectID, region, instanceID string
|
|
||||||
var userID int64
|
|
||||||
if !model.UserId.IsNull() && !model.UserId.IsUnknown() {
|
|
||||||
userID = model.UserId.ValueInt64()
|
|
||||||
} else {
|
|
||||||
if identity.UserID.IsNull() || identity.UserID.IsUnknown() {
|
|
||||||
return nil, fmt.Errorf("user_id not found in config")
|
|
||||||
}
|
|
||||||
userID = identity.UserID.ValueInt64()
|
|
||||||
}
|
|
||||||
|
|
||||||
if !model.ProjectId.IsNull() && !model.ProjectId.IsUnknown() {
|
|
||||||
projectID = model.ProjectId.ValueString()
|
|
||||||
} else {
|
|
||||||
if identity.ProjectID.IsNull() || identity.ProjectID.IsUnknown() {
|
|
||||||
return nil, fmt.Errorf("project_id not found in config")
|
|
||||||
}
|
|
||||||
projectID = identity.ProjectID.ValueString()
|
|
||||||
}
|
|
||||||
|
|
||||||
if !model.Region.IsNull() && !model.Region.IsUnknown() {
|
|
||||||
region = r.providerData.GetRegionWithOverride(model.Region)
|
|
||||||
} else {
|
|
||||||
if identity.Region.IsNull() || identity.Region.IsUnknown() {
|
|
||||||
return nil, fmt.Errorf("region not found in config")
|
|
||||||
}
|
|
||||||
region = r.providerData.GetRegionWithOverride(identity.Region)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !model.InstanceId.IsNull() && !model.InstanceId.IsUnknown() {
|
|
||||||
instanceID = model.InstanceId.ValueString()
|
|
||||||
} else {
|
|
||||||
if identity.InstanceID.IsNull() || identity.InstanceID.IsUnknown() {
|
|
||||||
return nil, fmt.Errorf("instance_id not found in config")
|
|
||||||
}
|
|
||||||
instanceID = identity.InstanceID.ValueString()
|
|
||||||
}
|
|
||||||
return &clientArg{
|
|
||||||
projectID: projectID,
|
|
||||||
instanceID: instanceID,
|
|
||||||
region: region,
|
|
||||||
userID: userID,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// setTFLogFields adds relevant fields to the context for terraform logging purposes.
|
// setTFLogFields adds relevant fields to the context for terraform logging purposes.
|
||||||
func (r *userResource) setTFLogFields(ctx context.Context, arg *clientArg) context.Context {
|
func (r *userResource) setTFLogFields(ctx context.Context, arg *clientArg) context.Context {
|
||||||
ctx = tflog.SetField(ctx, "project_id", arg.projectID)
|
ctx = tflog.SetField(ctx, "project_id", arg.projectID)
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import (
|
||||||
func UserResourceSchema(ctx context.Context) schema.Schema {
|
func UserResourceSchema(ctx context.Context) schema.Schema {
|
||||||
return schema.Schema{
|
return schema.Schema{
|
||||||
Attributes: map[string]schema.Attribute{
|
Attributes: map[string]schema.Attribute{
|
||||||
"id": schema.Int64Attribute{
|
"id": schema.StringAttribute{
|
||||||
Computed: true,
|
Computed: true,
|
||||||
Description: "The ID of the user.",
|
Description: "The ID of the user.",
|
||||||
MarkdownDescription: "The ID of the user.",
|
MarkdownDescription: "The ID of the user.",
|
||||||
|
|
@ -75,7 +75,7 @@ func UserResourceSchema(ctx context.Context) schema.Schema {
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserModel struct {
|
type UserModel struct {
|
||||||
Id types.Int64 `tfsdk:"id"`
|
Id types.String `tfsdk:"id"`
|
||||||
InstanceId types.String `tfsdk:"instance_id"`
|
InstanceId types.String `tfsdk:"instance_id"`
|
||||||
Name types.String `tfsdk:"name"`
|
Name types.String `tfsdk:"name"`
|
||||||
Password types.String `tfsdk:"password"`
|
Password types.String `tfsdk:"password"`
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,8 @@ type APIClientDatabaseInterface interface {
|
||||||
|
|
||||||
// CreateInstanceWaitHandler will wait for instance creation
|
// CreateInstanceWaitHandler will wait for instance creation
|
||||||
func CreateInstanceWaitHandler(
|
func CreateInstanceWaitHandler(
|
||||||
ctx context.Context, a APIClientInstanceInterface, projectId, region,
|
ctx context.Context, a APIClientInstanceInterface, projectID, region,
|
||||||
instanceId string,
|
instanceID string,
|
||||||
) *wait.AsyncActionHandler[v3alpha1api.GetInstanceResponse] {
|
) *wait.AsyncActionHandler[v3alpha1api.GetInstanceResponse] {
|
||||||
instanceCreated := false
|
instanceCreated := false
|
||||||
var instanceGetResponse *v3alpha1api.GetInstanceResponse
|
var instanceGetResponse *v3alpha1api.GetInstanceResponse
|
||||||
|
|
@ -67,11 +67,11 @@ func CreateInstanceWaitHandler(
|
||||||
handler := wait.New(
|
handler := wait.New(
|
||||||
func() (waitFinished bool, response *v3alpha1api.GetInstanceResponse, err error) {
|
func() (waitFinished bool, response *v3alpha1api.GetInstanceResponse, err error) {
|
||||||
if !instanceCreated {
|
if !instanceCreated {
|
||||||
s, err := a.GetInstanceRequest(ctx, projectId, region, instanceId).Execute()
|
s, getErr := a.GetInstanceRequest(ctx, projectID, region, instanceID).Execute()
|
||||||
if err != nil {
|
if getErr != nil {
|
||||||
return false, nil, err
|
return false, nil, getErr
|
||||||
}
|
}
|
||||||
if s == nil || s.Id != instanceId {
|
if s == nil || s.Id != instanceID {
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
}
|
}
|
||||||
tflog.Debug(
|
tflog.Debug(
|
||||||
|
|
@ -81,7 +81,7 @@ func CreateInstanceWaitHandler(
|
||||||
)
|
)
|
||||||
switch s.Status {
|
switch s.Status {
|
||||||
default:
|
default:
|
||||||
return true, s, fmt.Errorf("instance with id %s has unexpected status %s", instanceId, s.Status)
|
return true, s, fmt.Errorf("instance with id %s has unexpected status %s", instanceID, s.Status)
|
||||||
case InstanceStateEmpty:
|
case InstanceStateEmpty:
|
||||||
return false, nil, nil
|
return false, nil, nil
|
||||||
case InstanceStatePending:
|
case InstanceStatePending:
|
||||||
|
|
@ -98,30 +98,15 @@ func CreateInstanceWaitHandler(
|
||||||
"Wait handler still got status %s after %v for instance: %s",
|
"Wait handler still got status %s after %v for instance: %s",
|
||||||
InstanceStateProgressing,
|
InstanceStateProgressing,
|
||||||
maxWait,
|
maxWait,
|
||||||
instanceId,
|
instanceID,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if extendedTimeout < 3 {
|
if extendedTimeout < 3 {
|
||||||
maxWait += time.Minute * 5
|
maxWait += time.Minute * 5
|
||||||
extendedTimeout++
|
extendedTimeout++
|
||||||
if *s.Network.AccessScope == "SNA" {
|
return false, nil, nil
|
||||||
ready := true
|
|
||||||
if s.Network.InstanceAddress == nil {
|
|
||||||
tflog.Warn(ctx, "Waiting for instance_address")
|
|
||||||
ready = false
|
|
||||||
}
|
|
||||||
if s.Network.RouterAddress == nil {
|
|
||||||
tflog.Warn(ctx, "Waiting for router_address")
|
|
||||||
ready = false
|
|
||||||
}
|
|
||||||
if !ready {
|
|
||||||
return false, nil, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return false, nil, fmt.Errorf("instance after max timeout still in state %s", InstanceStateProgressing)
|
||||||
instanceCreated = true
|
|
||||||
instanceGetResponse = s
|
|
||||||
case InstanceStateSuccess:
|
case InstanceStateSuccess:
|
||||||
if s.Network.AccessScope != nil && *s.Network.AccessScope == "SNA" {
|
if s.Network.AccessScope != nil && *s.Network.AccessScope == "SNA" {
|
||||||
if s.Network.InstanceAddress == nil {
|
if s.Network.InstanceAddress == nil {
|
||||||
|
|
@ -144,9 +129,9 @@ func CreateInstanceWaitHandler(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
var waitCounter int64 = 1
|
var waitCounter int64 = 1
|
||||||
maxWait := big.NewInt(7)
|
maxWaitInt := big.NewInt(7)
|
||||||
n, err := rand.Int(rand.Reader, maxWait)
|
n, randErr := rand.Int(rand.Reader, maxWaitInt)
|
||||||
if err == nil {
|
if randErr == nil {
|
||||||
waitCounter = n.Int64() + 1
|
waitCounter = n.Int64() + 1
|
||||||
}
|
}
|
||||||
time.Sleep(time.Duration(waitCounter*30) * time.Second) //nolint:gosec // not that important and temporary
|
time.Sleep(time.Duration(waitCounter*30) * time.Second) //nolint:gosec // not that important and temporary
|
||||||
|
|
@ -154,7 +139,7 @@ func CreateInstanceWaitHandler(
|
||||||
}
|
}
|
||||||
return true, s, fmt.Errorf(
|
return true, s, fmt.Errorf(
|
||||||
"update got status FAILURE for instance with id %s after %d retries",
|
"update got status FAILURE for instance with id %s after %d retries",
|
||||||
instanceId,
|
instanceID,
|
||||||
failedCount,
|
failedCount,
|
||||||
)
|
)
|
||||||
// API responds with FAILURE for some seconds and then the instance goes to READY
|
// API responds with FAILURE for some seconds and then the instance goes to READY
|
||||||
|
|
@ -165,7 +150,7 @@ func CreateInstanceWaitHandler(
|
||||||
tflog.Info(ctx, "Waiting for instance (calling list users")
|
tflog.Info(ctx, "Waiting for instance (calling list users")
|
||||||
// // User operations aren't available right after an instance is deemed successful
|
// // User operations aren't available right after an instance is deemed successful
|
||||||
// // To check if they are, perform a users request
|
// // To check if they are, perform a users request
|
||||||
_, err = a.ListUsersRequest(ctx, projectId, region, instanceId).Execute()
|
_, err = a.ListUsersRequest(ctx, projectID, region, instanceID).Execute()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return true, instanceGetResponse, nil
|
return true, instanceGetResponse, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue