Skip to content

Commit

Permalink
feat(application): Adding custom plan validator for ResourceKey
Browse files Browse the repository at this point in the history
ResourceKey schema is validated using a custom PlanValidator named StringIsResourceKeyValidator to to ensure that the string is an int or OCI image information as a URL.
This will allow for failure during the planning phase if the values are not as expected.

Signed-off-by: gatici <[email protected]>
  • Loading branch information
gatici committed Jul 25, 2024
1 parent c1fd22f commit 8897908
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 7 deletions.
5 changes: 1 addition & 4 deletions internal/juju/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,7 @@ func (osFilesystem) Stat(name string) (os.FileInfo, error) {
// Used to detect resources which are given with revision number
func isInt(s string) bool {
_, err := strconv.Atoi(s)
if err != nil {
return false
}
return true
return err == nil
}

// Upload sends the provided resource blob up to Juju.
Expand Down
9 changes: 6 additions & 3 deletions internal/provider/resource_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ There are a few scenarios that need to be considered:
* A resource can be added or changed at any time. If the charm has resources and none are specified in the plan, Juju will use the resource defined in the charm's specified channel. Juju does not allow resources to be removed from an application.
* If a charm is refreshed, by changing the charm revision or channel, the resource is also refreshed to the current defined channel listed for the charm if the resource is specified by revision. This is normal behavior for juju but not typical behavior for terraform.
* If a charm is refreshed, by changing the charm revision or channel, the resource is also refreshed to the current defined channel listed for the charm if the resource is specified by revision. Please note that this is normal behavior for Juju but not typical behavior for Terraform.
* Resources specified by URL to an OCI image repository will never be refreshed (upgraded) by juju during a charm refresh unless explicitly changed in the plan.
`
Expand Down Expand Up @@ -272,8 +272,11 @@ func (r *applicationResource) Schema(_ context.Context, _ resource.SchemaRequest
},
},
ResourceKey: schema.MapAttribute{
Optional: true,
ElementType: types.StringType,
Optional: true,
ElementType: types.StringType,
Validators: []validator.Map{
StringIsResourceKeyValidator{},
},
MarkdownDescription: resourceKeyMarkdownDescription,
},
},
Expand Down
50 changes: 50 additions & 0 deletions internal/provider/validator_resourcekey.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright 2024 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package provider

import (
"context"
"fmt"
"strconv"

"github.com/hashicorp/terraform-plugin-framework/schema/validator"
)

type StringIsResourceKeyValidator struct{}

// Description returns a plain text description of the validator's behavior, suitable for a practitioner to understand its impact.
func (v StringIsResourceKeyValidator) Description(context.Context) string {
return "string must conform to a charm resource: a resource revision number from CharmHub or a custom OCI image resource"
}

// MarkdownDescription returns a markdown formatted description of the validator's behavior, suitable for a practitioner to understand its impact.
func (v StringIsResourceKeyValidator) MarkdownDescription(context.Context) string {
return resourceKeyMarkdownDescription
}

// ValidateMap Validate runs the main validation logic of the validator, reading configuration data out of `req` and updating `resp` with diagnostics.
func (v StringIsResourceKeyValidator) ValidateMap(ctx context.Context, req validator.MapRequest, resp *validator.MapResponse) {
// If the value is unknown or null, there is nothing to validate.
if req.ConfigValue.IsUnknown() || req.ConfigValue.IsNull() {
return
}

var resourceKey map[string]string
resp.Diagnostics.Append(req.ConfigValue.ElementsAs(ctx, &resourceKey, false)...)
if resp.Diagnostics.HasError() {
return
}
for name, value := range resourceKey {
if isInt(value) {
providedRev, err := strconv.Atoi(value)
if err != nil || providedRev <= 0 {
resp.Diagnostics.AddAttributeError(
req.Path,
"Invalid Resource Revision",
fmt.Sprintf("value of %q is expected to be a valid revision number: %s", name, err),
)
}
}
}
}
12 changes: 12 additions & 0 deletions internal/provider/validator_resourcekey_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Copyright 2024 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package provider_test

import (
"testing"
)

func TestResourceKeyValidatorValid(t *testing.T) {

}

0 comments on commit 8897908

Please sign in to comment.