Skip to content

Commit

Permalink
fix: Update framework codgen 0.4.1 and fix resource minimal and defau…
Browse files Browse the repository at this point in the history
…lt state (#11)

* Update terraform-plugin-codegen-framework to v0.4.1

* Return full apply result response on client apply

* Review optional and required user and group attributes in schema

* Fix User and Group resource default state and update on apply

* Add test for minimal User and Group resources definition
  • Loading branch information
qboileau authored Oct 16, 2024
1 parent 6c811e0 commit ecc548f
Show file tree
Hide file tree
Showing 22 changed files with 317 additions and 100 deletions.
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ CDK_BASE_URL=http://localhost:8080
CDK_ADMIN_EMAIL=[email protected]
CDK_ADMIN_PASSWORD=test
CDK_DEBUG=false
TF_LOG=INFO
TF_LOG_PROVIDER_CONDUKTOR=INFO
4 changes: 1 addition & 3 deletions docs/resources/group_v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ resource "conduktor_group_v2" "example" {
spec {
display_name = "Simple Group"
description = "Simple group description"
members = []
permissions = []
}
}
```
Expand Down Expand Up @@ -79,13 +77,13 @@ resource "conduktor_group_v2" "example" {
Required:

- `display_name` (String) Group display name
- `permissions` (Attributes List) Set of all group permissions (see [below for nested schema](#nestedatt--spec--permissions))

Optional:

- `description` (String) Group description
- `external_groups` (List of String) List of external groups from SSO mapped to this group
- `members` (List of String) List of members of the group
- `permissions` (Attributes List) Set of all group permissions (see [below for nested schema](#nestedatt--spec--permissions))

Read-Only:

Expand Down
7 changes: 3 additions & 4 deletions docs/resources/user_v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ This resource allows you to create, read, update and delete users in Conduktor.
resource "conduktor_user_v2" "example" {
name = "[email protected]"
spec {
firstname = "Bob"
lastname = "Smith"
permissions = []
firstname = "Bob"
lastname = "Smith"
}
}
```
Expand Down Expand Up @@ -64,7 +63,7 @@ resource "conduktor_user_v2" "example" {
<a id="nestedblock--spec"></a>
### Nested Schema for `spec`

Required:
Optional:

- `firstname` (String) User firstname
- `lastname` (String) User lastname
Expand Down
2 changes: 0 additions & 2 deletions examples/resources/conduktor_group_v2/simple.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,5 @@ resource "conduktor_group_v2" "example" {
spec {
display_name = "Simple Group"
description = "Simple group description"
members = []
permissions = []
}
}
5 changes: 2 additions & 3 deletions examples/resources/conduktor_user_v2/simple.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
resource "conduktor_user_v2" "example" {
name = "[email protected]"
spec {
firstname = "Bob"
lastname = "Smith"
permissions = []
firstname = "Bob"
lastname = "Smith"
}
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/ghodss/yaml v1.0.0
github.com/go-resty/resty/v2 v2.15.3
github.com/google/go-cmp v0.6.0
github.com/hashicorp/terraform-plugin-codegen-framework v0.4.0
github.com/hashicorp/terraform-plugin-codegen-framework v0.4.1
github.com/hashicorp/terraform-plugin-docs v0.19.4
github.com/hashicorp/terraform-plugin-framework v1.12.0
github.com/hashicorp/terraform-plugin-framework-validators v0.13.0
Expand Down Expand Up @@ -57,7 +57,7 @@ require (
github.com/hashicorp/logutils v1.0.0 // indirect
github.com/hashicorp/terraform-exec v0.21.0 // indirect
github.com/hashicorp/terraform-json v0.22.1 // indirect
github.com/hashicorp/terraform-plugin-codegen-spec v0.1.1 // indirect
github.com/hashicorp/terraform-plugin-codegen-spec v0.2.0 // indirect
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.0 // indirect
github.com/hashicorp/terraform-registry-address v0.2.3 // indirect
github.com/hashicorp/terraform-svchost v0.1.1 // indirect
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,10 @@ github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVW
github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg=
github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7orfb5Ltvec=
github.com/hashicorp/terraform-json v0.22.1/go.mod h1:JbWSQCLFSXFFhg42T7l9iJwdGXBYV8fmmD6o/ML4p3A=
github.com/hashicorp/terraform-plugin-codegen-framework v0.4.0 h1:xB96Rakulnn7ZxikDj8glCyojKpTbW+SGm6QxipoNxU=
github.com/hashicorp/terraform-plugin-codegen-framework v0.4.0/go.mod h1:nXlVjqHFBDr6EXnKTT9RCLmwnuTYj/3LE4ffkIdOtog=
github.com/hashicorp/terraform-plugin-codegen-spec v0.1.1 h1:7djpLeqtz0x6w01W4hckWwINJUnfXn2zGr/EhSC8rek=
github.com/hashicorp/terraform-plugin-codegen-spec v0.1.1/go.mod h1:PQn6bDD8UWoAVJoHXqFk2i/RmLbeQBjbiP38i+E+YIw=
github.com/hashicorp/terraform-plugin-codegen-framework v0.4.1 h1:eaI/3dsu2T5QAXbA+7N+B+UBj20GdtYnsRuYypKh3S4=
github.com/hashicorp/terraform-plugin-codegen-framework v0.4.1/go.mod h1:kpYM23L7NtcfaQdWAN0QFkV/lU0w16qJ2ddAPCI4zAg=
github.com/hashicorp/terraform-plugin-codegen-spec v0.2.0 h1:91dQG1A/DxP6vRz9GiytDTrZTXDbhHPvmpYnAyWA/Vw=
github.com/hashicorp/terraform-plugin-codegen-spec v0.2.0/go.mod h1:fywrEKpordQypmAjz/HIfm2LuNVmyJ6KDe8XT9GdJxQ=
github.com/hashicorp/terraform-plugin-docs v0.19.4 h1:G3Bgo7J22OMtegIgn8Cd/CaSeyEljqjH3G39w28JK4c=
github.com/hashicorp/terraform-plugin-docs v0.19.4/go.mod h1:4pLASsatTmRynVzsjEhbXZ6s7xBlUw/2Kt0zfrq8HxA=
github.com/hashicorp/terraform-plugin-framework v1.12.0 h1:7HKaueHPaikX5/7cbC1r9d1m12iYHY+FlNZEGxQ42CQ=
Expand Down
18 changes: 10 additions & 8 deletions internal/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ type LoginResult struct {
}

type ApplyResult struct {
UpsertResult string
UpsertResult string `json:"upsertResult"`
Resource interface{} `json:"resource"`
}

func Make(ctx context.Context, apiParameter ApiParameter, providerVersion string) (*Client, error) {
Expand Down Expand Up @@ -168,28 +169,29 @@ func (client *Client) ApplyGeneric(ctx context.Context, cliResource ctlresource.
return upsertResponse.UpsertResult, nil
}

func (client *Client) Apply(ctx context.Context, path string, resource interface{}) (string, error) {
func (client *Client) Apply(ctx context.Context, path string, resource interface{}) (ApplyResult, error) {
url := client.baseUrl + path
jsonData, err := jsoniter.Marshal(resource)
if err != nil {
return "", fmt.Errorf("Error marshalling resource: %s", err)
return ApplyResult{}, fmt.Errorf("Error marshalling resource: %s", err)
}

tflog.Trace(ctx, fmt.Sprintf("PUT on %s body : %s", path, string(jsonData)))
tflog.Trace(ctx, fmt.Sprintf("PUT %s request body : %s", path, string(jsonData)))
builder := client.client.R().SetBody(jsonData)
resp, err := builder.Put(url)
if err != nil {
return "", err
return ApplyResult{}, err
} else if resp.IsError() {
return "", fmt.Errorf("%s", extractApiError(resp))
return ApplyResult{}, fmt.Errorf("%s", extractApiError(resp))
}
bodyBytes := resp.Body()
tflog.Trace(ctx, fmt.Sprintf("PUT %s response body : %s", path, string(bodyBytes)))
var upsertResponse ApplyResult
err = jsoniter.Unmarshal(bodyBytes, &upsertResponse)
if err != nil {
return "", fmt.Errorf("Error unmarshalling response: %s", err)
return ApplyResult{}, fmt.Errorf("Error unmarshalling response: %s", err)
}
return upsertResponse.UpsertResult, nil
return upsertResponse, nil
}

func (client *Client) Describe(ctx context.Context, path string) ([]byte, error) {
Expand Down
45 changes: 28 additions & 17 deletions internal/mapper/group_v2/group_v2_resource_mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,20 @@ import (
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-plugin-log/tflog"
)

func TFToInternalModel(ctx context.Context, r *schema.GroupV2Model) (model.GroupConsoleResource, error) {

externalGroups, diag := schemaUtils.ListValueToStringArray(ctx, r.Spec.ExternalGroups)
if r.Spec.ExternalGroups.IsNull() {
tflog.Debug(ctx, "ListValue externalGroups is null")
}

if r.Spec.ExternalGroups.IsUnknown() {
tflog.Debug(ctx, "ListValue externalGroups is unknown")
}

if diag.HasError() {
return model.GroupConsoleResource{}, mapper.WrapDiagError(diag, "externalGroups", mapper.FromTerraform)
}
Expand All @@ -30,25 +39,27 @@ func TFToInternalModel(ctx context.Context, r *schema.GroupV2Model) (model.Group
}

permissions := make([]model.Permission, 0)
var tfPermissions []schema.PermissionsValue
diag = r.Spec.Permissions.ElementsAs(ctx, &tfPermissions, false)
if diag.HasError() {
return model.GroupConsoleResource{}, mapper.WrapDiagError(diag, "permissions", mapper.FromTerraform)
}
for _, p := range tfPermissions {
flags, diag := schemaUtils.ListValueToStringArray(ctx, p.Permissions)
if !r.Spec.Permissions.IsNull() && !r.Spec.Permissions.IsUnknown() {
var tfPermissions []schema.PermissionsValue
diag = r.Spec.Permissions.ElementsAs(ctx, &tfPermissions, false)
if diag.HasError() {
return model.GroupConsoleResource{}, mapper.WrapDiagError(diag, "permissions.permissions", mapper.FromTerraform)
return model.GroupConsoleResource{}, mapper.WrapDiagError(diag, "permissions", mapper.FromTerraform)
}
for _, p := range tfPermissions {
flags, diag := schemaUtils.ListValueToStringArray(ctx, p.Permissions)
if diag.HasError() {
return model.GroupConsoleResource{}, mapper.WrapDiagError(diag, "permissions.permissions", mapper.FromTerraform)
}

permissions = append(permissions, model.Permission{
Name: p.Name.ValueString(),
ResourceType: p.ResourceType.ValueString(),
Permissions: flags,
PatternType: p.PatternType.ValueString(),
Cluster: p.Cluster.ValueString(),
KafkaConnect: p.KafkaConnect.ValueString(),
})
}

permissions = append(permissions, model.Permission{
Name: p.Name.ValueString(),
ResourceType: p.ResourceType.ValueString(),
Permissions: flags,
PatternType: p.PatternType.ValueString(),
Cluster: p.Cluster.ValueString(),
KafkaConnect: p.KafkaConnect.ValueString(),
})
}

return model.NewGroupConsoleResource(
Expand Down
37 changes: 20 additions & 17 deletions internal/mapper/user_v2/user_v2_resource_mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,29 @@ import (
func TFToInternalModel(ctx context.Context, r *schema.UserV2Model) (model.UserConsoleResource, error) {

permissions := make([]model.Permission, 0)
var tfPermissions []schema.PermissionsValue
diag := r.Spec.Permissions.ElementsAs(ctx, &tfPermissions, false)
if diag.HasError() {
return model.UserConsoleResource{}, mapper.WrapDiagError(diag, "permissions", mapper.FromTerraform)
}
for _, p := range tfPermissions {
var flags []string
diag := p.Permissions.ElementsAs(ctx, &flags, false)

if !r.Spec.Permissions.IsNull() && !r.Spec.Permissions.IsUnknown() {
var tfPermissions []schema.PermissionsValue
diag := r.Spec.Permissions.ElementsAs(ctx, &tfPermissions, false)
if diag.HasError() {
return model.UserConsoleResource{}, mapper.WrapDiagError(diag, "permissions.permissions", mapper.FromTerraform)
return model.UserConsoleResource{}, mapper.WrapDiagError(diag, "permissions", mapper.FromTerraform)
}
for _, p := range tfPermissions {
var flags []string
diag := p.Permissions.ElementsAs(ctx, &flags, false)
if diag.HasError() {
return model.UserConsoleResource{}, mapper.WrapDiagError(diag, "permissions.permissions", mapper.FromTerraform)
}

permissions = append(permissions, model.Permission{
Name: p.Name.ValueString(),
ResourceType: p.ResourceType.ValueString(),
Permissions: flags,
PatternType: p.PatternType.ValueString(),
Cluster: p.Cluster.ValueString(),
KafkaConnect: p.KafkaConnect.ValueString(),
})
permissions = append(permissions, model.Permission{
Name: p.Name.ValueString(),
ResourceType: p.ResourceType.ValueString(),
Permissions: flags,
PatternType: p.PatternType.ValueString(),
Cluster: p.Cluster.ValueString(),
KafkaConnect: p.KafkaConnect.ValueString(),
})
}
}

return model.NewUserConsoleResource(
Expand Down
14 changes: 13 additions & 1 deletion internal/model/group_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func (r GroupConsoleMetadata) String() string {
}

type GroupConsoleSpec struct {
Description string `json:"description"`
Description string `json:"description,omitempty"`
DisplayName string `json:"displayName"`
ExternalGroups []string `json:"externalGroups"`
Members []string `json:"members"`
Expand Down Expand Up @@ -75,6 +75,18 @@ func (r *GroupConsoleResource) FromClientResource(cliResource ctlresource.Resour
return nil
}

func (r *GroupConsoleResource) FromRawJsonInterface(jsonInterface interface{}) error {
jsonData, err := json.Marshal(jsonInterface)
if err != nil {
return err
}
err = jsoniter.Unmarshal(jsonData, r)
if err != nil {
return err
}
return nil
}

func NewGroupConsoleResourceFromClientResource(cliResource ctlresource.Resource) (GroupConsoleResource, error) {
var consoleResource GroupConsoleResource
err := consoleResource.FromClientResource(cliResource)
Expand Down
16 changes: 14 additions & 2 deletions internal/model/user_v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ func (r UserConsoleMetadata) String() string {
}

type UserConsoleSpec struct {
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
FirstName string `json:"firstName,omitempty"`
LastName string `json:"lastName,omitempty"`
Permissions []Permission `json:"permissions"`
}

Expand Down Expand Up @@ -72,6 +72,18 @@ func (r *UserConsoleResource) FromClientResource(cliResource ctlresource.Resourc
return nil
}

func (r *UserConsoleResource) FromRawJsonInterface(jsonInterface interface{}) error {
jsonData, err := json.Marshal(jsonInterface)
if err != nil {
return err
}
err = jsoniter.Unmarshal(jsonData, r)
if err != nil {
return err
}
return nil
}

func NewUserConsoleResourceFromClientResource(cliResource ctlresource.Resource) (UserConsoleResource, error) {
var consoleResource UserConsoleResource
err := consoleResource.FromClientResource(cliResource)
Expand Down
37 changes: 32 additions & 5 deletions internal/provider/group_v2_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ func (r *GroupV2Resource) Create(ctx context.Context, req resource.CreateRequest
return
}

tflog.Info(ctx, fmt.Sprintf("Create group named %s", data.Name.String()))
tflog.Trace(ctx, fmt.Sprintf("Create group with TF data: %+v", data))
tflog.Info(ctx, fmt.Sprintf("Creating group named %s", data.Name.String()))
tflog.Trace(ctx, fmt.Sprintf("Create group with desired state : %+v", data))

consoleResource, err := mapper.TFToInternalModel(ctx, &data)
if err != nil {
Expand All @@ -83,7 +83,21 @@ func (r *GroupV2Resource) Create(ctx context.Context, req resource.CreateRequest
return
}

tflog.Debug(ctx, fmt.Sprintf("Group created with result: %s", apply))
tflog.Debug(ctx, fmt.Sprintf("Group created with result: %s", apply.UpsertResult))

var consoleRes = model.GroupConsoleResource{}
err = consoleRes.FromRawJsonInterface(apply.Resource)
if err != nil {
resp.Diagnostics.AddError("Unmarshall Error", fmt.Sprintf("Response resource can't be cast as group : %v, got error: %s", apply.Resource, err))
return
}
tflog.Debug(ctx, fmt.Sprintf("New group state : %+v", consoleRes))

data, err = mapper.InternalModelToTerraform(ctx, &consoleRes)
if err != nil {
resp.Diagnostics.AddError("Model Error", fmt.Sprintf("Unable to read group, got error: %s", err))
return
}

// Save data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
Expand Down Expand Up @@ -140,7 +154,7 @@ func (r *GroupV2Resource) Update(ctx context.Context, req resource.UpdateRequest
return
}

tflog.Info(ctx, fmt.Sprintf("Update group named %s", data.Name.String()))
tflog.Info(ctx, fmt.Sprintf("Updating group named %s", data.Name.String()))
tflog.Trace(ctx, fmt.Sprintf("Update group with TF data: %+v", data))

consoleResource, err := mapper.TFToInternalModel(ctx, &data)
Expand All @@ -157,6 +171,19 @@ func (r *GroupV2Resource) Update(ctx context.Context, req resource.UpdateRequest
}
tflog.Debug(ctx, fmt.Sprintf("Group updated with result: %s", apply))

var consoleRes = model.GroupConsoleResource{}
err = consoleRes.FromRawJsonInterface(apply.Resource)
if err != nil {
resp.Diagnostics.AddError("Unmarshall Error", fmt.Sprintf("Response resource can't be cast as group : %v, got error: %s", apply.Resource, err))
return
}
tflog.Debug(ctx, fmt.Sprintf("New group state : %+v", consoleRes))

data, err = mapper.InternalModelToTerraform(ctx, &consoleRes)
if err != nil {
resp.Diagnostics.AddError("Model Error", fmt.Sprintf("Unable to read group, got error: %s", err))
return
}
// Save updated data into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
Expand All @@ -167,7 +194,7 @@ func (r *GroupV2Resource) Delete(ctx context.Context, req resource.DeleteRequest
// Read Terraform prior state data into the model
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)

tflog.Info(ctx, fmt.Sprintf("Delete group named %s", data.Name.String()))
tflog.Info(ctx, fmt.Sprintf("Deleting group named %s", data.Name.String()))

if resp.Diagnostics.HasError() {
return
Expand Down
Loading

0 comments on commit ecc548f

Please sign in to comment.