diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/plugin/grpc_provisioner.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/plugin/grpc_provisioner.go | 178 |
1 files changed, 178 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/plugin/grpc_provisioner.go b/vendor/github.com/hashicorp/terraform/plugin/grpc_provisioner.go new file mode 100644 index 0000000..136c88d --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/plugin/grpc_provisioner.go | |||
@@ -0,0 +1,178 @@ | |||
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 | } | ||