Skip to content

Commit 15639be

Browse files
committed
validation: Return structured errors
The end goal is to return more meaningful error data in the HTTP API rather than just strings: [ { "value":"memory", "default":"9216", "request":"6144", "reason":"invalid", "requires":">= 9216" }, { "value":"disk-size", "default":"31", "request":"19", "reason":"invalid", "requires":">= 31" } ] instead of body: "Value '6144' for configuration property 'memory' is invalid, reason: requires memory in MiB >= 9216\n" + "Value '19' for configuration property 'disk-size' is invalid, reason: requires disk size in GiB >= 31\n" See issue crc-org#2973
1 parent 1e22000 commit 15639be

File tree

5 files changed

+39
-14
lines changed

5 files changed

+39
-14
lines changed

pkg/crc/config/config.go

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010

1111
const (
1212
configPropDoesntExistMsg = "Configuration property '%s' does not exist"
13-
invalidProp = "Value '%v' for configuration property '%s' is invalid, reason: %s"
1413
invalidType = "Type %T for configuration property '%s' is invalid"
1514
)
1615

@@ -59,32 +58,49 @@ func (c *Config) AddSetting(name string, defValue interface{}, validationFn Vali
5958
}
6059
}
6160

61+
type InvalidPropError struct {
62+
value interface{}
63+
key string
64+
err error
65+
}
66+
67+
func (err *InvalidPropError) Error() string {
68+
return fmt.Sprintf("Value '%v' for configuration property '%s' is invalid, reason: %w", err.value, err.key, err.err)
69+
}
70+
71+
func invalidPropError(value interface{}, key string, err error) error {
72+
return &InvalidPropError{
73+
value: value,
74+
key: key,
75+
err: err,
76+
}
77+
}
78+
6279
// Set sets the value for a given config key
6380
func (c *Config) Set(key string, value interface{}) (string, error) {
6481
setting, ok := c.settingsByName[key]
6582
if !ok {
6683
return "", fmt.Errorf(configPropDoesntExistMsg, key)
6784
}
6885

69-
ok, expectedValue := c.settingsByName[key].validationFn(value)
70-
if !ok {
71-
return "", fmt.Errorf(invalidProp, value, key, expectedValue)
86+
err := c.settingsByName[key].validationFn(value)
87+
if err != nil {
88+
return "", invalidPropError(value, key, err)
7289
}
7390

7491
var castValue interface{}
75-
var err error
7692
switch setting.defaultValue.(type) {
7793
case int:
7894
castValue, err = cast.ToIntE(value)
7995
if err != nil {
80-
return "", fmt.Errorf(invalidProp, value, key, err)
96+
return "", invalidPropError(value, key, err)
8197
}
8298
case string:
8399
castValue = cast.ToString(value)
84100
case bool:
85101
castValue, err = cast.ToBoolE(value)
86102
if err != nil {
87-
return "", fmt.Errorf(invalidProp, value, key, err)
103+
return "", invalidPropError(value, key, err)
88104
}
89105
case preset.Preset:
90106
castValue = cast.ToString(value)

pkg/crc/config/settings.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ func RegisterSettings(cfg *Config) {
6868
return ValidateCPUs(value, GetPreset(cfg))
6969
}
7070

71-
validateMemory := func(value interface{}) (bool, string) {
71+
validateMemory := func(value interface{}) error {
7272
return ValidateMemory(value, GetPreset(cfg))
7373
}
7474

pkg/crc/config/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func (v SettingValue) AsInt() int {
4040
}
4141

4242
// validationFnType takes the key, value as args and checks if valid
43-
type ValidationFnType func(interface{}) (bool, string)
43+
type ValidationFnType func(interface{}) error
4444
type SetFn func(string, interface{}) string
4545

4646
// RawStorage stores any key-value pair without validation

pkg/crc/config/validations.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@ func ValidateCPUs(value interface{}, preset crcpreset.Preset) (bool, string) {
5454
}
5555

5656
// ValidateMemory checks if provided memory is valid in the config
57-
func ValidateMemory(value interface{}, preset crcpreset.Preset) (bool, string) {
57+
func ValidateMemory(value interface{}, preset crcpreset.Preset) error {
5858
v, err := cast.ToIntE(value)
5959
if err != nil {
60-
return false, fmt.Sprintf("requires integer value in MiB >= %d", constants.GetDefaultMemory(preset))
60+
return &validation.IntRangeError{value: v, minimumValue: constants.GetDefaultMemory(preset)}
6161
}
6262
if err := validation.ValidateMemory(v, preset); err != nil {
63-
return false, err.Error()
63+
return err
6464
}
65-
return true, ""
65+
return nil
6666
}
6767

6868
// ValidateBundlePath checks if the provided bundle path is valid

pkg/crc/validation/validation.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ import (
1717
"github.com/pbnjay/memory"
1818
)
1919

20+
type IntRangeError struct {
21+
value int
22+
minimumValue int
23+
}
24+
25+
func (err *IntRangeError) Error() string {
26+
return fmt.Sprintf("requires integer value in MiB >= %d", err.minimumValue)
27+
}
28+
2029
// ValidateCPUs checks if provided cpus count is valid
2130
func ValidateCPUs(value int, preset crcpreset.Preset) error {
2231
if value < constants.GetDefaultCPUs(preset) {
@@ -28,7 +37,7 @@ func ValidateCPUs(value int, preset crcpreset.Preset) error {
2837
// ValidateMemory checks if provided Memory count is valid
2938
func ValidateMemory(value int, preset crcpreset.Preset) error {
3039
if value < constants.GetDefaultMemory(preset) {
31-
return fmt.Errorf("requires memory in MiB >= %d", constants.GetDefaultMemory(preset))
40+
return &IntRangeError{value: value, minimumValue: constants.GetDefaultMemory(preset)}
3241
}
3342
return ValidateEnoughMemory(value)
3443
}

0 commit comments

Comments
 (0)