]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/plugin/grpc_provisioner.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / plugin / grpc_provisioner.go
1 package plugin
2
3 import (
4 "context"
5 "errors"
6 "io"
7 "log"
8 "sync"
9
10 plugin "github.com/hashicorp/go-plugin"
11 "github.com/hashicorp/terraform/configs/configschema"
12 proto "github.com/hashicorp/terraform/internal/tfplugin5"
13 "github.com/hashicorp/terraform/plugin/convert"
14 "github.com/hashicorp/terraform/provisioners"
15 "github.com/zclconf/go-cty/cty"
16 "github.com/zclconf/go-cty/cty/msgpack"
17 "google.golang.org/grpc"
18 )
19
20 // GRPCProvisionerPlugin is the plugin.GRPCPlugin implementation.
21 type GRPCProvisionerPlugin struct {
22 plugin.Plugin
23 GRPCProvisioner func() proto.ProvisionerServer
24 }
25
26 func (p *GRPCProvisionerPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
27 return &GRPCProvisioner{
28 client: proto.NewProvisionerClient(c),
29 ctx: ctx,
30 }, nil
31 }
32
33 func (p *GRPCProvisionerPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
34 proto.RegisterProvisionerServer(s, p.GRPCProvisioner())
35 return nil
36 }
37
38 // provisioners.Interface grpc implementation
39 type GRPCProvisioner struct {
40 // PluginClient provides a reference to the plugin.Client which controls the plugin process.
41 // This allows the GRPCProvider a way to shutdown the plugin process.
42 PluginClient *plugin.Client
43
44 client proto.ProvisionerClient
45 ctx context.Context
46
47 // Cache the schema since we need it for serialization in each method call.
48 mu sync.Mutex
49 schema *configschema.Block
50 }
51
52 func (p *GRPCProvisioner) GetSchema() (resp provisioners.GetSchemaResponse) {
53 p.mu.Lock()
54 defer p.mu.Unlock()
55
56 if p.schema != nil {
57 return provisioners.GetSchemaResponse{
58 Provisioner: p.schema,
59 }
60 }
61
62 protoResp, err := p.client.GetSchema(p.ctx, new(proto.GetProvisionerSchema_Request))
63 if err != nil {
64 resp.Diagnostics = resp.Diagnostics.Append(err)
65 return resp
66 }
67 resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
68
69 if protoResp.Provisioner == nil {
70 resp.Diagnostics = resp.Diagnostics.Append(errors.New("missing provisioner schema"))
71 return resp
72 }
73
74 resp.Provisioner = convert.ProtoToConfigSchema(protoResp.Provisioner.Block)
75
76 p.schema = resp.Provisioner
77
78 return resp
79 }
80
81 func (p *GRPCProvisioner) ValidateProvisionerConfig(r provisioners.ValidateProvisionerConfigRequest) (resp provisioners.ValidateProvisionerConfigResponse) {
82 schema := p.GetSchema()
83 if schema.Diagnostics.HasErrors() {
84 resp.Diagnostics = resp.Diagnostics.Append(schema.Diagnostics)
85 return resp
86 }
87
88 mp, err := msgpack.Marshal(r.Config, schema.Provisioner.ImpliedType())
89 if err != nil {
90 resp.Diagnostics = resp.Diagnostics.Append(err)
91 return resp
92 }
93
94 protoReq := &proto.ValidateProvisionerConfig_Request{
95 Config: &proto.DynamicValue{Msgpack: mp},
96 }
97 protoResp, err := p.client.ValidateProvisionerConfig(p.ctx, protoReq)
98 if err != nil {
99 resp.Diagnostics = resp.Diagnostics.Append(err)
100 return resp
101 }
102 resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
103 return resp
104 }
105
106 func (p *GRPCProvisioner) ProvisionResource(r provisioners.ProvisionResourceRequest) (resp provisioners.ProvisionResourceResponse) {
107 schema := p.GetSchema()
108 if schema.Diagnostics.HasErrors() {
109 resp.Diagnostics = resp.Diagnostics.Append(schema.Diagnostics)
110 return resp
111 }
112
113 mp, err := msgpack.Marshal(r.Config, schema.Provisioner.ImpliedType())
114 if err != nil {
115 resp.Diagnostics = resp.Diagnostics.Append(err)
116 return resp
117 }
118
119 // connection is always assumed to be a simple string map
120 connMP, err := msgpack.Marshal(r.Connection, cty.Map(cty.String))
121 if err != nil {
122 resp.Diagnostics = resp.Diagnostics.Append(err)
123 return resp
124 }
125
126 protoReq := &proto.ProvisionResource_Request{
127 Config: &proto.DynamicValue{Msgpack: mp},
128 Connection: &proto.DynamicValue{Msgpack: connMP},
129 }
130
131 outputClient, err := p.client.ProvisionResource(p.ctx, protoReq)
132 if err != nil {
133 resp.Diagnostics = resp.Diagnostics.Append(err)
134 return resp
135 }
136
137 for {
138 rcv, err := outputClient.Recv()
139 if rcv != nil {
140 r.UIOutput.Output(rcv.Output)
141 }
142 if err != nil {
143 if err != io.EOF {
144 resp.Diagnostics = resp.Diagnostics.Append(err)
145 }
146 break
147 }
148
149 if len(rcv.Diagnostics) > 0 {
150 resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(rcv.Diagnostics))
151 break
152 }
153 }
154
155 return resp
156 }
157
158 func (p *GRPCProvisioner) Stop() error {
159 protoResp, err := p.client.Stop(p.ctx, &proto.Stop_Request{})
160 if err != nil {
161 return err
162 }
163 if protoResp.Error != "" {
164 return errors.New(protoResp.Error)
165 }
166 return nil
167 }
168
169 func (p *GRPCProvisioner) Close() error {
170 // check this since it's not automatically inserted during plugin creation
171 if p.PluginClient == nil {
172 log.Println("[DEBUG] provider has no plugin.Client")
173 return nil
174 }
175
176 p.PluginClient.Kill()
177 return nil
178 }