Skip to content

Commit

Permalink
use framework type instead of custom one
Browse files Browse the repository at this point in the history
  • Loading branch information
delca85 committed Oct 11, 2023
1 parent b760d08 commit 3b139b5
Show file tree
Hide file tree
Showing 2 changed files with 205 additions and 33 deletions.
100 changes: 78 additions & 22 deletions internal/provider/resource_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import (
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog"

"github.com/humanitec/humanitec-go-autogen"
"github.com/humanitec/humanitec-go-autogen/client"
Expand Down Expand Up @@ -41,7 +44,7 @@ type ValueModel struct {
Description types.String `tfsdk:"description"`
IsSecret types.Bool `tfsdk:"is_secret"`
Value types.String `tfsdk:"value"`
SecretRef *SecretRef `tfsdk:"secret_ref"`
SecretRef types.Object `tfsdk:"secret_ref"`
}

// SecretRef describes a secret reference that might contain a secret value or a reference to an already stored secret.
Expand All @@ -52,6 +55,15 @@ type SecretRef struct {
Value types.String `tfsdk:"value"`
}

func SecretRefAttributeTypes() map[string]attr.Type {
return map[string]attr.Type{
"ref": types.StringType,
"store": types.StringType,
"version": types.StringType,
"value": types.StringType,
}
}

func (r *ResourceValue) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_value"
}
Expand Down Expand Up @@ -107,18 +119,22 @@ func (r *ResourceValue) Schema(ctx context.Context, req resource.SchemaRequest,
"secret_ref": schema.SingleNestedAttribute{
MarkdownDescription: "The sensitive value that will be stored in the primary organization store or a reference to a sensitive value already stored in one of the registered stores. It can't be defined if is_secret is false or value is defined.",
Optional: true,
Computed: true,
Attributes: map[string]schema.Attribute{
"ref": schema.StringAttribute{
MarkdownDescription: "Secret reference in the format of the target store. It can't be defined if value is defined.",
Optional: true,
Computed: true,
},
"store": schema.StringAttribute{
MarkdownDescription: "Secret Store id. This can't be humanitec (our internal Secret Store). It's mandatory if ref is defined and can't be used if value is defined.",
Optional: true,
Computed: true,
},
"version": schema.StringAttribute{
MarkdownDescription: "Only valid if ref is defined. It's the version of the secret as defined in the target store.",
Optional: true,
Computed: true,
},
"value": schema.StringAttribute{
MarkdownDescription: "Value to store in the secret store. It can't be defined if ref is defined.",
Expand Down Expand Up @@ -156,21 +172,40 @@ func envValueIdPrefix(appID, envID string) string {
return strings.Join([]string{appID, envID}, "/")
}

func parseValueResponse(res *client.ValueResponse, data *ValueModel, idPrefix string) {
func parseValueResponse(ctx context.Context, res *client.ValueResponse, data *ValueModel, idPrefix string) {
data.ID = types.StringValue(strings.Join([]string{idPrefix, res.Key}, "/"))
data.Key = types.StringValue(res.Key)
data.Description = types.StringValue(res.Description)
data.IsSecret = types.BoolValue(res.IsSecret)
if !res.IsSecret {
data.Value = types.StringValue(res.Value)
data.SecretRef = basetypes.NewObjectNull(SecretRefAttributeTypes())
} else {
data.SecretRef = &SecretRef{
Ref: types.StringValue(*res.SecretKey),
Store: types.StringValue(*res.SecretStoreId),
var secretRef SecretRef
if data.SecretRef.IsUnknown() {
secretRef = SecretRef{}
} else {
diags := data.SecretRef.As(ctx, &secretRef, basetypes.ObjectAsOptions{})
if diags.HasError() {
tflog.Debug(ctx, "can't populate secretRef from model", map[string]interface{}{"err": diags.Errors()})
return
}
}

secretRef.Ref = types.StringValue(*res.SecretKey)
secretRef.Store = types.StringValue(*res.SecretStoreId)
if res.SecretVersion != nil {
data.SecretRef.Version = types.StringValue(*res.SecretVersion)
secretRef.Version = types.StringValue(*res.SecretVersion)
}
if secretRef.Value.IsNull() {
secretRef.Value = types.StringNull()
}
objectValue, diags := types.ObjectValueFrom(ctx, SecretRefAttributeTypes(), secretRef)
if diags.HasError() {
tflog.Debug(ctx, "can't decode object from secret ref", map[string]interface{}{"err": diags})
return
}
data.SecretRef = objectValue
}
}

Expand All @@ -194,14 +229,25 @@ func (r *ResourceValue) Create(ctx context.Context, req resource.CreateRequest,
Description: data.Description.ValueStringPointer(),
IsSecret: data.IsSecret.ValueBoolPointer(),
}
if data.SecretRef == nil {
if !data.Value.IsNull() {
createPayload.Value = data.Value.ValueStringPointer()
} else {
createPayload.SecretRef = &client.SecretReference{
Ref: data.SecretRef.Ref.ValueStringPointer(),
Store: data.SecretRef.Store.ValueStringPointer(),
Version: data.SecretRef.Version.ValueStringPointer(),
Value: data.SecretRef.Value.ValueStringPointer(),
var secretRef SecretRef
diags := data.SecretRef.As(ctx, &secretRef, basetypes.ObjectAsOptions{})
if diags.HasError() {
tflog.Debug(ctx, "can't populate secretRef from model", map[string]interface{}{"err": diags.Errors()})
return
}
if !secretRef.Value.IsNull() {
createPayload.SecretRef = &client.SecretReference{
Value: secretRef.Value.ValueStringPointer(),
}
} else {
createPayload.SecretRef = &client.SecretReference{
Ref: secretRef.Ref.ValueStringPointer(),
Store: secretRef.Store.ValueStringPointer(),
Version: secretRef.Version.ValueStringPointer(),
}
}
}

Expand Down Expand Up @@ -236,7 +282,7 @@ func (r *ResourceValue) Create(ctx context.Context, req resource.CreateRequest,
idPrefix = envValueIdPrefix(appID, envID)
}

parseValueResponse(res, data, idPrefix)
parseValueResponse(ctx, res, data, idPrefix)

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
Expand Down Expand Up @@ -299,7 +345,7 @@ func (r *ResourceValue) Read(ctx context.Context, req resource.ReadRequest, resp
return
}

parseValueResponse(&value, data, idPrefix)
parseValueResponse(ctx, &value, data, idPrefix)

// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
Expand All @@ -321,17 +367,27 @@ func (r *ResourceValue) Update(ctx context.Context, req resource.UpdateRequest,
Description: data.Description.ValueStringPointer(),
IsSecret: data.IsSecret.ValueBoolPointer(),
}
if data.SecretRef == nil {
if !data.Value.IsNull() {
editPayload.Value = data.Value.ValueStringPointer()
} else {
editPayload.SecretRef = &client.SecretReference{
Ref: data.SecretRef.Ref.ValueStringPointer(),
Store: data.SecretRef.Store.ValueStringPointer(),
Version: data.SecretRef.Version.ValueStringPointer(),
Value: data.SecretRef.Value.ValueStringPointer(),
var secretRef SecretRef
diags := data.SecretRef.As(ctx, &secretRef, basetypes.ObjectAsOptions{})
if diags.HasError() {
tflog.Debug(ctx, "can't populate secretRef from model", map[string]interface{}{"err": diags.Errors()})
return
}
if !secretRef.Value.IsNull() {
editPayload.SecretRef = &client.SecretReference{
Value: secretRef.Value.ValueStringPointer(),
}
} else {
editPayload.SecretRef = &client.SecretReference{
Ref: secretRef.Ref.ValueStringPointer(),
Store: secretRef.Store.ValueStringPointer(),
Version: secretRef.Version.ValueStringPointer(),
}
}
}

if data.EnvID.IsNull() {
httpResp, err := r.client.PutOrgsOrgIdAppsAppIdValuesKeyWithResponse(ctx, r.orgId, appID, data.Key.ValueString(), editPayload)
if err != nil {
Expand Down Expand Up @@ -363,7 +419,7 @@ func (r *ResourceValue) Update(ctx context.Context, req resource.UpdateRequest,
idPrefix = envValueIdPrefix(appID, envID)
}

parseValueResponse(res, data, idPrefix)
parseValueResponse(ctx, res, data, idPrefix)

// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
Expand Down
Loading

0 comments on commit 3b139b5

Please sign in to comment.