Skip to content

Commit 3eee796

Browse files
chore(actions): add custom plugin-framework validation (#3532)
* chore(actions): add custom plugin-framework validation * fix: review feedback * fix: optional regional.SchemaAttribute() param
1 parent 27dee65 commit 3eee796

File tree

8 files changed

+394
-17
lines changed

8 files changed

+394
-17
lines changed

internal/locality/regional/schemas_framework.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package regional
22

33
import (
44
"github.com/hashicorp/terraform-plugin-framework/action/schema"
5+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
56
"github.com/scaleway/scaleway-sdk-go/scw"
7+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
68
)
79

810
// AllRegions returns all valid Scaleway regions as strings
@@ -16,9 +18,17 @@ func AllRegions() []string {
1618
}
1719

1820
// SchemaAttribute returns a Plugin Framework schema attribute for a region field
19-
func SchemaAttribute() schema.StringAttribute {
21+
func SchemaAttribute(description ...string) schema.StringAttribute {
22+
desc := "The region you want to attach the resource to"
23+
if len(description) > 0 {
24+
desc = description[0]
25+
}
26+
2027
return schema.StringAttribute{
2128
Optional: true,
22-
Description: "The region you want to attach the resource to",
29+
Description: desc,
30+
Validators: []validator.String{
31+
verify.IsStringOneOfWithWarning(AllRegions()),
32+
},
2333
}
2434
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package zonal
2+
3+
import (
4+
"github.com/hashicorp/terraform-plugin-framework/action/schema"
5+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
6+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
7+
)
8+
9+
// SchemaAttribute returns a Plugin Framework schema attribute for a zone field
10+
func SchemaAttribute(description string) schema.StringAttribute {
11+
return schema.StringAttribute{
12+
Optional: true,
13+
Description: description,
14+
Validators: []validator.String{
15+
verify.IsStringOneOfWithWarning(AllZones()),
16+
},
17+
}
18+
}

internal/services/cockpit/action_trigger_test_alert_action.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@ import (
66

77
"github.com/hashicorp/terraform-plugin-framework/action"
88
"github.com/hashicorp/terraform-plugin-framework/action/schema"
9+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
910
"github.com/hashicorp/terraform-plugin-framework/types"
1011
"github.com/scaleway/scaleway-sdk-go/api/cockpit/v1"
1112
"github.com/scaleway/scaleway-sdk-go/scw"
1213
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/regional"
1314
"github.com/scaleway/terraform-provider-scaleway/v2/internal/meta"
15+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
1416
)
1517

1618
var (
@@ -62,8 +64,11 @@ func (a *TriggerTestAlertAction) Schema(ctx context.Context, req action.SchemaRe
6264
"project_id": schema.StringAttribute{
6365
Required: true,
6466
Description: "ID of the Project",
67+
Validators: []validator.String{
68+
verify.IsStringUUID(),
69+
},
6570
},
66-
"region": regional.SchemaAttribute(),
71+
"region": regional.SchemaAttribute("The region you want to attach the resource to"),
6772
},
6873
}
6974
}

internal/services/instance/action_server_action.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import (
1212
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
1313
"github.com/scaleway/scaleway-sdk-go/scw"
1414
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality"
15+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/zonal"
1516
"github.com/scaleway/terraform-provider-scaleway/v2/internal/meta"
17+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
1618
)
1719

1820
var (
@@ -78,11 +80,11 @@ func (a *ServerAction) Schema(ctx context.Context, req action.SchemaRequest, res
7880
"server_id": schema.StringAttribute{
7981
Required: true,
8082
Description: "Server id to send the action to",
83+
Validators: []validator.String{
84+
verify.IsStringUUID(),
85+
},
8186
},
82-
"zone": schema.StringAttribute{
83-
Optional: true,
84-
Description: "Zone of server to send the action to",
85-
},
87+
"zone": zonal.SchemaAttribute("Zone of server to send the action to"),
8688
"wait": schema.BoolAttribute{
8789
Optional: true,
8890
Description: "Wait for server to finish action",

internal/services/jobs/action_start_job_definition_action.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"fmt"
66

7-
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
87
"github.com/hashicorp/terraform-plugin-framework/action"
98
"github.com/hashicorp/terraform-plugin-framework/action/schema"
109
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
@@ -14,6 +13,7 @@ import (
1413
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality"
1514
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/regional"
1615
"github.com/scaleway/terraform-provider-scaleway/v2/internal/meta"
16+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
1717
)
1818

1919
var (
@@ -69,13 +69,10 @@ func (a *StartJobDefinitionAction) Schema(ctx context.Context, req action.Schema
6969
Required: true,
7070
Description: "ID of the job definition to start. Can be a plain UUID or a regional ID.",
7171
Validators: []validator.String{
72-
stringvalidator.LengthAtLeast(1),
72+
verify.IsStringUUIDOrUUIDWithLocality(),
7373
},
7474
},
75-
"region": schema.StringAttribute{
76-
Optional: true,
77-
Description: "Region of the job definition. If not set, the region is derived from the job_definition_id when possible or from the provider configuration.",
78-
},
75+
"region": regional.SchemaAttribute("Region of the job definition. If not set, the region is derived from the job_definition_id when possible or from the provider configuration."),
7976
"command": schema.StringAttribute{
8077
Optional: true,
8178
Description: "Contextual startup command for this specific job run.",

internal/services/keymanager/action_rotate_key_action.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ import (
66

77
"github.com/hashicorp/terraform-plugin-framework/action"
88
"github.com/hashicorp/terraform-plugin-framework/action/schema"
9+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
910
"github.com/hashicorp/terraform-plugin-framework/types"
1011
key_manager "github.com/scaleway/scaleway-sdk-go/api/key_manager/v1alpha1"
1112
"github.com/scaleway/scaleway-sdk-go/scw"
1213
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality"
1314
"github.com/scaleway/terraform-provider-scaleway/v2/internal/locality/regional"
1415
"github.com/scaleway/terraform-provider-scaleway/v2/internal/meta"
16+
"github.com/scaleway/terraform-provider-scaleway/v2/internal/verify"
1517
)
1618

1719
var (
@@ -60,13 +62,13 @@ func NewRotateKeyAction() action.Action {
6062
func (a *RotateKeyAction) Schema(ctx context.Context, req action.SchemaRequest, resp *action.SchemaResponse) {
6163
resp.Schema = schema.Schema{
6264
Attributes: map[string]schema.Attribute{
63-
"region": schema.StringAttribute{
64-
Optional: true,
65-
Description: "Region of the key. If not set, the region is derived from the key_id when possible or from the provider configuration.",
66-
},
65+
"region": regional.SchemaAttribute("Region of the key. If not set, the region is derived from the key_id when possible or from the provider configuration."),
6766
"key_id": schema.StringAttribute{
6867
Required: true,
6968
Description: "ID of the key to rotate (UUID format)",
69+
Validators: []validator.String{
70+
verify.IsStringUUIDOrUUIDWithLocality(),
71+
},
7072
},
7173
},
7274
}

internal/verify/framework.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package verify
2+
3+
import (
4+
"context"
5+
"regexp"
6+
7+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
8+
"github.com/hashicorp/terraform-plugin-framework/diag"
9+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
10+
)
11+
12+
// Validators for schema.StringAttribute{}
13+
14+
func IsStringUUID() validator.String {
15+
return stringvalidator.RegexMatches(
16+
regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`),
17+
"must be a valid UUID",
18+
)
19+
}
20+
21+
func IsStringUUIDOrUUIDWithLocality() validator.String {
22+
return stringvalidator.RegexMatches(
23+
regexp.MustCompile(`^([a-zA-Z]{2}-[a-zA-Z]{3}/)?[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`),
24+
"must be a valid UUID or UUID with locality prefix (format: aa-aaa-<uuid>)",
25+
)
26+
}
27+
28+
// IsStringOneOfWithWarning only raises a warning if the string is not oneOf validValues
29+
func IsStringOneOfWithWarning(validValues []string) validator.String {
30+
return ErrorToWarningValidator(
31+
stringvalidator.OneOf(validValues...),
32+
)
33+
}
34+
35+
// Converts errors from a validator into warnings
36+
func ErrorToWarningValidator(validator validator.String) validator.String {
37+
return errorToWarningValidator{validator: validator}
38+
}
39+
40+
type errorToWarningValidator struct {
41+
validator validator.String
42+
}
43+
44+
func (v errorToWarningValidator) Description(ctx context.Context) string {
45+
return v.validator.Description(ctx)
46+
}
47+
48+
func (v errorToWarningValidator) MarkdownDescription(ctx context.Context) string {
49+
return v.validator.MarkdownDescription(ctx)
50+
}
51+
52+
func (v errorToWarningValidator) ValidateString(ctx context.Context, req validator.StringRequest, resp *validator.StringResponse) {
53+
// Create a new response to capture the original diagnostics
54+
validationResp := &validator.StringResponse{}
55+
56+
// Run the original validator
57+
v.validator.ValidateString(ctx, req, validationResp)
58+
59+
// Convert any errors to warnings
60+
for _, d := range validationResp.Diagnostics {
61+
if d.Severity() == diag.SeverityError {
62+
// Convert error to warning using the diag.NewWarningDiagnostic function
63+
warningDiag := diag.NewWarningDiagnostic(
64+
d.Summary(),
65+
d.Detail(),
66+
)
67+
resp.Diagnostics = append(resp.Diagnostics, warningDiag)
68+
} else {
69+
// Keep existing warnings or info
70+
resp.Diagnostics = append(resp.Diagnostics, d)
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)