-
Notifications
You must be signed in to change notification settings - Fork 41
/
pluginHost.go
241 lines (203 loc) · 7.87 KB
/
pluginHost.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
// Copyright 2016-2022, Pulumi Corporation.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tfgen
import (
"encoding/json"
"fmt"
"sync"
"github.com/blang/semver"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
"github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin"
"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tf2pulumi/il"
"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tfbridge"
)
var _ = (plugin.Provider)((*inmemoryProvider)(nil))
type inmemoryProvider struct {
name tokens.Package
schema []byte
info tfbridge.ProviderInfo
}
func newInMemoryProvider(name tokens.Package, schema []byte, info tfbridge.ProviderInfo) *inmemoryProvider {
// Round-trip the info through a marshaler to normalize the types to the schema shim.
return &inmemoryProvider{
name: name,
schema: schema,
info: *tfbridge.MarshalProviderInfo(&info).Unmarshal(),
}
}
func (p *inmemoryProvider) Pkg() tokens.Package {
return p.name
}
func (p *inmemoryProvider) GetSchema(version int) ([]byte, error) {
return p.schema, nil
}
func (p *inmemoryProvider) GetMapping(key string) ([]byte, string, error) {
info := tfbridge.MarshalProviderInfo(&p.info)
mapping, err := json.Marshal(info)
if err != nil {
return nil, "", err
}
return mapping, p.info.Name, nil
}
func (p *inmemoryProvider) GetPluginInfo() (workspace.PluginInfo, error) {
var version *semver.Version
if p.info.Version != "" {
v, err := semver.ParseTolerant(p.info.Version)
if err != nil {
return workspace.PluginInfo{}, fmt.Errorf("failed to parse pkg %q version: %w", p.name, err)
}
version = &v
}
return workspace.PluginInfo{
Name: p.info.Name,
Kind: workspace.ResourcePlugin,
Version: version,
}, nil
}
func (p *inmemoryProvider) Call(tok tokens.ModuleMember, args resource.PropertyMap, info plugin.CallInfo,
options plugin.CallOptions) (plugin.CallResult, error) {
panic("unimplemented")
}
func (p *inmemoryProvider) CheckConfig(urn resource.URN, olds, news resource.PropertyMap,
allowUnknowns bool) (resource.PropertyMap, []plugin.CheckFailure, error) {
panic("unimplemented")
}
// DiffConfig checks what impacts a hypothetical change to this provider's configuration will have on the provider.
func (p *inmemoryProvider) DiffConfig(urn resource.URN, olds, news resource.PropertyMap, allowUnknowns bool,
ignoreChanges []string) (plugin.DiffResult, error) {
panic("unimplemented")
}
// Configure configures the resource provider with "globals" that control its behavior.
func (p *inmemoryProvider) Configure(inputs resource.PropertyMap) error {
panic("unimplemented")
}
func (p *inmemoryProvider) Check(urn resource.URN, olds, news resource.PropertyMap,
allowUnknowns bool, randomSeed []byte) (resource.PropertyMap, []plugin.CheckFailure, error) {
panic("unimplemented")
}
// Diff checks what impacts a hypothetical update will have on the resource's properties.
func (p *inmemoryProvider) Diff(urn resource.URN, id resource.ID, olds resource.PropertyMap, news resource.PropertyMap,
allowUnknowns bool, ignoreChanges []string) (plugin.DiffResult, error) {
panic("unimplemented")
}
// Create allocates a new instance of the provided resource and returns its unique resource.ID.
func (p *inmemoryProvider) Create(urn resource.URN, news resource.PropertyMap, timeout float64,
preview bool) (resource.ID, resource.PropertyMap, resource.Status, error) {
panic("unimplemented")
}
// Read the current live state associated with a resource. Enough state must be include in the inputs to uniquely
// identify the resource; this is typically just the resource ID, but may also include some properties. If the
// resource is missing (for instance, because it has been deleted), the resulting property map will be nil.
func (p *inmemoryProvider) Read(urn resource.URN, id resource.ID,
inputs, state resource.PropertyMap) (plugin.ReadResult, resource.Status, error) {
panic("unimplemented")
}
// Update updates an existing resource with new values.
func (p *inmemoryProvider) Update(urn resource.URN, id resource.ID,
olds resource.PropertyMap, news resource.PropertyMap, timeout float64, ignoreChanges []string,
preview bool) (resource.PropertyMap, resource.Status, error) {
panic("unimplemented")
}
// Delete tears down an existing resource.
func (p *inmemoryProvider) Delete(urn resource.URN, id resource.ID, props resource.PropertyMap,
timeout float64) (resource.Status, error) {
panic("unimplemented")
}
// Construct creates a new component resource.
func (p *inmemoryProvider) Construct(info plugin.ConstructInfo, typ tokens.Type, name tokens.QName,
parent resource.URN, inputs resource.PropertyMap, options plugin.ConstructOptions) (plugin.ConstructResult, error) {
panic("unimplemented")
}
// Invoke dynamically executes a built-in function in the provider.
func (p *inmemoryProvider) Invoke(tok tokens.ModuleMember, args resource.PropertyMap) (resource.PropertyMap,
[]plugin.CheckFailure, error) {
panic("unimplemented")
}
// StreamInvoke dynamically executes a built-in function in the provider, which returns a stream
// of responses.
func (p *inmemoryProvider) StreamInvoke(
tok tokens.ModuleMember,
args resource.PropertyMap,
onNext func(resource.PropertyMap) error) ([]plugin.CheckFailure, error) {
panic("unimplemented")
}
func (p *inmemoryProvider) Close() error {
return nil
}
func (p *inmemoryProvider) SignalCancellation() error {
return nil
}
type inmemoryProviderHost struct {
plugin.Host
il.ProviderInfoSource
provider *inmemoryProvider
}
func (host *inmemoryProviderHost) Provider(pkg tokens.Package, version *semver.Version) (plugin.Provider, error) {
if pkg == host.provider.Pkg() {
return host.provider, nil
}
return host.Host.Provider(pkg, version)
}
// ResolvePlugin resolves a plugin kind, name, and optional semver to a candidate plugin
// to load. inmemoryProviderHost does this by checking if the generating provider is being
// loaded. If it is, it returns it's provider. Otherwise, we defer
// inmemoryProviderHost.Host.
func (host *inmemoryProviderHost) ResolvePlugin(kind workspace.PluginKind, name string,
version *semver.Version) (*workspace.PluginInfo, error) {
if name == host.provider.name.String() {
info, err := host.provider.GetPluginInfo()
if err != nil {
return nil, err
}
return &info, nil
}
return host.Host.ResolvePlugin(kind, name, version)
}
func (host *inmemoryProviderHost) GetProviderInfo(
registryName, namespace, name, version string) (*tfbridge.ProviderInfo, error) {
if name == il.GetTerraformProviderName(host.provider.info) {
return &host.provider.info, nil
}
return host.ProviderInfoSource.GetProviderInfo(registryName, namespace, name, version)
}
type cachingProviderHost struct {
plugin.Host
m sync.RWMutex
cache map[string]plugin.Provider
}
func (host *cachingProviderHost) getProvider(key string) (plugin.Provider, bool) {
host.m.RLock()
defer host.m.RUnlock()
provider, ok := host.cache[key]
return provider, ok
}
func (host *cachingProviderHost) Provider(pkg tokens.Package, version *semver.Version) (plugin.Provider, error) {
key := pkg.String() + "@"
if version != nil {
key = version.String()
}
if provider, ok := host.getProvider(key); ok {
return provider, nil
}
host.m.Lock()
defer host.m.Unlock()
provider, err := host.Host.Provider(pkg, version)
if err != nil {
return nil, err
}
host.cache[key] = provider
return provider, nil
}