]>
Commit | Line | Data |
---|---|---|
107c1cdb ND |
1 | package plugin |
2 | ||
3 | import ( | |
4 | "context" | |
5 | "errors" | |
6 | "log" | |
7 | "sync" | |
8 | ||
9 | "github.com/zclconf/go-cty/cty" | |
10 | ||
11 | plugin "github.com/hashicorp/go-plugin" | |
12 | proto "github.com/hashicorp/terraform/internal/tfplugin5" | |
13 | "github.com/hashicorp/terraform/plugin/convert" | |
14 | "github.com/hashicorp/terraform/providers" | |
15 | "github.com/hashicorp/terraform/version" | |
16 | "github.com/zclconf/go-cty/cty/msgpack" | |
17 | "google.golang.org/grpc" | |
18 | ) | |
19 | ||
20 | // GRPCProviderPlugin implements plugin.GRPCPlugin for the go-plugin package. | |
21 | type GRPCProviderPlugin struct { | |
22 | plugin.Plugin | |
23 | GRPCProvider func() proto.ProviderServer | |
24 | } | |
25 | ||
26 | func (p *GRPCProviderPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) { | |
27 | return &GRPCProvider{ | |
28 | client: proto.NewProviderClient(c), | |
29 | ctx: ctx, | |
30 | }, nil | |
31 | } | |
32 | ||
33 | func (p *GRPCProviderPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error { | |
34 | proto.RegisterProviderServer(s, p.GRPCProvider()) | |
35 | return nil | |
36 | } | |
37 | ||
38 | // GRPCProvider handles the client, or core side of the plugin rpc connection. | |
39 | // The GRPCProvider methods are mostly a translation layer between the | |
40 | // terraform provioders types and the grpc proto types, directly converting | |
41 | // between the two. | |
42 | type GRPCProvider struct { | |
43 | // PluginClient provides a reference to the plugin.Client which controls the plugin process. | |
44 | // This allows the GRPCProvider a way to shutdown the plugin process. | |
45 | PluginClient *plugin.Client | |
46 | ||
47 | // TestServer contains a grpc.Server to close when the GRPCProvider is being | |
48 | // used in an end to end test of a provider. | |
49 | TestServer *grpc.Server | |
50 | ||
51 | // Proto client use to make the grpc service calls. | |
52 | client proto.ProviderClient | |
53 | ||
54 | // this context is created by the plugin package, and is canceled when the | |
55 | // plugin process ends. | |
56 | ctx context.Context | |
57 | ||
58 | // schema stores the schema for this provider. This is used to properly | |
59 | // serialize the state for requests. | |
60 | mu sync.Mutex | |
61 | schemas providers.GetSchemaResponse | |
62 | } | |
63 | ||
64 | // getSchema is used internally to get the saved provider schema. The schema | |
65 | // should have already been fetched from the provider, but we have to | |
66 | // synchronize access to avoid being called concurrently with GetSchema. | |
67 | func (p *GRPCProvider) getSchema() providers.GetSchemaResponse { | |
68 | p.mu.Lock() | |
69 | // unlock inline in case GetSchema needs to be called | |
70 | if p.schemas.Provider.Block != nil { | |
71 | p.mu.Unlock() | |
72 | return p.schemas | |
73 | } | |
74 | p.mu.Unlock() | |
75 | ||
76 | // the schema should have been fetched already, but give it another shot | |
77 | // just in case things are being called out of order. This may happen for | |
78 | // tests. | |
79 | schemas := p.GetSchema() | |
80 | if schemas.Diagnostics.HasErrors() { | |
81 | panic(schemas.Diagnostics.Err()) | |
82 | } | |
83 | ||
84 | return schemas | |
85 | } | |
86 | ||
87 | // getResourceSchema is a helper to extract the schema for a resource, and | |
88 | // panics if the schema is not available. | |
89 | func (p *GRPCProvider) getResourceSchema(name string) providers.Schema { | |
90 | schema := p.getSchema() | |
91 | resSchema, ok := schema.ResourceTypes[name] | |
92 | if !ok { | |
93 | panic("unknown resource type " + name) | |
94 | } | |
95 | return resSchema | |
96 | } | |
97 | ||
98 | // gettDatasourceSchema is a helper to extract the schema for a datasource, and | |
99 | // panics if that schema is not available. | |
100 | func (p *GRPCProvider) getDatasourceSchema(name string) providers.Schema { | |
101 | schema := p.getSchema() | |
102 | dataSchema, ok := schema.DataSources[name] | |
103 | if !ok { | |
104 | panic("unknown data source " + name) | |
105 | } | |
106 | return dataSchema | |
107 | } | |
108 | ||
109 | func (p *GRPCProvider) GetSchema() (resp providers.GetSchemaResponse) { | |
110 | log.Printf("[TRACE] GRPCProvider: GetSchema") | |
111 | p.mu.Lock() | |
112 | defer p.mu.Unlock() | |
113 | ||
114 | if p.schemas.Provider.Block != nil { | |
115 | return p.schemas | |
116 | } | |
117 | ||
118 | resp.ResourceTypes = make(map[string]providers.Schema) | |
119 | resp.DataSources = make(map[string]providers.Schema) | |
120 | ||
121 | // Some providers may generate quite large schemas, and the internal default | |
122 | // grpc response size limit is 4MB. 64MB should cover most any use case, and | |
123 | // if we get providers nearing that we may want to consider a finer-grained | |
124 | // API to fetch individual resource schemas. | |
125 | // Note: this option is marked as EXPERIMENTAL in the grpc API. | |
126 | const maxRecvSize = 64 << 20 | |
127 | protoResp, err := p.client.GetSchema(p.ctx, new(proto.GetProviderSchema_Request), grpc.MaxRecvMsgSizeCallOption{MaxRecvMsgSize: maxRecvSize}) | |
128 | if err != nil { | |
129 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
130 | return resp | |
131 | } | |
132 | ||
133 | resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics)) | |
134 | ||
135 | if protoResp.Provider == nil { | |
136 | resp.Diagnostics = resp.Diagnostics.Append(errors.New("missing provider schema")) | |
137 | return resp | |
138 | } | |
139 | ||
140 | resp.Provider = convert.ProtoToProviderSchema(protoResp.Provider) | |
141 | ||
142 | for name, res := range protoResp.ResourceSchemas { | |
143 | resp.ResourceTypes[name] = convert.ProtoToProviderSchema(res) | |
144 | } | |
145 | ||
146 | for name, data := range protoResp.DataSourceSchemas { | |
147 | resp.DataSources[name] = convert.ProtoToProviderSchema(data) | |
148 | } | |
149 | ||
150 | p.schemas = resp | |
151 | ||
152 | return resp | |
153 | } | |
154 | ||
155 | func (p *GRPCProvider) PrepareProviderConfig(r providers.PrepareProviderConfigRequest) (resp providers.PrepareProviderConfigResponse) { | |
156 | log.Printf("[TRACE] GRPCProvider: PrepareProviderConfig") | |
157 | ||
158 | schema := p.getSchema() | |
159 | ty := schema.Provider.Block.ImpliedType() | |
160 | ||
161 | mp, err := msgpack.Marshal(r.Config, ty) | |
162 | if err != nil { | |
163 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
164 | return resp | |
165 | } | |
166 | ||
167 | protoReq := &proto.PrepareProviderConfig_Request{ | |
168 | Config: &proto.DynamicValue{Msgpack: mp}, | |
169 | } | |
170 | ||
171 | protoResp, err := p.client.PrepareProviderConfig(p.ctx, protoReq) | |
172 | if err != nil { | |
173 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
174 | return resp | |
175 | } | |
176 | ||
177 | config := cty.NullVal(ty) | |
178 | if protoResp.PreparedConfig != nil { | |
179 | config, err = msgpack.Unmarshal(protoResp.PreparedConfig.Msgpack, ty) | |
180 | if err != nil { | |
181 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
182 | return resp | |
183 | } | |
184 | } | |
185 | resp.PreparedConfig = config | |
186 | ||
187 | resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics)) | |
188 | return resp | |
189 | } | |
190 | ||
191 | func (p *GRPCProvider) ValidateResourceTypeConfig(r providers.ValidateResourceTypeConfigRequest) (resp providers.ValidateResourceTypeConfigResponse) { | |
192 | log.Printf("[TRACE] GRPCProvider: ValidateResourceTypeConfig") | |
193 | resourceSchema := p.getResourceSchema(r.TypeName) | |
194 | ||
195 | mp, err := msgpack.Marshal(r.Config, resourceSchema.Block.ImpliedType()) | |
196 | if err != nil { | |
197 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
198 | return resp | |
199 | } | |
200 | ||
201 | protoReq := &proto.ValidateResourceTypeConfig_Request{ | |
202 | TypeName: r.TypeName, | |
203 | Config: &proto.DynamicValue{Msgpack: mp}, | |
204 | } | |
205 | ||
206 | protoResp, err := p.client.ValidateResourceTypeConfig(p.ctx, protoReq) | |
207 | if err != nil { | |
208 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
209 | return resp | |
210 | } | |
211 | ||
212 | resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics)) | |
213 | return resp | |
214 | } | |
215 | ||
216 | func (p *GRPCProvider) ValidateDataSourceConfig(r providers.ValidateDataSourceConfigRequest) (resp providers.ValidateDataSourceConfigResponse) { | |
217 | log.Printf("[TRACE] GRPCProvider: ValidateDataSourceConfig") | |
218 | ||
219 | dataSchema := p.getDatasourceSchema(r.TypeName) | |
220 | ||
221 | mp, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType()) | |
222 | if err != nil { | |
223 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
224 | return resp | |
225 | } | |
226 | ||
227 | protoReq := &proto.ValidateDataSourceConfig_Request{ | |
228 | TypeName: r.TypeName, | |
229 | Config: &proto.DynamicValue{Msgpack: mp}, | |
230 | } | |
231 | ||
232 | protoResp, err := p.client.ValidateDataSourceConfig(p.ctx, protoReq) | |
233 | if err != nil { | |
234 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
235 | return resp | |
236 | } | |
237 | resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics)) | |
238 | return resp | |
239 | } | |
240 | ||
241 | func (p *GRPCProvider) UpgradeResourceState(r providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) { | |
242 | log.Printf("[TRACE] GRPCProvider: UpgradeResourceState") | |
243 | ||
244 | resSchema := p.getResourceSchema(r.TypeName) | |
245 | ||
246 | protoReq := &proto.UpgradeResourceState_Request{ | |
247 | TypeName: r.TypeName, | |
248 | Version: int64(r.Version), | |
249 | RawState: &proto.RawState{ | |
250 | Json: r.RawStateJSON, | |
251 | Flatmap: r.RawStateFlatmap, | |
252 | }, | |
253 | } | |
254 | ||
255 | protoResp, err := p.client.UpgradeResourceState(p.ctx, protoReq) | |
256 | if err != nil { | |
257 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
258 | return resp | |
259 | } | |
260 | resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics)) | |
261 | ||
262 | state := cty.NullVal(resSchema.Block.ImpliedType()) | |
263 | if protoResp.UpgradedState != nil { | |
264 | state, err = msgpack.Unmarshal(protoResp.UpgradedState.Msgpack, resSchema.Block.ImpliedType()) | |
265 | if err != nil { | |
266 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
267 | return resp | |
268 | } | |
269 | } | |
270 | ||
271 | resp.UpgradedState = state | |
272 | return resp | |
273 | } | |
274 | ||
275 | func (p *GRPCProvider) Configure(r providers.ConfigureRequest) (resp providers.ConfigureResponse) { | |
276 | log.Printf("[TRACE] GRPCProvider: Configure") | |
277 | ||
278 | schema := p.getSchema() | |
279 | ||
280 | var mp []byte | |
281 | ||
282 | // we don't have anything to marshal if there's no config | |
283 | mp, err := msgpack.Marshal(r.Config, schema.Provider.Block.ImpliedType()) | |
284 | if err != nil { | |
285 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
286 | return resp | |
287 | } | |
288 | ||
289 | protoReq := &proto.Configure_Request{ | |
290 | TerraformVersion: version.Version, | |
291 | Config: &proto.DynamicValue{ | |
292 | Msgpack: mp, | |
293 | }, | |
294 | } | |
295 | ||
296 | protoResp, err := p.client.Configure(p.ctx, protoReq) | |
297 | if err != nil { | |
298 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
299 | return resp | |
300 | } | |
301 | resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics)) | |
302 | return resp | |
303 | } | |
304 | ||
305 | func (p *GRPCProvider) Stop() error { | |
306 | log.Printf("[TRACE] GRPCProvider: Stop") | |
307 | ||
308 | resp, err := p.client.Stop(p.ctx, new(proto.Stop_Request)) | |
309 | if err != nil { | |
310 | return err | |
311 | } | |
312 | ||
313 | if resp.Error != "" { | |
314 | return errors.New(resp.Error) | |
315 | } | |
316 | return nil | |
317 | } | |
318 | ||
319 | func (p *GRPCProvider) ReadResource(r providers.ReadResourceRequest) (resp providers.ReadResourceResponse) { | |
320 | log.Printf("[TRACE] GRPCProvider: ReadResource") | |
321 | ||
322 | resSchema := p.getResourceSchema(r.TypeName) | |
323 | ||
324 | mp, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType()) | |
325 | if err != nil { | |
326 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
327 | return resp | |
328 | } | |
329 | ||
330 | protoReq := &proto.ReadResource_Request{ | |
331 | TypeName: r.TypeName, | |
332 | CurrentState: &proto.DynamicValue{Msgpack: mp}, | |
333 | } | |
334 | ||
335 | protoResp, err := p.client.ReadResource(p.ctx, protoReq) | |
336 | if err != nil { | |
337 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
338 | return resp | |
339 | } | |
340 | resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics)) | |
341 | ||
342 | state := cty.NullVal(resSchema.Block.ImpliedType()) | |
343 | if protoResp.NewState != nil { | |
344 | state, err = msgpack.Unmarshal(protoResp.NewState.Msgpack, resSchema.Block.ImpliedType()) | |
345 | if err != nil { | |
346 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
347 | return resp | |
348 | } | |
349 | } | |
350 | resp.NewState = state | |
351 | ||
352 | return resp | |
353 | } | |
354 | ||
355 | func (p *GRPCProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) { | |
356 | log.Printf("[TRACE] GRPCProvider: PlanResourceChange") | |
357 | ||
358 | resSchema := p.getResourceSchema(r.TypeName) | |
359 | ||
360 | priorMP, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType()) | |
361 | if err != nil { | |
362 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
363 | return resp | |
364 | } | |
365 | ||
366 | configMP, err := msgpack.Marshal(r.Config, resSchema.Block.ImpliedType()) | |
367 | if err != nil { | |
368 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
369 | return resp | |
370 | } | |
371 | ||
372 | propMP, err := msgpack.Marshal(r.ProposedNewState, resSchema.Block.ImpliedType()) | |
373 | if err != nil { | |
374 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
375 | return resp | |
376 | } | |
377 | ||
378 | protoReq := &proto.PlanResourceChange_Request{ | |
379 | TypeName: r.TypeName, | |
380 | PriorState: &proto.DynamicValue{Msgpack: priorMP}, | |
381 | Config: &proto.DynamicValue{Msgpack: configMP}, | |
382 | ProposedNewState: &proto.DynamicValue{Msgpack: propMP}, | |
383 | PriorPrivate: r.PriorPrivate, | |
384 | } | |
385 | ||
386 | protoResp, err := p.client.PlanResourceChange(p.ctx, protoReq) | |
387 | if err != nil { | |
388 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
389 | return resp | |
390 | } | |
391 | resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics)) | |
392 | ||
393 | state := cty.NullVal(resSchema.Block.ImpliedType()) | |
394 | if protoResp.PlannedState != nil { | |
395 | state, err = msgpack.Unmarshal(protoResp.PlannedState.Msgpack, resSchema.Block.ImpliedType()) | |
396 | if err != nil { | |
397 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
398 | return resp | |
399 | } | |
400 | } | |
401 | resp.PlannedState = state | |
402 | ||
403 | for _, p := range protoResp.RequiresReplace { | |
404 | resp.RequiresReplace = append(resp.RequiresReplace, convert.AttributePathToPath(p)) | |
405 | } | |
406 | ||
407 | resp.PlannedPrivate = protoResp.PlannedPrivate | |
408 | ||
409 | resp.LegacyTypeSystem = protoResp.LegacyTypeSystem | |
410 | ||
411 | return resp | |
412 | } | |
413 | ||
414 | func (p *GRPCProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) { | |
415 | log.Printf("[TRACE] GRPCProvider: ApplyResourceChange") | |
416 | ||
417 | resSchema := p.getResourceSchema(r.TypeName) | |
418 | ||
419 | priorMP, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType()) | |
420 | if err != nil { | |
421 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
422 | return resp | |
423 | } | |
424 | plannedMP, err := msgpack.Marshal(r.PlannedState, resSchema.Block.ImpliedType()) | |
425 | if err != nil { | |
426 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
427 | return resp | |
428 | } | |
429 | configMP, err := msgpack.Marshal(r.Config, resSchema.Block.ImpliedType()) | |
430 | if err != nil { | |
431 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
432 | return resp | |
433 | } | |
434 | ||
435 | protoReq := &proto.ApplyResourceChange_Request{ | |
436 | TypeName: r.TypeName, | |
437 | PriorState: &proto.DynamicValue{Msgpack: priorMP}, | |
438 | PlannedState: &proto.DynamicValue{Msgpack: plannedMP}, | |
439 | Config: &proto.DynamicValue{Msgpack: configMP}, | |
440 | PlannedPrivate: r.PlannedPrivate, | |
441 | } | |
442 | ||
443 | protoResp, err := p.client.ApplyResourceChange(p.ctx, protoReq) | |
444 | if err != nil { | |
445 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
446 | return resp | |
447 | } | |
448 | resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics)) | |
449 | ||
450 | resp.Private = protoResp.Private | |
451 | ||
452 | state := cty.NullVal(resSchema.Block.ImpliedType()) | |
453 | if protoResp.NewState != nil { | |
454 | state, err = msgpack.Unmarshal(protoResp.NewState.Msgpack, resSchema.Block.ImpliedType()) | |
455 | if err != nil { | |
456 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
457 | return resp | |
458 | } | |
459 | } | |
460 | resp.NewState = state | |
461 | ||
462 | resp.LegacyTypeSystem = protoResp.LegacyTypeSystem | |
463 | ||
464 | return resp | |
465 | } | |
466 | ||
467 | func (p *GRPCProvider) ImportResourceState(r providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) { | |
468 | log.Printf("[TRACE] GRPCProvider: ImportResourceState") | |
469 | ||
470 | protoReq := &proto.ImportResourceState_Request{ | |
471 | TypeName: r.TypeName, | |
472 | Id: r.ID, | |
473 | } | |
474 | ||
475 | protoResp, err := p.client.ImportResourceState(p.ctx, protoReq) | |
476 | if err != nil { | |
477 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
478 | return resp | |
479 | } | |
480 | resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics)) | |
481 | ||
482 | for _, imported := range protoResp.ImportedResources { | |
483 | resource := providers.ImportedResource{ | |
484 | TypeName: imported.TypeName, | |
485 | Private: imported.Private, | |
486 | } | |
487 | ||
488 | resSchema := p.getResourceSchema(resource.TypeName) | |
489 | state := cty.NullVal(resSchema.Block.ImpliedType()) | |
490 | if imported.State != nil { | |
491 | state, err = msgpack.Unmarshal(imported.State.Msgpack, resSchema.Block.ImpliedType()) | |
492 | if err != nil { | |
493 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
494 | return resp | |
495 | } | |
496 | } | |
497 | resource.State = state | |
498 | resp.ImportedResources = append(resp.ImportedResources, resource) | |
499 | } | |
500 | ||
501 | return resp | |
502 | } | |
503 | ||
504 | func (p *GRPCProvider) ReadDataSource(r providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) { | |
505 | log.Printf("[TRACE] GRPCProvider: ReadDataSource") | |
506 | ||
507 | dataSchema := p.getDatasourceSchema(r.TypeName) | |
508 | ||
509 | config, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType()) | |
510 | if err != nil { | |
511 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
512 | return resp | |
513 | } | |
514 | ||
515 | protoReq := &proto.ReadDataSource_Request{ | |
516 | TypeName: r.TypeName, | |
517 | Config: &proto.DynamicValue{ | |
518 | Msgpack: config, | |
519 | }, | |
520 | } | |
521 | ||
522 | protoResp, err := p.client.ReadDataSource(p.ctx, protoReq) | |
523 | if err != nil { | |
524 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
525 | return resp | |
526 | } | |
527 | resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics)) | |
528 | ||
529 | state := cty.NullVal(dataSchema.Block.ImpliedType()) | |
530 | if protoResp.State != nil { | |
531 | state, err = msgpack.Unmarshal(protoResp.State.Msgpack, dataSchema.Block.ImpliedType()) | |
532 | if err != nil { | |
533 | resp.Diagnostics = resp.Diagnostics.Append(err) | |
534 | return resp | |
535 | } | |
536 | } | |
537 | resp.State = state | |
538 | ||
539 | return resp | |
540 | } | |
541 | ||
542 | // closing the grpc connection is final, and terraform will call it at the end of every phase. | |
543 | func (p *GRPCProvider) Close() error { | |
544 | log.Printf("[TRACE] GRPCProvider: Close") | |
545 | ||
546 | // Make sure to stop the server if we're not running within go-plugin. | |
547 | if p.TestServer != nil { | |
548 | p.TestServer.Stop() | |
549 | } | |
550 | ||
551 | // Check this since it's not automatically inserted during plugin creation. | |
552 | // It's currently only inserted by the command package, because that is | |
553 | // where the factory is built and is the only point with access to the | |
554 | // plugin.Client. | |
555 | if p.PluginClient == nil { | |
556 | log.Println("[DEBUG] provider has no plugin.Client") | |
557 | return nil | |
558 | } | |
559 | ||
560 | p.PluginClient.Kill() | |
561 | return nil | |
562 | } |