-
Notifications
You must be signed in to change notification settings - Fork 98
/
Copy pathdefinition.go
255 lines (214 loc) · 10 KB
/
definition.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package function
import (
"context"
"fmt"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/internal/fwfunction"
)
// Definition is a function definition. Always set at least the Result field.
//
// NOTE: Provider-defined function support is in technical preview and offered
// without compatibility promises until Terraform 1.8 is generally available.
type Definition struct {
// Parameters is the ordered list of function parameters and their
// associated data types.
Parameters []Parameter
// VariadicParameter is an optional final parameter which can accept zero or
// more arguments when the function is called. The argument data is sent as
// a tuple, where all elements are of the same associated data type.
VariadicParameter Parameter
// Return is the function call response data type.
Return Return
// Summary is a short description of the function, preferably a single
// sentence. Use the Description field for longer documentation about the
// function and its implementation.
Summary string
// Description is the longer documentation for usage, such as editor
// integrations, to give practitioners more information about the purpose of
// the function and how its logic is implemented. It should be plaintext
// formatted.
Description string
// MarkdownDescription is the longer documentation for usage, such as a
// registry, to give practitioners more information about the purpose of the
// function and how its logic is implemented.
MarkdownDescription string
// DeprecationMessage defines warning diagnostic details to display when
// practitioner configurations use this function. The warning diagnostic
// summary is automatically set to "Function Deprecated" along with
// configuration source file and line information.
DeprecationMessage string
}
// Parameter returns the Parameter for a given argument position. This may be
// from the Parameters field or, if defined, the VariadicParameter field. An
// error diagnostic is raised if the position is outside the expected arguments.
func (d Definition) Parameter(ctx context.Context, position int) (Parameter, diag.Diagnostics) {
if d.VariadicParameter != nil && position >= len(d.Parameters) {
return d.VariadicParameter, nil
}
if len(d.Parameters) == 0 {
return nil, diag.Diagnostics{
diag.NewErrorDiagnostic(
"Invalid Parameter Position for Definition",
"When determining the parameter for the given argument position, an invalid value was given. "+
"This is always an issue in the provider code and should be reported to the provider developers.\n\n"+
"Function does not implement parameters.\n"+
fmt.Sprintf("Given position: %d", position),
),
}
}
if position >= len(d.Parameters) {
return nil, diag.Diagnostics{
diag.NewErrorDiagnostic(
"Invalid Parameter Position for Definition",
"When determining the parameter for the given argument position, an invalid value was given. "+
"This is always an issue in the provider code and should be reported to the provider developers.\n\n"+
fmt.Sprintf("Max argument position: %d\n", len(d.Parameters)-1)+
fmt.Sprintf("Given position: %d", position),
),
}
}
return d.Parameters[position], nil
}
// ValidateImplementation contains logic for validating the provider-defined
// implementation of the definition to prevent unexpected errors or panics. This
// logic runs during the GetProviderSchema RPC, or via provider-defined unit
// testing, and should never include false positives.
func (d Definition) ValidateImplementation(ctx context.Context, req DefinitionValidateRequest, resp *DefinitionValidateResponse) {
var diags diag.Diagnostics
if d.Return == nil {
diags.AddError(
"Invalid Function Definition",
"When validating the function definition, an implementation issue was found. "+
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
fmt.Sprintf("Function %q - Definition Return field is undefined", req.FuncName),
)
} else if d.Return.GetType() == nil {
diags.AddError(
"Invalid Function Definition",
"When validating the function definition, an implementation issue was found. "+
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
fmt.Sprintf("Function %q - Definition return data type is undefined", req.FuncName),
)
} else if returnWithValidateImplementation, ok := d.Return.(fwfunction.ReturnWithValidateImplementation); ok {
req := fwfunction.ValidateReturnImplementationRequest{}
resp := &fwfunction.ValidateReturnImplementationResponse{}
returnWithValidateImplementation.ValidateImplementation(ctx, req, resp)
diags.Append(resp.Diagnostics...)
}
paramNames := make(map[string]int, len(d.Parameters))
for pos, param := range d.Parameters {
parameterPosition := int64(pos)
name := param.GetName()
// If name is not set, add an error diagnostic, parameter names are mandatory.
if name == "" {
diags.AddError(
"Invalid Function Definition",
"When validating the function definition, an implementation issue was found. "+
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
fmt.Sprintf("Function %q - Parameter at position %d does not have a name", req.FuncName, pos),
)
}
if paramWithValidateImplementation, ok := param.(fwfunction.ParameterWithValidateImplementation); ok {
req := fwfunction.ValidateParameterImplementationRequest{
Name: name,
ParameterPosition: ¶meterPosition,
}
resp := &fwfunction.ValidateParameterImplementationResponse{}
paramWithValidateImplementation.ValidateImplementation(ctx, req, resp)
diags.Append(resp.Diagnostics...)
}
if paramWithValidateImplementation, ok := param.(fwfunction.ParameterWithValidateImplementation); ok {
req := fwfunction.ValidateParameterImplementationRequest{
Name: name,
ParameterPosition: ¶meterPosition,
}
resp := &fwfunction.ValidateParameterImplementationResponse{}
paramWithValidateImplementation.ValidateImplementation(ctx, req, resp)
diags.Append(resp.Diagnostics...)
}
conflictPos, exists := paramNames[name]
if exists && name != "" {
diags.AddError(
"Invalid Function Definition",
"When validating the function definition, an implementation issue was found. "+
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
"Parameter names must be unique. "+
fmt.Sprintf("Function %q - Parameters at position %d and %d have the same name %q", req.FuncName, conflictPos, pos, name),
)
continue
}
paramNames[name] = pos
}
if d.VariadicParameter != nil {
name := d.VariadicParameter.GetName()
// If name is not set, add an error diagnostic, parameter names are mandatory.
if name == "" {
diags.AddError(
"Invalid Function Definition",
"When validating the function definition, an implementation issue was found. "+
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
fmt.Sprintf("Function %q - The variadic parameter does not have a name", req.FuncName),
)
}
if paramWithValidateImplementation, ok := d.VariadicParameter.(fwfunction.ParameterWithValidateImplementation); ok {
req := fwfunction.ValidateParameterImplementationRequest{
Name: name,
}
resp := &fwfunction.ValidateParameterImplementationResponse{}
paramWithValidateImplementation.ValidateImplementation(ctx, req, resp)
diags.Append(resp.Diagnostics...)
}
if paramWithValidateImplementation, ok := d.VariadicParameter.(fwfunction.ParameterWithValidateImplementation); ok {
req := fwfunction.ValidateParameterImplementationRequest{
Name: name,
}
resp := &fwfunction.ValidateParameterImplementationResponse{}
paramWithValidateImplementation.ValidateImplementation(ctx, req, resp)
diags.Append(resp.Diagnostics...)
}
conflictPos, exists := paramNames[name]
if exists && name != "" {
diags.AddError(
"Invalid Function Definition",
"When validating the function definition, an implementation issue was found. "+
"This is always an issue with the provider and should be reported to the provider developers.\n\n"+
"Parameter names must be unique. "+
fmt.Sprintf("Function %q - Parameter at position %d and the variadic parameter have the same name %q", req.FuncName, conflictPos, name),
)
}
}
resp.Diagnostics.Append(diags...)
}
// DefinitionRequest represents a request for the Function to return its
// definition, such as its ordered parameters and result. An instance of this
// request struct is supplied as an argument to the Function type Definition
// method.
type DefinitionRequest struct{}
// DefinitionResponse represents a response to a DefinitionRequest. An instance
// of this response struct is supplied as an argument to the Function type
// Definition method. Always set at least the Definition field.
type DefinitionResponse struct {
// Definition is the function definition.
Definition Definition
// Diagnostics report errors or warnings related to defining the function.
// An empty slice indicates success, with no warnings or errors generated.
Diagnostics diag.Diagnostics
}
// DefinitionValidateRequest represents a request for the Function to validate its
// definition. An instance of this request struct is supplied as an argument to
// the Definition type ValidateImplementation method.
type DefinitionValidateRequest struct {
// FuncName is the name of the function definition being validated.
FuncName string
}
// DefinitionValidateResponse represents a response to a DefinitionValidateRequest.
// An instance of this response struct is supplied as an argument to the Definition
// type ValidateImplementation method.
type DefinitionValidateResponse struct {
// Diagnostics report errors or warnings related to validation of a function
// definition. An empty slice indicates success, with no warnings or errors
// generated.
Diagnostics diag.Diagnostics
}