Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
anvial committed Jun 14, 2024
1 parent 0fd22d8 commit fc3a919
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 2 deletions.
7 changes: 5 additions & 2 deletions internal/juju/applications.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,9 @@ func (c applicationsClient) CreateApplication(ctx context.Context, input *Create
return nil, err
}

// print transformedInput.storage
c.Tracef("transformedInput.storage", map[string]interface{}{"transformedInput.storage": transformedInput.storage})

applicationAPIClient := apiapplication.NewClient(conn)
if applicationAPIClient.BestAPIVersion() >= 19 {
err = c.deployFromRepository(applicationAPIClient, transformedInput)
Expand Down Expand Up @@ -781,7 +784,7 @@ func (c applicationsClient) ReadApplicationWithRetryOnNotFound(ctx context.Conte
// NOTE: Application can always have storages. However, they
// will not be listed right after the application is created. So
// we need to wait for the storages to be ready. And we need to
// check if all storage contraints have pool equal "" and size equal 0
// check if all storage constraints have pool equal "" and size equal 0
// to drop the error.
for _, storage := range output.Storage {
if storage.Pool == "" || storage.Size == 0 {
Expand Down Expand Up @@ -896,7 +899,7 @@ func (c applicationsClient) ReadApplication(input *ReadApplicationInput) (*ReadA
IncludeStorage: true,
})
if err != nil {
if strings.Contains(err.Error(), "filesystem for storage instance") {
if strings.Contains(err.Error(), "filesystem for storage instance") || strings.Contains(err.Error(), "volume for storage instance") {
// Retry if we get this error. It means the storage is not ready yet.
return nil, &storageNotFoundError{input.AppName}
}
Expand Down
91 changes: 91 additions & 0 deletions internal/provider/resource_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package provider
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier"
"strings"

"github.com/dustin/go-humanize"
Expand Down Expand Up @@ -128,6 +129,92 @@ func (r *applicationResource) Configure(ctx context.Context, req resource.Config
r.subCtx = tflog.NewSubsystem(ctx, LogResourceApplication)
}

func storageSetRequiresReplace(ctx context.Context, req planmodifier.SetRequest, resp *setplanmodifier.RequiresReplaceIfFuncResponse) {

planSet := make(map[string]jujustorage.Constraints)
if !req.PlanValue.IsNull() {
var planStorageSlice []nestedStorage
resp.Diagnostics.Append(req.PlanValue.ElementsAs(ctx, &planStorageSlice, false)...)
if resp.Diagnostics.HasError() {
return
}
if len(planStorageSlice) > 0 {
for _, storage := range planStorageSlice {
storageName := storage.Label.ValueString()
storageSize := storage.Size.ValueString()
storagePool := storage.Pool.ValueString()
storageCount := storage.Count.ValueInt64()

// Validate storage size
parsedStorageSize, err := utils.ParseSize(storageSize)
if err != nil {
resp.Diagnostics.AddError("Invalid StorageContraints Size", fmt.Sprintf("Invalid storage size %q: %s", storageSize, err))
return
}

planSet[storageName] = jujustorage.Constraints{
Size: parsedStorageSize,
Pool: storagePool,
Count: uint64(storageCount),
}
}
}
}

stateSet := make(map[string]jujustorage.Constraints)
if !req.StateValue.IsNull() {
var stateStorageSlice []nestedStorage
resp.Diagnostics.Append(req.StateValue.ElementsAs(ctx, &stateStorageSlice, false)...)
if resp.Diagnostics.HasError() {
return
}
if len(stateStorageSlice) > 0 {
for _, storage := range stateStorageSlice {
storageName := storage.Label.ValueString()
storageSize := storage.Size.ValueString()
storagePool := storage.Pool.ValueString()
storageCount := storage.Count.ValueInt64()

// Validate storage size
parsedStorageSize, err := utils.ParseSize(storageSize)
if err != nil {
resp.Diagnostics.AddError("Invalid StorageConstraints Size", fmt.Sprintf("Invalid storage size %q: %s", storageSize, err))
return
}

stateSet[storageName] = jujustorage.Constraints{
Size: parsedStorageSize,
Pool: storagePool,
Count: uint64(storageCount),
}
}
}
}

// Return false if new items were added and old items were not changed
for key, value := range planSet {
stateValue, ok := stateSet[key]
if !ok {
resp.RequiresReplace = false
return
}
if (value.Size != stateValue.Size) || (value.Pool != stateValue.Pool) || (value.Count != stateValue.Count) {
resp.RequiresReplace = true
return
}
}

// Return true if old items were removed
for key := range stateSet {
if _, ok := planSet[key]; !ok {
resp.RequiresReplace = true
return
}
}

resp.RequiresReplace = false
}

func (r *applicationResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "A resource that represents a single Juju application deployment from a charm. Deployment of bundles" +
Expand Down Expand Up @@ -214,6 +301,10 @@ func (r *applicationResource) Schema(_ context.Context, _ resource.SchemaRequest
PathExpressions: path.MatchRelative().AtAnySetValue().MergeExpressions(path.MatchRelative().AtName("label")),
},
},
PlanModifiers: []planmodifier.Set{
setplanmodifier.RequiresReplaceIf(storageSetRequiresReplace, "", ""),
setplanmodifier.UseStateForUnknown(),
},
},
"trust": schema.BoolAttribute{
Description: "Set the trust for the application.",
Expand Down

0 comments on commit fc3a919

Please sign in to comment.