fix: change identity handling for user & database #50

Merged
marcel.henselin merged 4 commits from fix/identity-user-database into alpha 2026-02-11 15:39:21 +00:00
14 changed files with 278 additions and 241 deletions

View file

@ -23,11 +23,6 @@ func DatabasesDataSourceSchema(ctx context.Context) schema.Schema {
"databases": schema.ListNestedAttribute{
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"created": schema.StringAttribute{
Computed: true,
Description: "The data when the database was created in RFC3339 format.",
MarkdownDescription: "The data when the database was created in RFC3339 format.",
},
"id": schema.Int64Attribute{
Computed: true,
Description: "The id of the database.",
@ -169,24 +164,6 @@ func (t DatabasesType) ValueFromObject(ctx context.Context, in basetypes.ObjectV
attributes := in.Attributes()
createdAttribute, ok := attributes["created"]
if !ok {
diags.AddError(
"Attribute Missing",
`created is missing from object`)
return nil, diags
}
createdVal, ok := createdAttribute.(basetypes.StringValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`created expected to be basetypes.StringValue, was: %T`, createdAttribute))
}
idAttribute, ok := attributes["id"]
if !ok {
@ -246,11 +223,10 @@ func (t DatabasesType) ValueFromObject(ctx context.Context, in basetypes.ObjectV
}
return DatabasesValue{
Created: createdVal,
Id: idVal,
Name: nameVal,
Owner: ownerVal,
state: attr.ValueStateKnown,
Id: idVal,
Name: nameVal,
Owner: ownerVal,
state: attr.ValueStateKnown,
}, diags
}
@ -317,24 +293,6 @@ func NewDatabasesValue(attributeTypes map[string]attr.Type, attributes map[strin
return NewDatabasesValueUnknown(), diags
}
createdAttribute, ok := attributes["created"]
if !ok {
diags.AddError(
"Attribute Missing",
`created is missing from object`)
return NewDatabasesValueUnknown(), diags
}
createdVal, ok := createdAttribute.(basetypes.StringValue)
if !ok {
diags.AddError(
"Attribute Wrong Type",
fmt.Sprintf(`created expected to be basetypes.StringValue, was: %T`, createdAttribute))
}
idAttribute, ok := attributes["id"]
if !ok {
@ -394,11 +352,10 @@ func NewDatabasesValue(attributeTypes map[string]attr.Type, attributes map[strin
}
return DatabasesValue{
Created: createdVal,
Id: idVal,
Name: nameVal,
Owner: ownerVal,
state: attr.ValueStateKnown,
Id: idVal,
Name: nameVal,
Owner: ownerVal,
state: attr.ValueStateKnown,
}, diags
}
@ -470,20 +427,18 @@ func (t DatabasesType) ValueType(ctx context.Context) attr.Value {
var _ basetypes.ObjectValuable = DatabasesValue{}
type DatabasesValue struct {
Created basetypes.StringValue `tfsdk:"created"`
Id basetypes.Int64Value `tfsdk:"id"`
Name basetypes.StringValue `tfsdk:"name"`
Owner basetypes.StringValue `tfsdk:"owner"`
state attr.ValueState
Id basetypes.Int64Value `tfsdk:"id"`
Name basetypes.StringValue `tfsdk:"name"`
Owner basetypes.StringValue `tfsdk:"owner"`
state attr.ValueState
}
func (v DatabasesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) {
attrTypes := make(map[string]tftypes.Type, 4)
attrTypes := make(map[string]tftypes.Type, 3)
var val tftypes.Value
var err error
attrTypes["created"] = basetypes.StringType{}.TerraformType(ctx)
attrTypes["id"] = basetypes.Int64Type{}.TerraformType(ctx)
attrTypes["name"] = basetypes.StringType{}.TerraformType(ctx)
attrTypes["owner"] = basetypes.StringType{}.TerraformType(ctx)
@ -492,15 +447,7 @@ func (v DatabasesValue) ToTerraformValue(ctx context.Context) (tftypes.Value, er
switch v.state {
case attr.ValueStateKnown:
vals := make(map[string]tftypes.Value, 4)
val, err = v.Created.ToTerraformValue(ctx)
if err != nil {
return tftypes.NewValue(objectType, tftypes.UnknownValue), err
}
vals["created"] = val
vals := make(map[string]tftypes.Value, 3)
val, err = v.Id.ToTerraformValue(ctx)
@ -556,10 +503,9 @@ func (v DatabasesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValu
var diags diag.Diagnostics
attributeTypes := map[string]attr.Type{
"created": basetypes.StringType{},
"id": basetypes.Int64Type{},
"name": basetypes.StringType{},
"owner": basetypes.StringType{},
"id": basetypes.Int64Type{},
"name": basetypes.StringType{},
"owner": basetypes.StringType{},
}
if v.IsNull() {
@ -573,10 +519,9 @@ func (v DatabasesValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValu
objVal, diags := types.ObjectValue(
attributeTypes,
map[string]attr.Value{
"created": v.Created,
"id": v.Id,
"name": v.Name,
"owner": v.Owner,
"id": v.Id,
"name": v.Name,
"owner": v.Owner,
})
return objVal, diags
@ -597,10 +542,6 @@ func (v DatabasesValue) Equal(o attr.Value) bool {
return true
}
if !v.Created.Equal(other.Created) {
return false
}
if !v.Id.Equal(other.Id) {
return false
}
@ -626,10 +567,9 @@ func (v DatabasesValue) Type(ctx context.Context) attr.Type {
func (v DatabasesValue) AttributeTypes(ctx context.Context) map[string]attr.Type {
return map[string]attr.Type{
"created": basetypes.StringType{},
"id": basetypes.Int64Type{},
"name": basetypes.StringType{},
"owner": basetypes.StringType{},
"id": basetypes.Int64Type{},
"name": basetypes.StringType{},
"owner": basetypes.StringType{},
}
}

View file

@ -178,18 +178,11 @@ func (r *databaseResource) Create(
return
}
// Read identity data
var identityData DatabaseResourceIdentityModel
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
if resp.Diagnostics.HasError() {
return
}
ctx = core.InitProviderContext(ctx)
projectId := identityData.ProjectID.ValueString()
region := identityData.ProjectID.ValueString()
instanceId := identityData.InstanceID.ValueString()
projectId := model.ProjectId.ValueString()
region := model.InstanceId.ValueString()
instanceId := model.InstanceId.ValueString()
ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "instance_id", instanceId)
@ -218,8 +211,6 @@ func (r *databaseResource) Create(
return
}
ctx = core.LogResponse(ctx)
if databaseResp == nil || databaseResp.Id == nil {
core.LogAndAddError(
ctx,
@ -231,6 +222,19 @@ func (r *databaseResource) Create(
}
databaseId := *databaseResp.Id
ctx = tflog.SetField(ctx, "database_id", databaseId)
ctx = core.LogResponse(ctx)
// 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
}
database, err := getDatabaseById(ctx, r.client, projectId, region, instanceId, databaseId)
if err != nil {
@ -255,18 +259,6 @@ func (r *databaseResource) Create(
return
}
// Set data returned by API in identity
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
resp.Diagnostics.Append(resp.State.Set(ctx, model)...)
if resp.Diagnostics.HasError() {
@ -337,6 +329,18 @@ func (r *databaseResource) Read(
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 refreshed state
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
@ -415,7 +419,7 @@ func (r *databaseResource) Update(
}
// Update existing database
res, err := r.client.UpdateDatabasePartiallyRequest(
err := r.client.UpdateDatabasePartiallyRequest(
ctx,
projectId,
region,
@ -430,19 +434,45 @@ func (r *databaseResource) Update(
ctx = core.LogResponse(ctx)
// Map response body to schema
err = mapResourceFields(res.Database, &model)
databaseResp, err := getDatabaseById(ctx, r.client, projectId, region, instanceId, databaseId64)
if err != nil {
oapiErr, ok := err.(*oapierror.GenericOpenAPIError) //nolint:errorlint //complaining that error.As should be used to catch wrapped errors, but this error should not be wrapped
if (ok && oapiErr.StatusCode == http.StatusNotFound) || errors.Is(err, errDatabaseNotFound) {
resp.State.RemoveResource(ctx)
return
}
core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading database", fmt.Sprintf("Calling API: %v", err))
return
}
ctx = core.LogResponse(ctx)
// Map response body to schema
err = mapResourceFields(databaseResp, &model)
if err != nil {
core.LogAndAddError(
ctx,
&resp.Diagnostics,
"Error updating database",
"Error reading database",
fmt.Sprintf("Processing API payload: %v", err),
)
return
}
// Save identity into Terraform state
identity := DatabaseResourceIdentityModel{
ProjectID: types.StringValue(projectId),
Region: types.StringValue(region),
InstanceID: types.StringValue(instanceId),
DatabaseID: types.Int64Value(databaseId64),
}
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
if resp.Diagnostics.HasError() {
return
}
// Set state to fully populated data
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
if resp.Diagnostics.HasError() {
return
}

View file

@ -159,14 +159,10 @@ func (r *userResource) Create(
ctx = core.InitProviderContext(ctx)
arg, errExt := r.extractIdentityData(model, identityData)
if errExt != nil {
core.LogAndAddError(
ctx,
&resp.Diagnostics,
extractErrorSummary,
fmt.Sprintf(extractErrorMessage, errExt),
)
arg := &clientArg{
projectId: model.ProjectId.ValueString(),
instanceId: model.InstanceId.ValueString(),
region: r.providerData.GetRegionWithOverride(model.Region),
}
ctx = r.setTFLogFields(ctx, arg)
@ -204,11 +200,13 @@ func (r *userResource) Create(
)
return
}
model.Id = types.Int64PointerValue(userResp.Id)
model.UserId = types.Int64PointerValue(userResp.Id)
model.Password = types.StringPointerValue(userResp.Password)
model.Id = types.Int64Value(userResp.GetId())
model.UserId = types.Int64Value(userResp.GetId())
model.Password = types.StringValue(userResp.GetPassword())
model.Status = types.StringValue(userResp.GetStatus())
model.ConnectionString = types.StringValue(userResp.GetConnectionString())
ctx = tflog.SetField(ctx, "user_id", *userResp.Id)
ctx = tflog.SetField(ctx, "user_id", userResp.GetId())
ctx = core.LogResponse(ctx)
@ -217,7 +215,7 @@ func (r *userResource) Create(
ProjectID: types.StringValue(arg.projectId),
Region: types.StringValue(arg.region),
InstanceID: types.StringValue(arg.instanceId),
UserID: types.Int64PointerValue(userResp.Id),
UserID: types.Int64Value(userResp.GetId()),
}
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
if resp.Diagnostics.HasError() {
@ -261,23 +259,12 @@ func (r *userResource) Read(
return
}
// Read identity data
var identityData UserResourceIdentityModel
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
if resp.Diagnostics.HasError() {
return
}
ctx = core.InitProviderContext(ctx)
arg, errExt := r.extractIdentityData(model, identityData)
if errExt != nil {
core.LogAndAddError(
ctx,
&resp.Diagnostics,
extractErrorSummary,
fmt.Sprintf(extractErrorMessage, errExt),
)
arg := &clientArg{
projectId: model.ProjectId.ValueString(),
instanceId: model.InstanceId.ValueString(),
region: r.providerData.GetRegionWithOverride(model.Region),
}
ctx = r.setTFLogFields(ctx, arg)
@ -299,6 +286,18 @@ func (r *userResource) Read(
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(arg.userId),
}
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
if resp.Diagnostics.HasError() {
return
}
// Set refreshed state
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
@ -385,6 +384,18 @@ func (r *userResource) Update(
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
exists, err := r.getUserResource(ctx, &stateModel, arg)

View file

@ -155,18 +155,11 @@ func (r *databaseResource) Create(ctx context.Context, req resource.CreateReques
return
}
// Read identity data
var identityData DatabaseResourceIdentityModel
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
if resp.Diagnostics.HasError() {
return
}
ctx = core.InitProviderContext(ctx)
projectId := identityData.ProjectID.ValueString()
region := identityData.ProjectID.ValueString()
instanceId := identityData.InstanceID.ValueString()
projectId := model.ProjectId.ValueString()
region := model.Region.ValueString()
instanceId := model.InstanceId.ValueString()
ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "instance_id", instanceId)
@ -215,6 +208,18 @@ func (r *databaseResource) Create(ctx context.Context, req resource.CreateReques
ctx = core.LogResponse(ctx)
// Set data returned by API in identity
identity := DatabaseResourceIdentityModel{
ProjectID: types.StringValue(projectId),
Region: types.StringValue(region),
InstanceID: types.StringValue(instanceId),
DatabaseName: types.StringValue(databaseName),
}
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
if resp.Diagnostics.HasError() {
return
}
database, err := r.client.GetDatabaseRequest(ctx, projectId, region, instanceId, databaseName).Execute()
if err != nil {
core.LogAndAddError(
@ -238,18 +243,6 @@ func (r *databaseResource) Create(ctx context.Context, req resource.CreateReques
return
}
// Set data returned by API in identity
identity := DatabaseResourceIdentityModel{
ProjectID: types.StringValue(projectId),
Region: types.StringValue(region),
InstanceID: types.StringValue(instanceId),
DatabaseName: types.StringValue(databaseName),
}
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
if resp.Diagnostics.HasError() {
return
}
// Set state to fully populated data
resp.Diagnostics.Append(resp.State.Set(ctx, model)...)
if resp.Diagnostics.HasError() {
@ -316,9 +309,20 @@ func (r *databaseResource) Read(ctx context.Context, req resource.ReadRequest, r
return
}
// Set data returned by API in identity
identity := DatabaseResourceIdentityModel{
ProjectID: types.StringValue(projectId),
Region: types.StringValue(region),
InstanceID: types.StringValue(instanceId),
DatabaseName: types.StringValue(databaseName),
}
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
if resp.Diagnostics.HasError() {
return
}
// Set refreshed state
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
if resp.Diagnostics.HasError() {
return
}
@ -371,6 +375,7 @@ func (r *databaseResource) Delete(ctx context.Context, req resource.DeleteReques
}
ctx = core.LogResponse(ctx)
resp.State.RemoveResource(ctx)
tflog.Info(ctx, "sqlserverflexalpha.Database deleted")
}
@ -382,7 +387,7 @@ func (r *databaseResource) ModifyPlan(
req resource.ModifyPlanRequest,
resp *resource.ModifyPlanResponse,
) { // nolint:gocritic // function signature required by Terraform
var configModel sqlserverflexalphaGen.DatabaseModel
var configModel resourceModel
// skip initial empty configuration to avoid follow-up errors
if req.Config.Raw.IsNull() {
return
@ -392,7 +397,7 @@ func (r *databaseResource) ModifyPlan(
return
}
var planModel sqlserverflexalphaGen.DatabaseModel
var planModel resourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
if resp.Diagnostics.HasError() {
return
@ -485,8 +490,8 @@ func (r *databaseResource) extractIdentityData(
model resourceModel,
identity DatabaseResourceIdentityModel,
) (projectId, region, instanceId, databaseName string, err error) {
if !model.DatabaseName.IsNull() && !model.DatabaseName.IsUnknown() {
databaseName = model.DatabaseName.ValueString()
if !model.Name.IsNull() && !model.Name.IsUnknown() {
databaseName = model.Name.ValueString()
} else {
if identity.DatabaseName.IsNull() || identity.DatabaseName.IsUnknown() {
return "", "", "", "", fmt.Errorf("database_name not found in config")

View file

@ -140,7 +140,7 @@ func mapFieldsCreate(userResp *sqlserverflexalpha.CreateUserResponse, model *res
if user.Roles != nil {
var roles []attr.Value
for _, role := range *user.Roles {
roles = append(roles, types.StringValue(string(role)))
roles = append(roles, types.StringValue(role))
}
rolesSet, diags := types.SetValue(types.StringType, roles)
if diags.HasError() {
@ -165,7 +165,7 @@ func mapFieldsCreate(userResp *sqlserverflexalpha.CreateUserResponse, model *res
// toCreatePayload converts a resourceModel to an API CreateUserRequestPayload.
func toCreatePayload(
model *resourceModel,
roles []sqlserverflexalpha.UserRole,
roles []string,
) (*sqlserverflexalpha.CreateUserRequestPayload, error) {
if model == nil {
return nil, fmt.Errorf("nil model")

View file

@ -42,7 +42,7 @@ func TestMapDataSourceFields(t *testing.T) {
"simple_values",
&sqlserverflexalpha.GetUserResponse{
Roles: &[]sqlserverflexalpha.UserRole{
Roles: &[]string{
"role_1",
"role_2",
"",
@ -79,7 +79,7 @@ func TestMapDataSourceFields(t *testing.T) {
"null_fields_and_int_conversions",
&sqlserverflexalpha.GetUserResponse{
Id: utils.Ptr(int64(1)),
Roles: &[]sqlserverflexalpha.UserRole{},
Roles: &[]string{},
Username: nil,
Host: nil,
Port: utils.Ptr(int64(2123456789)),
@ -180,7 +180,7 @@ func TestMapFieldsCreate(t *testing.T) {
"simple_values",
&sqlserverflexalpha.CreateUserResponse{
Id: utils.Ptr(int64(2)),
Roles: &[]sqlserverflexalpha.UserRole{
Roles: &[]string{
"role_1",
"role_2",
"",
@ -221,7 +221,7 @@ func TestMapFieldsCreate(t *testing.T) {
"null_fields_and_int_conversions",
&sqlserverflexalpha.CreateUserResponse{
Id: utils.Ptr(int64(3)),
Roles: &[]sqlserverflexalpha.UserRole{},
Roles: &[]string{},
Username: nil,
Password: utils.Ptr(""),
Host: nil,
@ -329,7 +329,7 @@ func TestMapFields(t *testing.T) {
{
"simple_values",
&sqlserverflexalpha.GetUserResponse{
Roles: &[]sqlserverflexalpha.UserRole{
Roles: &[]string{
"role_1",
"role_2",
"",
@ -364,7 +364,7 @@ func TestMapFields(t *testing.T) {
"null_fields_and_int_conversions",
&sqlserverflexalpha.GetUserResponse{
Id: utils.Ptr(int64(1)),
Roles: &[]sqlserverflexalpha.UserRole{},
Roles: &[]string{},
Username: nil,
Host: nil,
Port: utils.Ptr(int64(2123456789)),
@ -435,16 +435,16 @@ func TestToCreatePayload(t *testing.T) {
tests := []struct {
description string
input *resourceModel
inputRoles []sqlserverflexalpha.UserRole
inputRoles []string
expected *sqlserverflexalpha.CreateUserRequestPayload
isValid bool
}{
{
"default_values",
&resourceModel{},
[]sqlserverflexalpha.UserRole{},
[]string{},
&sqlserverflexalpha.CreateUserRequestPayload{
Roles: &[]sqlserverflexalpha.UserRole{},
Roles: &[]string{},
Username: nil,
},
true,
@ -454,12 +454,12 @@ func TestToCreatePayload(t *testing.T) {
&resourceModel{
Username: types.StringValue("username"),
},
[]sqlserverflexalpha.UserRole{
[]string{
"role_1",
"role_2",
},
&sqlserverflexalpha.CreateUserRequestPayload{
Roles: &[]sqlserverflexalpha.UserRole{
Roles: &[]string{
"role_1",
"role_2",
},
@ -472,11 +472,11 @@ func TestToCreatePayload(t *testing.T) {
&resourceModel{
Username: types.StringNull(),
},
[]sqlserverflexalpha.UserRole{
[]string{
"",
},
&sqlserverflexalpha.CreateUserRequestPayload{
Roles: &[]sqlserverflexalpha.UserRole{
Roles: &[]string{
"",
},
Username: nil,
@ -486,7 +486,7 @@ func TestToCreatePayload(t *testing.T) {
{
"nil_model",
nil,
[]sqlserverflexalpha.UserRole{},
[]string{},
nil,
false,
},
@ -495,9 +495,9 @@ func TestToCreatePayload(t *testing.T) {
&resourceModel{
Username: types.StringValue("username"),
},
[]sqlserverflexalpha.UserRole{},
[]string{},
&sqlserverflexalpha.CreateUserRequestPayload{
Roles: &[]sqlserverflexalpha.UserRole{},
Roles: &[]string{},
Username: utils.Ptr("username"),
},
true,

View file

@ -179,7 +179,7 @@ func (r *userResource) Create(
ctx = tflog.SetField(ctx, "instance_id", instanceId)
ctx = tflog.SetField(ctx, "region", region)
var roles []sqlserverflexalpha.UserRole
var roles []string
if !model.Roles.IsNull() && !model.Roles.IsUnknown() {
diags = model.Roles.ElementsAs(ctx, &roles, false)
resp.Diagnostics.Append(diags...)
@ -220,6 +220,18 @@ func (r *userResource) Create(
userId := *userResp.Id
ctx = tflog.SetField(ctx, "user_id", userId)
// Set data returned by API in identity
identity := UserResourceIdentityModel{
ProjectID: types.StringValue(projectId),
Region: types.StringValue(region),
InstanceID: types.StringValue(instanceId),
UserID: types.Int64Value(userResp.GetId()),
}
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
if resp.Diagnostics.HasError() {
return
}
// Map response body to schema
err = mapFieldsCreate(userResp, &model, region)
if err != nil {
@ -282,6 +294,18 @@ func (r *userResource) Read(
ctx = core.LogResponse(ctx)
// Set data returned by API in identity
identity := UserResourceIdentityModel{
ProjectID: types.StringValue(projectId),
Region: types.StringValue(region),
InstanceID: types.StringValue(instanceId),
UserID: types.Int64Value(userId),
}
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
if resp.Diagnostics.HasError() {
return
}
// Map response body to schema
err = mapFields(recordSetResp, &model, region)
if err != nil {
@ -351,6 +375,7 @@ func (r *userResource) Delete(
}
ctx = core.LogResponse(ctx)
resp.State.RemoveResource(ctx)
tflog.Info(ctx, "SQLServer Flex user deleted")
}

View file

@ -66,8 +66,8 @@ func UserResourceSchema(ctx context.Context) schema.Schema {
"roles": schema.ListAttribute{
ElementType: types.StringType,
Required: true,
Description: "A list containing the user roles for the instance.",
MarkdownDescription: "A list containing the user roles for the instance.",
Description: "A list containing the user roles for the instance. A list with the valid user roles can be retrieved using the List Roles endpoint.",
MarkdownDescription: "A list containing the user roles for the instance. A list with the valid user roles can be retrieved using the List Roles endpoint.",
},
"status": schema.StringAttribute{
Computed: true,

View file

@ -69,7 +69,7 @@ func (r *databaseResource) Metadata(
//go:embed planModifiers.yaml
var modifiersFileByte []byte
func (r *databaseResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
func (r *databaseResource) Schema(ctx context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
s := sqlserverflexbetaResGen.DatabaseResourceSchema(ctx)
@ -160,23 +160,16 @@ func (r *databaseResource) Create(ctx context.Context, req resource.CreateReques
return
}
// Read identity data
var identityData DatabaseResourceIdentityModel
resp.Diagnostics.Append(req.Identity.Get(ctx, &identityData)...)
if resp.Diagnostics.HasError() {
return
}
ctx = core.InitProviderContext(ctx)
projectId := identityData.ProjectID.ValueString()
region := identityData.Region.ValueString()
instanceId := identityData.InstanceID.ValueString()
projectId := data.ProjectId.ValueString()
region := data.Region.ValueString()
instanceId := data.InstanceId.ValueString()
ctx = tflog.SetField(ctx, "project_id", projectId)
ctx = tflog.SetField(ctx, "region", region)
ctx = tflog.SetField(ctx, "instance_id", instanceId)
databaseName := identityData.DatabaseName.ValueString()
databaseName := data.Name.ValueString()
ctx = tflog.SetField(ctx, "database_name", databaseName)
payLoad := sqlserverflexbeta.CreateDatabaseRequestPayload{
@ -215,6 +208,18 @@ func (r *databaseResource) Create(ctx context.Context, req resource.CreateReques
ctx = core.LogResponse(ctx)
// Set data returned by API in identity
identity := DatabaseResourceIdentityModel{
ProjectID: types.StringValue(projectId),
Region: types.StringValue(region),
InstanceID: types.StringValue(instanceId),
DatabaseName: types.StringValue(databaseName),
}
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
if resp.Diagnostics.HasError() {
return
}
// TODO: is this neccessary to wait for the database-> API say 200 ?
/*waitResp, err := wait.CreateDatabaseWaitHandler(
ctx,
@ -301,18 +306,6 @@ func (r *databaseResource) Create(ctx context.Context, req resource.CreateReques
return
}
// Set data returned by API in identity
identity := DatabaseResourceIdentityModel{
ProjectID: types.StringValue(projectId),
Region: types.StringValue(region),
InstanceID: types.StringValue(instanceId),
DatabaseName: types.StringValue(databaseName),
}
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
if resp.Diagnostics.HasError() {
return
}
// Set state to fully populated data
resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
if resp.Diagnostics.HasError() {
@ -381,9 +374,20 @@ func (r *databaseResource) Read(ctx context.Context, req resource.ReadRequest, r
return
}
// Save identity into Terraform state
identity := DatabaseResourceIdentityModel{
ProjectID: types.StringValue(projectId),
Region: types.StringValue(region),
InstanceID: types.StringValue(instanceId),
DatabaseName: types.StringValue(databaseName),
}
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
if resp.Diagnostics.HasError() {
return
}
// Set refreshed state
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
if resp.Diagnostics.HasError() {
return
}
@ -391,7 +395,7 @@ func (r *databaseResource) Read(ctx context.Context, req resource.ReadRequest, r
tflog.Info(ctx, "sqlserverflexbeta.Database read")
}
func (r *databaseResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
func (r *databaseResource) Update(ctx context.Context, _ resource.UpdateRequest, resp *resource.UpdateResponse) {
// TODO: Check update api endpoint - not available at the moment, so return an error for now
core.LogAndAddError(ctx, &resp.Diagnostics, "Error updating database", "Database can't be updated")
}
@ -436,6 +440,7 @@ func (r *databaseResource) Delete(ctx context.Context, req resource.DeleteReques
}
ctx = core.LogResponse(ctx)
resp.State.RemoveResource(ctx)
tflog.Info(ctx, "sqlserverflexbeta.Database deleted")
}
@ -453,13 +458,13 @@ func (r *databaseResource) ModifyPlan(
return
}
var configModel sqlserverflexbetaResGen.DatabaseModel
var configModel resourceModel
resp.Diagnostics.Append(req.Config.Get(ctx, &configModel)...)
if resp.Diagnostics.HasError() {
return
}
var planModel sqlserverflexbetaResGen.DatabaseModel
var planModel resourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
if resp.Diagnostics.HasError() {
return
@ -562,8 +567,8 @@ func (r *databaseResource) extractIdentityData(
model resourceModel,
identity DatabaseResourceIdentityModel,
) (projectId, region, instanceId, databaseName string, err error) {
if !model.DatabaseName.IsNull() && !model.DatabaseName.IsUnknown() {
databaseName = model.DatabaseName.ValueString()
if !model.Name.IsNull() && !model.Name.IsUnknown() {
databaseName = model.Name.ValueString()
} else {
if identity.DatabaseName.IsNull() || identity.DatabaseName.IsUnknown() {
return "", "", "", "", fmt.Errorf("database_name not found in config")

View file

@ -160,7 +160,7 @@ func (r *instanceResource) ModifyPlan(
if req.Plan.Raw.IsNull() {
return
}
var planModel sqlserverflexbetaResGen.InstanceModel
var planModel resourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &planModel)...)
if resp.Diagnostics.HasError() {
return
@ -334,6 +334,7 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
return
}
// Save identity into Terraform state
identity := InstanceResourceIdentityModel{
ProjectID: types.StringValue(projectId),
Region: types.StringValue(region),
@ -346,6 +347,9 @@ func (r *instanceResource) Read(ctx context.Context, req resource.ReadRequest, r
// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "sqlserverflexbeta.Instance read")
}
@ -433,6 +437,9 @@ func (r *instanceResource) Update(ctx context.Context, req resource.UpdateReques
// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}
tflog.Info(ctx, "sqlserverflexbeta.Instance updated")
}

View file

@ -165,7 +165,7 @@ func mapFieldsCreate(userResp *sqlserverflexbeta.CreateUserResponse, model *reso
// toCreatePayload converts a resourceModel to an API CreateUserRequestPayload.
func toCreatePayload(
model *resourceModel,
roles []sqlserverflexbeta.UserRole,
roles []string,
) (*sqlserverflexbeta.CreateUserRequestPayload, error) {
if model == nil {
return nil, fmt.Errorf("nil model")

View file

@ -42,7 +42,7 @@ func TestMapDataSourceFields(t *testing.T) {
"simple_values",
&sqlserverflexbeta.GetUserResponse{
Roles: &[]sqlserverflexbeta.UserRole{
Roles: &[]string{
"role_1",
"role_2",
"",
@ -81,7 +81,7 @@ func TestMapDataSourceFields(t *testing.T) {
"null_fields_and_int_conversions",
&sqlserverflexbeta.GetUserResponse{
Id: utils.Ptr(int64(1)),
Roles: &[]sqlserverflexbeta.UserRole{},
Roles: &[]string{},
Username: nil,
Host: nil,
Port: utils.Ptr(int64(2123456789)),
@ -182,7 +182,7 @@ func TestMapFieldsCreate(t *testing.T) {
"simple_values",
&sqlserverflexbeta.CreateUserResponse{
Id: utils.Ptr(int64(2)),
Roles: &[]sqlserverflexbeta.UserRole{
Roles: &[]string{
"role_1",
"role_2",
"",
@ -223,7 +223,7 @@ func TestMapFieldsCreate(t *testing.T) {
"null_fields_and_int_conversions",
&sqlserverflexbeta.CreateUserResponse{
Id: utils.Ptr(int64(3)),
Roles: &[]sqlserverflexbeta.UserRole{},
Roles: &[]string{},
Username: nil,
Password: utils.Ptr(""),
Host: nil,
@ -331,7 +331,7 @@ func TestMapFields(t *testing.T) {
{
"simple_values",
&sqlserverflexbeta.GetUserResponse{
Roles: &[]sqlserverflexbeta.UserRole{
Roles: &[]string{
"role_1",
"role_2",
"",
@ -366,7 +366,7 @@ func TestMapFields(t *testing.T) {
"null_fields_and_int_conversions",
&sqlserverflexbeta.GetUserResponse{
Id: utils.Ptr(int64(1)),
Roles: &[]sqlserverflexbeta.UserRole{},
Roles: &[]string{},
Username: nil,
Host: nil,
Port: utils.Ptr(int64(2123456789)),
@ -437,16 +437,16 @@ func TestToCreatePayload(t *testing.T) {
tests := []struct {
description string
input *resourceModel
inputRoles []sqlserverflexbeta.UserRole
inputRoles []string
expected *sqlserverflexbeta.CreateUserRequestPayload
isValid bool
}{
{
"default_values",
&resourceModel{},
[]sqlserverflexbeta.UserRole{},
[]string{},
&sqlserverflexbeta.CreateUserRequestPayload{
Roles: &[]sqlserverflexbeta.UserRole{},
Roles: &[]string{},
Username: nil,
},
true,
@ -456,12 +456,12 @@ func TestToCreatePayload(t *testing.T) {
&resourceModel{
Username: types.StringValue("username"),
},
[]sqlserverflexbeta.UserRole{
[]string{
"role_1",
"role_2",
},
&sqlserverflexbeta.CreateUserRequestPayload{
Roles: &[]sqlserverflexbeta.UserRole{
Roles: &[]string{
"role_1",
"role_2",
},
@ -474,11 +474,11 @@ func TestToCreatePayload(t *testing.T) {
&resourceModel{
Username: types.StringNull(),
},
[]sqlserverflexbeta.UserRole{
[]string{
"",
},
&sqlserverflexbeta.CreateUserRequestPayload{
Roles: &[]sqlserverflexbeta.UserRole{
Roles: &[]string{
"",
},
Username: nil,
@ -488,7 +488,7 @@ func TestToCreatePayload(t *testing.T) {
{
"nil_model",
nil,
[]sqlserverflexbeta.UserRole{},
[]string{},
nil,
false,
},
@ -497,9 +497,9 @@ func TestToCreatePayload(t *testing.T) {
&resourceModel{
Username: types.StringValue("username"),
},
[]sqlserverflexbeta.UserRole{},
[]string{},
&sqlserverflexbeta.CreateUserRequestPayload{
Roles: &[]sqlserverflexbeta.UserRole{},
Roles: &[]string{},
Username: utils.Ptr("username"),
},
true,

View file

@ -177,7 +177,7 @@ func (r *userResource) Create(
ctx = tflog.SetField(ctx, "instance_id", instanceId)
ctx = tflog.SetField(ctx, "region", region)
var roles []sqlserverflexbeta.UserRole
var roles []string
if !model.Roles.IsNull() && !model.Roles.IsUnknown() {
diags = model.Roles.ElementsAs(ctx, &roles, false)
resp.Diagnostics.Append(diags...)
@ -292,6 +292,18 @@ func (r *userResource) Read(
return
}
// Set data returned by API in identity
identity := UserResourceIdentityModel{
ProjectID: types.StringValue(projectId),
Region: types.StringValue(region),
InstanceID: types.StringValue(instanceId),
UserID: types.Int64Value(userId),
}
resp.Diagnostics.Append(resp.Identity.Set(ctx, identity)...)
if resp.Diagnostics.HasError() {
return
}
// Set refreshed state
diags = resp.State.Set(ctx, model)
resp.Diagnostics.Append(diags...)
@ -350,6 +362,8 @@ func (r *userResource) Delete(
ctx = core.LogResponse(ctx)
resp.State.RemoveResource(ctx)
tflog.Info(ctx, "SQLServer Flex user deleted")
}

View file

@ -66,8 +66,8 @@ func UserResourceSchema(ctx context.Context) schema.Schema {
"roles": schema.ListAttribute{
ElementType: types.StringType,
Required: true,
Description: "A list containing the user roles for the instance.",
MarkdownDescription: "A list containing the user roles for the instance.",
Description: "A list containing the user roles for the instance. A list with the valid user roles can be retrieved using the List Roles endpoint.",
MarkdownDescription: "A list containing the user roles for the instance. A list with the valid user roles can be retrieved using the List Roles endpoint.",
},
"status": schema.StringAttribute{
Computed: true,