Onboard MongoDB Flex instance (#86)

* Onboard instance resource

* Add options.type as required field

* Implement resource unit tests

* Implement data source

* Implement acc tests

* Adjust update acc test

* Fix typo

* Adjust update unit tests

* Adjustments after review

* Minor adjustment for uniformity

* Adjustments after review
This commit is contained in:
João Palet 2023-10-17 11:20:22 +02:00 committed by GitHub
parent 6372434e56
commit ade77eb544
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 2245 additions and 106 deletions

View file

@ -64,7 +64,7 @@ var flavorTypes = map[string]attr.Type{
"ram": basetypes.Int64Type{},
}
// Struct corresponding to DataSourceModel.Storage
// Struct corresponding to Model.Storage
type storageModel struct {
Class types.String `tfsdk:"class"`
Size types.Int64 `tfsdk:"size"`
@ -261,8 +261,9 @@ func (r *instanceResource) Create(ctx context.Context, req resource.CreateReques
if resp.Diagnostics.HasError() {
return
}
r.loadFlavorId(ctx, &resp.Diagnostics, &model, flavor)
if resp.Diagnostics.HasError() {
err := loadFlavorId(ctx, r.client, &model, flavor)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error creating instance", fmt.Sprintf("Loading flavor ID: %v", err))
return
}
}
@ -395,8 +396,9 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
if resp.Diagnostics.HasError() {
return
}
r.loadFlavorId(ctx, &resp.Diagnostics, &model, flavor)
if resp.Diagnostics.HasError() {
err := loadFlavorId(ctx, r.client, &model, flavor)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Loading flavor ID: %v", err))
return
}
}
@ -435,7 +437,7 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
// Map response body to schema
err = mapFields(got, &model, flavor, storage)
if err != nil {
core.LogAndAddError(ctx, &resp.Diagnostics, "Error mapping fields in update", err.Error())
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating instance", fmt.Sprintf("Processing API payload: %v", err))
return
}
diags = resp.State.Set(ctx, model)
@ -524,15 +526,15 @@ func mapFields(resp *postgresflex.InstanceResponse, model *Model, flavor *flavor
}
aclList, diags = types.ListValue(types.StringType, acl)
if diags.HasError() {
return fmt.Errorf("failed to map ACL: %w", core.DiagsToError(diags))
return fmt.Errorf("mapping ACL: %w", core.DiagsToError(diags))
}
}
var flavorValues map[string]attr.Value
if instance.Flavor == nil {
flavorValues = map[string]attr.Value{
"id": types.StringNull(),
"description": types.StringNull(),
"id": flavor.Id,
"description": flavor.Description,
"cpu": flavor.CPU,
"ram": flavor.RAM,
}
@ -540,13 +542,13 @@ func mapFields(resp *postgresflex.InstanceResponse, model *Model, flavor *flavor
flavorValues = map[string]attr.Value{
"id": types.StringValue(*instance.Flavor.Id),
"description": types.StringValue(*instance.Flavor.Description),
"cpu": types.Int64Value(int64(*instance.Flavor.Cpu)),
"ram": types.Int64Value(int64(*instance.Flavor.Memory)),
"cpu": conversion.ToTypeInt64(instance.Flavor.Cpu),
"ram": conversion.ToTypeInt64(instance.Flavor.Memory),
}
}
flavorObject, diags := types.ObjectValue(flavorTypes, flavorValues)
if diags.HasError() {
return fmt.Errorf("failed to create flavor: %w", core.DiagsToError(diags))
return fmt.Errorf("creating flavor: %w", core.DiagsToError(diags))
}
var storageValues map[string]attr.Value
@ -558,12 +560,12 @@ func mapFields(resp *postgresflex.InstanceResponse, model *Model, flavor *flavor
} else {
storageValues = map[string]attr.Value{
"class": types.StringValue(*instance.Storage.Class),
"size": types.Int64Value(int64(*instance.Storage.Size)),
"size": conversion.ToTypeInt64(instance.Storage.Size),
}
}
storageObject, diags := types.ObjectValue(storageTypes, storageValues)
if diags.HasError() {
return fmt.Errorf("failed to create storage: %w", core.DiagsToError(diags))
return fmt.Errorf("creating storage: %w", core.DiagsToError(diags))
}
idParts := []string{
@ -574,29 +576,13 @@ func mapFields(resp *postgresflex.InstanceResponse, model *Model, flavor *flavor
strings.Join(idParts, core.Separator),
)
model.InstanceId = types.StringValue(instanceId)
if instance.Name == nil {
model.Name = types.StringNull()
} else {
model.Name = types.StringValue(*instance.Name)
}
model.Name = types.StringPointerValue(instance.Name)
model.ACL = aclList
if instance.BackupSchedule == nil {
model.BackupSchedule = types.StringNull()
} else {
model.BackupSchedule = types.StringValue(*instance.BackupSchedule)
}
model.BackupSchedule = types.StringPointerValue(instance.BackupSchedule)
model.Flavor = flavorObject
if instance.Replicas == nil {
model.Replicas = types.Int64Null()
} else {
model.Replicas = types.Int64Value(int64(*instance.Replicas))
}
model.Replicas = conversion.ToTypeInt64(instance.Replicas)
model.Storage = storageObject
if instance.Version == nil {
model.Version = types.StringNull()
} else {
model.Version = types.StringValue(*instance.Version)
}
model.Version = types.StringPointerValue(instance.Version)
return nil
}
@ -660,37 +646,35 @@ func toUpdatePayload(model *Model, acl []string, flavor *flavorModel, storage *s
}, nil
}
func (r *instanceResource) loadFlavorId(ctx context.Context, diags *diag.Diagnostics, model *Model, flavor *flavorModel) {
type postgresFlexClient interface {
GetFlavorsExecute(ctx context.Context, projectId string) (*postgresflex.FlavorsResponse, error)
}
func loadFlavorId(ctx context.Context, client postgresFlexClient, model *Model, flavor *flavorModel) error {
if model == nil {
diags.AddError("invalid model", "nil model")
return
return fmt.Errorf("nil model")
}
if flavor == nil {
diags.AddError("invalid flavor", "nil flavor")
return
return fmt.Errorf("nil flavor")
}
cpu := conversion.ToPtrInt32(flavor.CPU)
if cpu == nil {
diags.AddError("invalid flavor", "nil CPU")
return
return fmt.Errorf("nil CPU")
}
ram := conversion.ToPtrInt32(flavor.RAM)
if ram == nil {
diags.AddError("invalid flavor", "nil RAM")
return
return fmt.Errorf("nil RAM")
}
projectId := model.ProjectId.ValueString()
res, err := r.client.GetFlavors(ctx, projectId).Execute()
res, err := client.GetFlavorsExecute(ctx, projectId)
if err != nil {
diags.AddError("failed to list postgresflex flavors", err.Error())
return
return fmt.Errorf("listing postgresflex flavors: %w", err)
}
avl := ""
if res.Flavors == nil {
diags.AddError("no flavors", fmt.Sprintf("couldn't find flavors for id %s", flavor.Id.ValueString()))
return
return fmt.Errorf("finding flavors for project %s", projectId)
}
for _, f := range *res.Flavors {
if f.Id == nil || f.Cpu == nil || f.Memory == nil {
@ -698,12 +682,14 @@ func (r *instanceResource) loadFlavorId(ctx context.Context, diags *diag.Diagnos
}
if *f.Cpu == *cpu && *f.Memory == *ram {
flavor.Id = types.StringValue(*f.Id)
flavor.Description = types.StringValue(*f.Description)
break
}
avl = fmt.Sprintf("%s\n- %d CPU, %d GB RAM", avl, *f.Cpu, *f.Cpu)
}
if flavor.Id.ValueString() == "" {
diags.AddError("invalid flavor", fmt.Sprintf("couldn't find flavor.\navailable specs are:%s", avl))
return
return fmt.Errorf("couldn't find flavor, available specs are:%s", avl)
}
return nil
}