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

Commitf9d70ae

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 parent3c74804 commitf9d70ae

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
}
@@ -395,7 +401,7 @@ func valueIsType(typ OptionType, value string) error {
395401
returnnil
396402
}
397403

398-
func (v*Parameter)ValidateInput(input*string) (string, diag.Diagnostics) {
404+
func (v*Parameter)ValidateInput(input*string,previous*string) (string, diag.Diagnostics) {
399405
varerrerror
400406
varoptionTypeOptionType
401407

@@ -442,7 +448,7 @@ func (v *Parameter) ValidateInput(input *string) (string, diag.Diagnostics) {
442448
forcedValue=*value
443449
}
444450

445-
d:=v.validValue(forcedValue,optionType,optionValues,valuePath)
451+
d:=v.validValue(forcedValue,previous,optionType,optionValues,valuePath)
446452
ifd.HasError() {
447453
return"",d
448454
}
@@ -506,7 +512,7 @@ func (v *Parameter) ValidOptions(optionType OptionType) (map[string]struct{}, di
506512
returnoptionValues,nil
507513
}
508514

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

574580
iflen(v.Validation)==1 {
575581
validCheck:=&v.Validation[0]
576-
err:=validCheck.Valid(v.Type,value)
582+
err:=validCheck.Valid(v.Type,value,previous)
577583
iferr!=nil {
578584
return diag.Diagnostics{
579585
{
@@ -589,7 +595,7 @@ func (v *Parameter) validValue(value string, optionType OptionType, optionValues
589595
returnnil
590596
}
591597

592-
func (v*Validation)Valid(typOptionType,valuestring)error {
598+
func (v*Validation)Valid(typOptionType,valuestring,previous*string)error {
593599
iftyp!=OptionTypeNumber {
594600
if!v.MinDisabled {
595601
returnfmt.Errorf("a min cannot be specified for a %s type",typ)
@@ -639,6 +645,28 @@ func (v *Validation) Valid(typ OptionType, value string) error {
639645
ifv.Monotonic!=""&&v.Monotonic!=ValidationMonotonicIncreasing&&v.Monotonic!=ValidationMonotonicDecreasing {
640646
returnfmt.Errorf("number monotonicity can be either %q or %q",ValidationMonotonicIncreasing,ValidationMonotonicDecreasing)
641647
}
648+
649+
switchv.Monotonic {
650+
case"":
651+
// No monotonicity check
652+
caseValidationMonotonicIncreasing,ValidationMonotonicDecreasing:
653+
ifprevious!=nil {// Only check if previous value exists
654+
previousNum,err:=strconv.Atoi(*previous)
655+
iferr!=nil {
656+
returnfmt.Errorf("previous value %q is not a number",*previous)
657+
}
658+
659+
ifv.Monotonic==ValidationMonotonicIncreasing&&!(num>=previousNum) {
660+
returnfmt.Errorf("parameter value '%d' must be equal or greater than previous value: %d",num,previousNum)
661+
}
662+
663+
ifv.Monotonic==ValidationMonotonicDecreasing&&!(num<=previousNum) {
664+
returnfmt.Errorf("parameter value '%d' must be equal or lower than previous value: %d",num,previousNum)
665+
}
666+
}
667+
default:
668+
returnfmt.Errorf("number monotonicity can be either %q or %q",ValidationMonotonicIncreasing,ValidationMonotonicDecreasing)
669+
}
642670
caseOptionTypeListString:
643671
varlistOfStrings []string
644672
err:=json.Unmarshal([]byte(value),&listOfStrings)
@@ -666,6 +694,15 @@ func ParameterEnvironmentVariable(name string) string {
666694
return"CODER_PARAMETER_"+hex.EncodeToString(sum[:])
667695
}
668696

697+
// ParameterEnvironmentVariablePrevious returns the environment variable to
698+
// specify for a parameter's previous value. This is used for workspace
699+
// subsequent builds after the first. Primarily to validate monotonicity in the
700+
// `validation` block.
701+
funcParameterEnvironmentVariablePrevious(namestring)string {
702+
sum:=sha256.Sum256([]byte(name))
703+
return"CODER_PARAMETER_PREVIOUS_"+hex.EncodeToString(sum[:])
704+
}
705+
669706
functakeFirstError(errs...error)error {
670707
for_,err:=rangeerrs {
671708
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