Skip to content

Commit

Permalink
Add acceptance tests for secret resource.
Browse files Browse the repository at this point in the history
This tests check Create/Read/Update/Detele func of secretsi.
  • Loading branch information
anvial committed Apr 11, 2024
1 parent 3d8efd0 commit 364a1ca
Show file tree
Hide file tree
Showing 3 changed files with 253 additions and 28 deletions.
13 changes: 11 additions & 2 deletions internal/juju/secrets.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"errors"
"fmt"

jujuerrors "github.com/juju/errors"
"github.com/juju/juju/api"
apisecrets "github.com/juju/juju/api/client/secrets"
coresecrets "github.com/juju/juju/core/secrets"
Expand Down Expand Up @@ -200,12 +199,14 @@ func (c *secretsClient) UpdateSecret(input *UpdateSecretInput) error {
return err
}
if input.Name == nil {
fmt.Println("Updating secret by ID")
// Update secret without changing the name
err = secretAPIClient.UpdateSecret(secretURI, "", input.AutoPrune, "", info, value)
if err != nil {
return typedError(err)
}
} else {
fmt.Println("Updating secret by ID with a new name")
// Update secret with a new name
err = secretAPIClient.UpdateSecret(secretURI, "", input.AutoPrune, *input.Name, info, value)
if err != nil {
Expand All @@ -216,6 +217,8 @@ func (c *secretsClient) UpdateSecret(input *UpdateSecretInput) error {
return errors.New("updating secrets by name is not supported")
}

fmt.Println("Secret updated successfully")

return nil
}

Expand All @@ -226,16 +229,22 @@ func (c *secretsClient) DeleteSecret(input *DeleteSecretInput) error {
return err
}

// print delete secret input
fmt.Printf("deleteSecretInput = %+v\n", input)

secretAPIClient := c.getSecretAPIClient(conn)
secretURI, err := coresecrets.ParseURI(input.SecretId)

fmt.Printf("secretURI = %+v\n", secretURI)
if err != nil {
return err
}
// TODO: think about removing concrete revision.
err = secretAPIClient.RemoveSecret(secretURI, "", nil)
if !errors.Is(err, jujuerrors.NotFound) {
if err != nil {
return typedError(err)
}

fmt.Println("Secret deleted successfully")
return nil
}
82 changes: 57 additions & 25 deletions internal/provider/resource_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ package provider
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"

"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/types"
"github.com/hashicorp/terraform-plugin-log/tflog"

"github.com/juju/terraform-provider-juju/internal/juju"
)

Expand Down Expand Up @@ -60,13 +62,16 @@ func (s *secretResource) Schema(_ context.Context, req resource.SchemaRequest, r
"model": schema.StringAttribute{
Description: "The model in which the secret belongs.",
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"name": schema.StringAttribute{
Description: "The name of the secret. Note that the name cannot be changed once set.",
Description: "The name of the secret.",
Optional: true,
},
"value": schema.MapAttribute{
Description: "The value of the secret.",
Description: "The value map of the secret. There can be more than one key-value pair.",
ElementType: types.StringType,
Required: true,
Sensitive: true,
Expand Down Expand Up @@ -117,7 +122,7 @@ func (s *secretResource) Create(ctx context.Context, req resource.CreateRequest,
return
}

var secretValue map[string]string
secretValue := make(map[string]string)
resp.Diagnostics.Append(plan.Value.ElementsAs(ctx, &secretValue, false)...)

createSecretOutput, err := s.client.Secrets.CreateSecret(&juju.CreateSecretInput{
Expand All @@ -140,10 +145,6 @@ func (s *secretResource) Create(ctx context.Context, req resource.CreateRequest,
s.trace(fmt.Sprintf("create secret resource %q", plan.SecretId))
}

func StringPtr(s string) *string {
return &s
}

func (s *secretResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
// Prevent panic if the provider has not been configured.
if s.client == nil {
Expand All @@ -162,19 +163,32 @@ func (s *secretResource) Read(ctx context.Context, req resource.ReadRequest, res
readSecretOutput, err := s.client.Secrets.ReadSecret(&juju.ReadSecretInput{
SecretId: state.SecretId.ValueString(),
ModelName: state.Model.ValueString(),
Name: StringPtr(state.Name.ValueString()),
Name: state.Name.ValueStringPointer(),
Revision: nil,
})
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read secret, got error: %s", err))
return
}
s.trace(fmt.Sprintf("read secret resource %q", state.SecretId))

stateConfig := make(map[string]string, len(readSecretOutput.Value))
resp.Diagnostics.Append(state.Value.ElementsAs(ctx, &stateConfig, false)...)
// Print the secret details
fmt.Printf("r = %#v\n", readSecretOutput)

// Save the secret details into the Terraform state
if !state.Name.IsNull() {
state.Name = types.StringValue(readSecretOutput.Name)
}
if !state.Info.IsNull() {
state.Info = types.StringValue(readSecretOutput.Info)
}

secretValue, errDiag := types.MapValueFrom(ctx, types.StringType, readSecretOutput.Value)
resp.Diagnostics.Append(errDiag...)
if resp.Diagnostics.HasError() {
return
}
state.Value = secretValue

// Save state into Terraform state
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
Expand All @@ -196,48 +210,63 @@ func (s *secretResource) Update(ctx context.Context, req resource.UpdateRequest,
return
}

// print the plan and state
fmt.Printf("plan = %+v\n", plan)
fmt.Printf("state = %+v\n", state)

var err error
noChange := true

var updatedSecretInput juju.UpdateSecretInput

updatedSecretInput.ModelName = state.Model.ValueString()
updatedSecretInput.SecretId = state.SecretId.ValueString()

// Check if the secret name has changed
secretName := ""
if !plan.Name.Equal(state.Name) {
noChange = false
secretName = plan.Name.ValueString()
state.Name = plan.Name
updatedSecretInput.Name = plan.Name.ValueStringPointer()
} else {
updatedSecretInput.Name = state.Name.ValueStringPointer()
}

// Check if the secret value has changed
secretValue := make(map[string]string)
if !plan.Value.Equal(state.Value) {
noChange = false
resp.Diagnostics.Append(plan.Value.ElementsAs(ctx, &secretValue, false)...)
resp.Diagnostics.Append(plan.Value.ElementsAs(ctx, &state.Value, false)...)
if resp.Diagnostics.HasError() {
return
}
resp.Diagnostics.Append(plan.Value.ElementsAs(ctx, &updatedSecretInput.Value, false)...)
if resp.Diagnostics.HasError() {
return
}
}

// Check if the secret info has changed
secretInfo := ""
if !plan.Info.Equal(state.Info) {
noChange = false
secretInfo = plan.Info.ValueString()
state.Info = plan.Info
updatedSecretInput.Info = plan.Info.ValueStringPointer()
}

if noChange {
return
}

err = s.client.Secrets.UpdateSecret(&juju.UpdateSecretInput{
ModelName: state.Model.ValueString(),
Name: &secretName,
SecretId: state.SecretId.ValueString(),
Value: &secretValue,
Info: &secretInfo,
})
// print the updated secret input
fmt.Printf("updatedSecretInput = %+v\n", updatedSecretInput)

err = s.client.Secrets.UpdateSecret(&updatedSecretInput)
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to update secret, got error: %s", err))
return
}

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

s.trace(fmt.Sprintf("update secret resource %q", state.SecretId))
}

Expand All @@ -256,6 +285,10 @@ func (s *secretResource) Delete(ctx context.Context, req resource.DeleteRequest,
return
}

s.trace("Deleting", map[string]interface{}{
"ID": state.SecretId.ValueString(),
})

err := s.client.Secrets.DeleteSecret(&juju.DeleteSecretInput{
ModelName: state.Model.ValueString(),
SecretId: state.SecretId.ValueString(),
Expand All @@ -264,7 +297,6 @@ func (s *secretResource) Delete(ctx context.Context, req resource.DeleteRequest,
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete secret, got error: %s", err))
return
}
s.trace(fmt.Sprintf("delete secret resource %q", state.SecretId))
}

func (s *secretResource) trace(msg string, additionalFields ...map[string]interface{}) {
Expand Down
Loading

0 comments on commit 364a1ca

Please sign in to comment.