Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
anvial committed Apr 11, 2024
1 parent a12d900 commit da78d75
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 29 deletions.
60 changes: 34 additions & 26 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,7 +163,7 @@ 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 {
Expand All @@ -171,12 +172,18 @@ func (s *secretResource) Read(ctx context.Context, req resource.ReadRequest, res
}
s.trace(fmt.Sprintf("read secret resource %q", state.SecretId))

// Print the secret details
fmt.Printf("r = %#v\n", readSecretOutput)

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

encodedValues := readSecretOutput.SecretDetails.Value.EncodedValues()
secretValue, errDiag := types.MapValueFrom(ctx, types.StringType, encodedValues)
secretValue, errDiag := types.MapValueFrom(ctx, types.StringType, readSecretOutput.Value)
resp.Diagnostics.Append(errDiag...)
if resp.Diagnostics.HasError() {
return
Expand Down Expand Up @@ -206,45 +213,46 @@ func (s *secretResource) Update(ctx context.Context, req resource.UpdateRequest,
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()
updatedSecretInput.Name = plan.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)...)
// Print
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()
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,
})
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 Down
84 changes: 81 additions & 3 deletions internal/provider/resource_secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
internaltesting "github.com/juju/terraform-provider-juju/internal/testing"
)

func TestAcc_ResourceSecret(t *testing.T) {
func TestAcc_ResourceSecret_CreateWithInfo(t *testing.T) {
modelName := acctest.RandomWithPrefix("tf-test-model")
secretName := "tf-test-secret"
secretInfo := "test-info"
Expand All @@ -20,8 +20,8 @@ func TestAcc_ResourceSecret(t *testing.T) {
"key2": "value2",
}

// print plan to console
t.Logf("Plan: %s", testAccResourceSecret(modelName, secretName, secretValue, secretInfo))
// Print step plans to console
t.Logf("Step 1 Plan: %s", testAccResourceSecret(modelName, secretName, secretValue, secretInfo))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Expand All @@ -41,6 +41,82 @@ func TestAcc_ResourceSecret(t *testing.T) {
})
}

func TestAcc_ResourceSecret_CreateWithNoInfo(t *testing.T) {
modelName := acctest.RandomWithPrefix("tf-test-model")
secretName := "tf-test-secret"
secretValue := map[string]string{
"key1": "value1",
"key2": "value2",
}

// Print step plans to console
t.Logf("Step 1 Plan: %s", testAccResourceSecret(modelName, secretName, secretValue, ""))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProtoV6ProviderFactories: frameworkProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccResourceSecret(modelName, secretName, secretValue, ""),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("juju_secret."+secretName, "model", modelName),
resource.TestCheckResourceAttr("juju_secret."+secretName, "name", secretName),
resource.TestCheckResourceAttr("juju_secret."+secretName, "value.key1", "value1"),
resource.TestCheckResourceAttr("juju_secret."+secretName, "value.key2", "value2"),
),
},
},
})
}

func TestAcc_ResourceSecret_Update(t *testing.T) {
modelName := acctest.RandomWithPrefix("tf-test-model")
secretName := "tf-test-secret"
secretInfo := "test-info"

updatedSecretInfo := "updated-test-info"

secretValue := map[string]string{
"key1": "value1",
"key2": "value2",
}

secretValueUpdated := map[string]string{
"key1": "value1",
"key2": "newValue2",
"key3": "value3",
}

// Print step plans to console
t.Logf("Step 1 Plan: %s", testAccResourceSecret(modelName, secretName, secretValue, secretInfo))
t.Logf("Step 2 Plan: %s", testAccResourceSecret(modelName, secretName, secretValueUpdated, secretInfo))

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
ProtoV6ProviderFactories: frameworkProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccResourceSecret(modelName, secretName, secretValue, secretInfo),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("juju_secret."+secretName, "model", modelName),
resource.TestCheckResourceAttr("juju_secret."+secretName, "name", secretName),
resource.TestCheckResourceAttr("juju_secret."+secretName, "info", secretInfo),
resource.TestCheckResourceAttr("juju_secret."+secretName, "value.key1", "value1"),
),
},
{
Config: testAccResourceSecret(modelName, secretName, secretValueUpdated, updatedSecretInfo),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("juju_secret."+secretName, "model", modelName),
resource.TestCheckResourceAttr("juju_secret."+secretName, "name", secretName),
resource.TestCheckResourceAttr("juju_secret."+secretName, "info", updatedSecretInfo),
resource.TestCheckResourceAttr("juju_secret."+secretName, "value.key1", "value1"),
),
},
},
})
}

func testAccResourceSecret(modelName, secretName string, secretValue map[string]string, secretInfo string) string {
return internaltesting.GetStringFromTemplateWithData(
"testAccResourceSecret",
Expand All @@ -57,7 +133,9 @@ resource "juju_secret" "{{.SecretName}}" {
"{{$key}}" = "{{$value}}"
{{- end }}
}
{{- if ne .SecretInfo "" }}
info = "{{.SecretInfo}}"
{{- end }}
}
`, internaltesting.TemplateData{
"ModelName": modelName,
Expand Down

0 comments on commit da78d75

Please sign in to comment.