Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9274e81

Browse files
committed
feat: enforce monotonicity in terraform provider
Previous value must come from env var. To read tfstate requireschanging param from a `data` block to a `resource` block
1 parent0fd96ee commit9274e81

File tree

2 files changed

+110
-14
lines changed

2 files changed

+110
-14
lines changed

‎provider/parameter.go

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,13 @@ func parameterDataSource() *schema.Resource {
144144
input=&envValue
145145
}
146146

147-
value,diags:=parameter.ValidateInput(input)
147+
varprevious*string
148+
envPreviousValue,ok:=os.LookupEnv(ParameterEnvironmentVariablePrevious(parameter.Name))
149+
ifok {
150+
previous=&envPreviousValue
151+
}
152+
153+
value,diags:=parameter.ValidateInput(input,previous)
148154
ifdiags.HasError() {
149155
returndiags
150156
}
@@ -393,7 +399,7 @@ func valueIsType(typ OptionType, value string) error {
393399
returnnil
394400
}
395401

396-
func (v*Parameter)ValidateInput(input*string) (string, diag.Diagnostics) {
402+
func (v*Parameter)ValidateInput(input*string,previous*string) (string, diag.Diagnostics) {
397403
varerrerror
398404
varoptionTypeOptionType
399405

@@ -436,7 +442,7 @@ func (v *Parameter) ValidateInput(input *string) (string, diag.Diagnostics) {
436442
forcedValue=*value
437443
}
438444

439-
d:=v.validValue(forcedValue,optionType,optionValues, cty.Path{})
445+
d:=v.validValue(forcedValue,previous,optionType,optionValues, cty.Path{})
440446
ifd.HasError() {
441447
return"",d
442448
}
@@ -500,7 +506,7 @@ func (v *Parameter) ValidOptions(optionType OptionType) (map[string]struct{}, di
500506
returnoptionValues,nil
501507
}
502508

503-
func (v*Parameter)validValue(valuestring,optionTypeOptionType,optionValuesmap[string]struct{},path cty.Path) diag.Diagnostics {
509+
func (v*Parameter)validValue(valuestring,previous*string,optionTypeOptionType,optionValuesmap[string]struct{},path cty.Path) diag.Diagnostics {
504510
// name is used for constructing more precise error messages.
505511
name:="Value"
506512
ifpath.Equals(defaultValuePath) {
@@ -567,7 +573,7 @@ func (v *Parameter) validValue(value string, optionType OptionType, optionValues
567573

568574
iflen(v.Validation)==1 {
569575
validCheck:=&v.Validation[0]
570-
err:=validCheck.Valid(v.Type,value)
576+
err:=validCheck.Valid(v.Type,value,previous)
571577
iferr!=nil {
572578
return diag.Diagnostics{
573579
{
@@ -583,7 +589,7 @@ func (v *Parameter) validValue(value string, optionType OptionType, optionValues
583589
returnnil
584590
}
585591

586-
func (v*Validation)Valid(typOptionType,valuestring)error {
592+
func (v*Validation)Valid(typOptionType,valuestring,previous*string)error {
587593
iftyp!=OptionTypeNumber {
588594
if!v.MinDisabled {
589595
returnfmt.Errorf("a min cannot be specified for a %s type",typ)
@@ -633,6 +639,28 @@ func (v *Validation) Valid(typ OptionType, value string) error {
633639
ifv.Monotonic!=""&&v.Monotonic!=ValidationMonotonicIncreasing&&v.Monotonic!=ValidationMonotonicDecreasing {
634640
returnfmt.Errorf("number monotonicity can be either %q or %q",ValidationMonotonicIncreasing,ValidationMonotonicDecreasing)
635641
}
642+
643+
switchv.Monotonic {
644+
case"":
645+
// No monotonicity check
646+
caseValidationMonotonicIncreasing,ValidationMonotonicDecreasing:
647+
ifprevious!=nil {// Only check if previous value exists
648+
previousNum,err:=strconv.Atoi(*previous)
649+
iferr!=nil {
650+
returnfmt.Errorf("previous value %q is not a number",*previous)
651+
}
652+
653+
ifv.Monotonic==ValidationMonotonicIncreasing&&!(num>=previousNum) {
654+
returnfmt.Errorf("parameter value '%d' must be equal or greater than previous value: %d",num,previousNum)
655+
}
656+
657+
ifv.Monotonic==ValidationMonotonicDecreasing&&!(num<=previousNum) {
658+
returnfmt.Errorf("parameter value '%d' must be equal or lower than previous value: %d",num,previousNum)
659+
}
660+
}
661+
default:
662+
returnfmt.Errorf("number monotonicity can be either %q or %q",ValidationMonotonicIncreasing,ValidationMonotonicDecreasing)
663+
}
636664
caseOptionTypeListString:
637665
varlistOfStrings []string
638666
err:=json.Unmarshal([]byte(value),&listOfStrings)
@@ -660,6 +688,15 @@ func ParameterEnvironmentVariable(name string) string {
660688
return"CODER_PARAMETER_"+hex.EncodeToString(sum[:])
661689
}
662690

691+
// ParameterEnvironmentVariablePrevious returns the environment variable to
692+
// specify for a parameter's previous value. This is used for workspace
693+
// subsequent builds after the first. Primarily to validate monotonicity in the
694+
// `validation` block.
695+
funcParameterEnvironmentVariablePrevious(namestring)string {
696+
sum:=sha256.Sum256([]byte(name))
697+
return"CODER_PARAMETER_PREVIOUS_"+hex.EncodeToString(sum[:])
698+
}
699+
663700
functakeFirstError(errs...error)error {
664701
for_,err:=rangeerrs {
665702
iferr!=nil {

‎provider/parameter_test.go

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -839,7 +839,7 @@ func TestParameterValidation(t *testing.T) {
839839
t.Run(tc.Name,func(t*testing.T) {
840840
t.Parallel()
841841
value:=&tc.Value
842-
_,diags:=tc.Parameter.ValidateInput(value)
842+
_,diags:=tc.Parameter.ValidateInput(value,nil)
843843
iftc.ExpectError!=nil {
844844
require.True(t,diags.HasError())
845845
errMsg:=fmt.Sprintf("%+v",diags[0])// close enough
@@ -919,11 +919,19 @@ func TestParameterValidationEnforcement(t *testing.T) {
919919

920920
varvalidation*provider.Validation
921921
ifcolumns[5]!="" {
922-
// Min-Max validation should look like:
923-
//1-10 :: min=1, max=10
924-
//-10 :: max=10
925-
//1- :: min=1
926-
ifvalidMinMax.MatchString(columns[5]) {
922+
switch {
923+
casecolumns[5]==provider.ValidationMonotonicIncreasing||columns[5]==provider.ValidationMonotonicDecreasing:
924+
validation=&provider.Validation{
925+
MinDisabled:true,
926+
MaxDisabled:true,
927+
Monotonic:columns[5],
928+
Error:"monotonicity",
929+
}
930+
casevalidMinMax.MatchString(columns[5]):
931+
// Min-Max validation should look like:
932+
//1-10 :: min=1, max=10
933+
//-10 :: max=10
934+
//1- :: min=1
927935
parts:=strings.Split(columns[5],"-")
928936
min,_:=strconv.ParseInt(parts[0],10,64)
929937
max,_:=strconv.ParseInt(parts[1],10,64)
@@ -936,7 +944,7 @@ func TestParameterValidationEnforcement(t *testing.T) {
936944
Regex:"",
937945
Error:"{min} < {value} < {max}",
938946
}
939-
}else {
947+
default:
940948
validation=&provider.Validation{
941949
Min:0,
942950
MinDisabled:true,
@@ -1067,6 +1075,7 @@ func TestValueValidatesType(t *testing.T) {
10671075
Namestring
10681076
Type provider.OptionType
10691077
Valuestring
1078+
Previous*string
10701079
Regexstring
10711080
RegexErrorstring
10721081
Minint
@@ -1154,6 +1163,56 @@ func TestValueValidatesType(t *testing.T) {
11541163
Min:0,
11551164
Max:2,
11561165
Monotonic:"decreasing",
1166+
}, {
1167+
Name:"IncreasingMonotonicityEqual",
1168+
Type:"number",
1169+
Previous:ptr("1"),
1170+
Value:"1",
1171+
Monotonic:"increasing",
1172+
MinDisabled:true,
1173+
MaxDisabled:true,
1174+
}, {
1175+
Name:"DecreasingMonotonicityEqual",
1176+
Type:"number",
1177+
Value:"1",
1178+
Previous:ptr("1"),
1179+
Monotonic:"decreasing",
1180+
MinDisabled:true,
1181+
MaxDisabled:true,
1182+
}, {
1183+
Name:"IncreasingMonotonicityGreater",
1184+
Type:"number",
1185+
Previous:ptr("0"),
1186+
Value:"1",
1187+
Monotonic:"increasing",
1188+
MinDisabled:true,
1189+
MaxDisabled:true,
1190+
}, {
1191+
Name:"DecreasingMonotonicityGreater",
1192+
Type:"number",
1193+
Value:"1",
1194+
Previous:ptr("0"),
1195+
Monotonic:"decreasing",
1196+
MinDisabled:true,
1197+
MaxDisabled:true,
1198+
Error:regexp.MustCompile("must be equal or"),
1199+
}, {
1200+
Name:"IncreasingMonotonicityLesser",
1201+
Type:"number",
1202+
Previous:ptr("2"),
1203+
Value:"1",
1204+
Monotonic:"increasing",
1205+
MinDisabled:true,
1206+
MaxDisabled:true,
1207+
Error:regexp.MustCompile("must be equal or"),
1208+
}, {
1209+
Name:"DecreasingMonotonicityLesser",
1210+
Type:"number",
1211+
Value:"1",
1212+
Previous:ptr("2"),
1213+
Monotonic:"decreasing",
1214+
MinDisabled:true,
1215+
MaxDisabled:true,
11571216
}, {
11581217
Name:"ValidListOfStrings",
11591218
Type:"list(string)",
@@ -1205,7 +1264,7 @@ func TestValueValidatesType(t *testing.T) {
12051264
Regex:tc.Regex,
12061265
Error:tc.RegexError,
12071266
}
1208-
err:=v.Valid(tc.Type,tc.Value)
1267+
err:=v.Valid(tc.Type,tc.Value,tc.Previous)
12091268
iftc.Error!=nil {
12101269
require.Error(t,err)
12111270
require.True(t,tc.Error.MatchString(err.Error()),"got: %s",err.Error())

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp