Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Add support for write only attributes #1375

Draft
wants to merge 42 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
6e8402b
Update `terraform-plugin-go` dependency
SBGoods Aug 30, 2024
d30854f
Add `WriteOnly` attribute to schema and internal schema validation.
SBGoods Aug 30, 2024
17b4a61
Add `WriteOnly` validation for data source, provider, and provider me…
SBGoods Aug 30, 2024
5218321
Add WriteOnly capabilities validation to `ValidateResourceTypeConfig`…
SBGoods Aug 30, 2024
bb2bb08
Skip value validation for `Required` + `WriteOnly` attributes.
SBGoods Aug 30, 2024
1d70831
Fix intermittent test failures for `hasWriteOnly()`
SBGoods Aug 30, 2024
e7d79db
Validate non-null values for `Required` and `WriteOnly` attributes in…
SBGoods Sep 3, 2024
d171fb7
Add initial implementation for `PreferWriteOnlyAttribute()` validator
SBGoods Sep 5, 2024
25c2a13
Finish `PreferWriteOnlyAttribute()` validator implementation.
SBGoods Sep 9, 2024
2f917f8
Move `schema.ValidateResourceConfigFuncs` to `schema.Resource` and im…
SBGoods Sep 9, 2024
cab2a27
Add automatic state handling for writeOnly attributes
SBGoods Sep 10, 2024
6cc6811
Apply suggestions from code review
SBGoods Sep 16, 2024
994bc66
Wrap `setWriteOnlyNullValues` call in client capabilities check
SBGoods Sep 17, 2024
ff70638
Refactor tests to match diag summary changes
SBGoods Sep 17, 2024
c5c870d
Move write-only helper functions and tests to their own files.
SBGoods Sep 17, 2024
21cebbe
Refactor test attribute names for clarity
SBGoods Sep 17, 2024
a276ff4
Refactor `validateWriteOnlyNullValues()` to build an attribute path.`
SBGoods Sep 23, 2024
fac41b5
Refactor `validateWriteOnlyRequiredValues()` to build an attribute pa…
SBGoods Sep 23, 2024
7cf9024
Refactor field and function names based on PR feedback.
SBGoods Sep 23, 2024
d3a4926
Add clarifying comments.
SBGoods Sep 23, 2024
437577d
Add internal validation preventing data sources from defining `Valida…
SBGoods Sep 23, 2024
d5a7bd6
Change `writeOnlyAttributeName` parameter to use `cty.Path`
SBGoods Oct 3, 2024
5c2e2e2
Simplify validation condition logic
SBGoods Oct 3, 2024
1c21c96
Merge branch 'main' into SBGoods/write-only-attributes
SBGoods Nov 25, 2024
a5d8c2a
run `go mod tidy`
SBGoods Nov 25, 2024
3f32220
update `terraform-plugin-go` dependency
SBGoods Nov 25, 2024
28a5768
Add write-only support to `ProtoToConfigSchema()`
SBGoods Nov 26, 2024
2aec830
Nullify write-only attributes during Plan and Apply regardless of cli…
SBGoods Dec 3, 2024
1479d62
Introduce `(*ResourceData).GetRawWriteOnly()` and `(*ResourceData).Ge…
SBGoods Dec 17, 2024
18894a8
Revert "Introduce `(*ResourceData).GetRawWriteOnly()` and `(*Resource…
SBGoods Dec 17, 2024
20550b9
Introduce `(*ResourceData).GetRawConfigAt()` helper method for retrie…
SBGoods Dec 17, 2024
396b49b
null out write-only values
austinvalle Dec 18, 2024
e1dbbac
Return `diag.Diagnostics` instead of error for `(*ResourceData).GetRa…
SBGoods Dec 18, 2024
84b9873
Update `terraform-plugin-go` dependency
SBGoods Dec 18, 2024
0a9d11a
Add additional tests for automatic write-only value nullification
SBGoods Dec 18, 2024
6461314
Resolve linting errors and add copyright headers
SBGoods Dec 18, 2024
45cceb5
Merge branch 'main' into SBGoods/write-only-attributes
SBGoods Dec 18, 2024
0816d60
Remove "incorrect" test case
SBGoods Dec 18, 2024
e844e2d
Use `cty.DynamicVal` as default value for `GetRawConfigAt()`
SBGoods Dec 19, 2024
ec6675f
Throw validation error for computed blocks with write-only attributes
SBGoods Dec 19, 2024
f529da0
add `GetRawConfigAt` to `ResourceDiff` for usage in `CustomizeDiff` f…
austinvalle Jan 3, 2025
5f29273
unit tests for `ResourceDiff`
austinvalle Jan 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ require (
github.com/hashicorp/logutils v1.0.0
github.com/hashicorp/terraform-exec v0.21.0
github.com/hashicorp/terraform-json v0.23.0
github.com/hashicorp/terraform-plugin-go v0.25.0
github.com/hashicorp/terraform-plugin-go v0.25.1-0.20241217173851-dcf8f64dbfaa
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/mitchellh/copystructure v1.2.0
github.com/mitchellh/go-testing-interface v1.14.1
Expand Down Expand Up @@ -49,13 +49,13 @@ require (
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/net v0.28.0 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
google.golang.org/grpc v1.67.1 // indirect
google.golang.org/protobuf v1.35.1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/grpc v1.68.1 // indirect
google.golang.org/protobuf v1.35.2 // indirect
)
20 changes: 10 additions & 10 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVW
github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg=
github.com/hashicorp/terraform-json v0.23.0 h1:sniCkExU4iKtTADReHzACkk8fnpQXrdD2xoR+lppBkI=
github.com/hashicorp/terraform-json v0.23.0/go.mod h1:MHdXbBAbSg0GvzuWazEGKAn/cyNfIB7mN6y7KJN6y2c=
github.com/hashicorp/terraform-plugin-go v0.25.0 h1:oi13cx7xXA6QciMcpcFi/rwA974rdTxjqEhXJjbAyks=
github.com/hashicorp/terraform-plugin-go v0.25.0/go.mod h1:+SYagMYadJP86Kvn+TGeV+ofr/R3g4/If0O5sO96MVw=
github.com/hashicorp/terraform-plugin-go v0.25.1-0.20241217173851-dcf8f64dbfaa h1:GOXZVYZrfDrWxZMHdSNqZKDwayH8WBBtyOLx25ekwv8=
github.com/hashicorp/terraform-plugin-go v0.25.1-0.20241217173851-dcf8f64dbfaa/go.mod h1:OKJU8uauqiLVRWjlFB0KIgK++baq26qfvOU1IVycx9k=
github.com/hashicorp/terraform-plugin-log v0.9.0 h1:i7hOA+vdAItN1/7UrfBqBwvYPQ9TFvymaRGZED3FCV0=
github.com/hashicorp/terraform-plugin-log v0.9.0/go.mod h1:rKL8egZQ/eXSyDqzLUuwUYLVdlYeamldAHSxjUFADow=
github.com/hashicorp/terraform-registry-address v0.2.3 h1:2TAiKJ1A3MAkZlH1YI/aTVcLZRu7JseiXNRHbOAyoTI=
Expand Down Expand Up @@ -153,8 +153,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE=
golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down Expand Up @@ -195,14 +195,14 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 h1:e7S5W7MGGLaSu8j3YjdezkZ+m1/Nm0uRVRMEMGk26Xs=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E=
google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
Expand Down
1 change: 1 addition & 0 deletions helper/schema/core_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ func (s *Schema) coreConfigSchemaAttribute() *configschema.Attribute {
Description: desc,
DescriptionKind: descKind,
Deprecated: s.Deprecated != "",
WriteOnly: s.WriteOnly,
}
}

Expand Down
19 changes: 19 additions & 0 deletions helper/schema/core_schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,25 @@ func TestSchemaMapCoreConfigSchema(t *testing.T) {
BlockTypes: map[string]*configschema.NestedBlock{},
}),
},
"write-only": {
map[string]*Schema{
"string": {
Type: TypeString,
Optional: true,
WriteOnly: true,
},
},
testResource(&configschema.Block{
Attributes: map[string]*configschema.Attribute{
"string": {
Type: cty.String,
Optional: true,
WriteOnly: true,
},
},
BlockTypes: map[string]*configschema.NestedBlock{},
}),
},
}

for name, test := range tests {
Expand Down
42 changes: 42 additions & 0 deletions helper/schema/grpc_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,32 @@ func (s *GRPCProviderServer) ValidateResourceTypeConfig(ctx context.Context, req
resp.Diagnostics = convert.AppendProtoDiag(ctx, resp.Diagnostics, err)
return resp, nil
}
if req.ClientCapabilities == nil || !req.ClientCapabilities.WriteOnlyAttributesAllowed {
SBGoods marked this conversation as resolved.
Show resolved Hide resolved
resp.Diagnostics = convert.AppendProtoDiag(ctx, resp.Diagnostics, validateWriteOnlyNullValues(configVal, schemaBlock, cty.Path{}))
}

r := s.provider.ResourcesMap[req.TypeName]

// Calling all ValidateRawResourceConfigFunc here since they validate on the raw go-cty config value
// and were introduced after the public provider.ValidateResource method.
if r.ValidateRawResourceConfigFuncs != nil {
writeOnlyAllowed := false

if req.ClientCapabilities != nil {
writeOnlyAllowed = req.ClientCapabilities.WriteOnlyAttributesAllowed
}

validateReq := ValidateResourceConfigFuncRequest{
WriteOnlyAttributesAllowed: writeOnlyAllowed,
RawConfig: configVal,
}

for _, validateFunc := range r.ValidateRawResourceConfigFuncs {
validateResp := &ValidateResourceConfigFuncResponse{}
validateFunc(ctx, validateReq, validateResp)
resp.Diagnostics = convert.AppendProtoDiag(ctx, resp.Diagnostics, validateResp.Diagnostics)
}
}

config := terraform.NewResourceConfigShimmed(configVal, schemaBlock)

Expand Down Expand Up @@ -738,6 +764,7 @@ func (s *GRPCProviderServer) ReadResource(ctx context.Context, req *tfprotov5.Re

newStateVal = normalizeNullValues(newStateVal, stateVal, false)
newStateVal = copyTimeoutValues(newStateVal, stateVal)
newStateVal = setWriteOnlyNullValues(newStateVal, schemaBlock)

newStateMP, err := msgpack.Marshal(newStateVal, schemaBlock.ImpliedType())
if err != nil {
Expand Down Expand Up @@ -820,6 +847,16 @@ func (s *GRPCProviderServer) PlanResourceChange(ctx context.Context, req *tfprot
return resp, nil
}

// If the resource is being created, validate that all required write-only
// attributes in the config have non-nil values.
if create {
diags := validateWriteOnlyRequiredValues(configVal, schemaBlock, cty.Path{})
if diags.HasError() {
resp.Diagnostics = convert.AppendProtoDiag(ctx, resp.Diagnostics, diags)
return resp, nil
}
}

priorState, err := res.ShimInstanceStateFromValue(priorStateVal)
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(ctx, resp.Diagnostics, err)
Expand Down Expand Up @@ -937,6 +974,9 @@ func (s *GRPCProviderServer) PlanResourceChange(ctx context.Context, req *tfprot
plannedStateVal = SetUnknowns(plannedStateVal, schemaBlock)
}

// Set any write-only attribute values to null
plannedStateVal = setWriteOnlyNullValues(plannedStateVal, schemaBlock)

plannedMP, err := msgpack.Marshal(plannedStateVal, schemaBlock.ImpliedType())
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(ctx, resp.Diagnostics, err)
Expand Down Expand Up @@ -1184,6 +1224,8 @@ func (s *GRPCProviderServer) ApplyResourceChange(ctx context.Context, req *tfpro

newStateVal = copyTimeoutValues(newStateVal, plannedStateVal)

newStateVal = setWriteOnlyNullValues(newStateVal, schemaBlock)
SBGoods marked this conversation as resolved.
Show resolved Hide resolved
SBGoods marked this conversation as resolved.
Show resolved Hide resolved

newStateMP, err := msgpack.Marshal(newStateVal, schemaBlock.ImpliedType())
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(ctx, resp.Diagnostics, err)
Expand Down
Loading
Loading