-
Notifications
You must be signed in to change notification settings - Fork 9.5k
/
provisioner.go
119 lines (98 loc) · 3.5 KB
/
provisioner.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
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package grpcwrap
import (
"context"
"log"
"strings"
"unicode/utf8"
"github.com/hashicorp/terraform/internal/communicator/shared"
"github.com/hashicorp/terraform/internal/configs/configschema"
"github.com/hashicorp/terraform/internal/plugin/convert"
"github.com/hashicorp/terraform/internal/provisioners"
"github.com/hashicorp/terraform/internal/tfplugin5"
)
// New wraps a provisioners.Interface to implement a grpc ProviderServer.
// This is useful for creating a test binary out of an internal provider
// implementation.
func Provisioner(p provisioners.Interface) tfplugin5.ProvisionerServer {
return &provisioner{
provisioner: p,
schema: p.GetSchema().Provisioner,
}
}
type provisioner struct {
provisioner provisioners.Interface
schema *configschema.Block
}
func (p *provisioner) GetSchema(_ context.Context, req *tfplugin5.GetProvisionerSchema_Request) (*tfplugin5.GetProvisionerSchema_Response, error) {
resp := &tfplugin5.GetProvisionerSchema_Response{}
resp.Provisioner = &tfplugin5.Schema{
Block: &tfplugin5.Schema_Block{},
}
if p.schema != nil {
resp.Provisioner.Block = convert.ConfigSchemaToProto(p.schema)
}
return resp, nil
}
func (p *provisioner) ValidateProvisionerConfig(_ context.Context, req *tfplugin5.ValidateProvisionerConfig_Request) (*tfplugin5.ValidateProvisionerConfig_Response, error) {
resp := &tfplugin5.ValidateProvisionerConfig_Response{}
ty := p.schema.ImpliedType()
configVal, err := decodeDynamicValue(req.Config, ty)
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil
}
validateResp := p.provisioner.ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{
Config: configVal,
})
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, validateResp.Diagnostics)
return resp, nil
}
func (p *provisioner) ProvisionResource(req *tfplugin5.ProvisionResource_Request, srv tfplugin5.Provisioner_ProvisionResourceServer) error {
// We send back a diagnostics over the stream if there was a
// provisioner-side problem.
srvResp := &tfplugin5.ProvisionResource_Response{}
ty := p.schema.ImpliedType()
configVal, err := decodeDynamicValue(req.Config, ty)
if err != nil {
srvResp.Diagnostics = convert.AppendProtoDiag(srvResp.Diagnostics, err)
srv.Send(srvResp)
return nil
}
connVal, err := decodeDynamicValue(req.Connection, shared.ConnectionBlockSupersetSchema.ImpliedType())
if err != nil {
srvResp.Diagnostics = convert.AppendProtoDiag(srvResp.Diagnostics, err)
srv.Send(srvResp)
return nil
}
resp := p.provisioner.ProvisionResource(provisioners.ProvisionResourceRequest{
Config: configVal,
Connection: connVal,
UIOutput: uiOutput{srv},
})
srvResp.Diagnostics = convert.AppendProtoDiag(srvResp.Diagnostics, resp.Diagnostics)
srv.Send(srvResp)
return nil
}
func (p *provisioner) Stop(context.Context, *tfplugin5.Stop_Request) (*tfplugin5.Stop_Response, error) {
resp := &tfplugin5.Stop_Response{}
err := p.provisioner.Stop()
if err != nil {
resp.Error = err.Error()
}
return resp, nil
}
// uiOutput implements the terraform.UIOutput interface to adapt the grpc
// stream to the legacy Provisioner.Apply method.
type uiOutput struct {
srv tfplugin5.Provisioner_ProvisionResourceServer
}
func (o uiOutput) Output(s string) {
err := o.srv.Send(&tfplugin5.ProvisionResource_Response{
Output: strings.ToValidUTF8(s, string(utf8.RuneError)),
})
if err != nil {
log.Printf("[ERROR] %s", err)
}
}