diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/plugin')
5 files changed, 250 insertions, 7 deletions
diff --git a/vendor/github.com/hashicorp/terraform/plugin/client.go b/vendor/github.com/hashicorp/terraform/plugin/client.go index 3a5cb7a..7e2f4fe 100644 --- a/vendor/github.com/hashicorp/terraform/plugin/client.go +++ b/vendor/github.com/hashicorp/terraform/plugin/client.go | |||
@@ -1,8 +1,10 @@ | |||
1 | package plugin | 1 | package plugin |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "os" | ||
4 | "os/exec" | 5 | "os/exec" |
5 | 6 | ||
7 | hclog "github.com/hashicorp/go-hclog" | ||
6 | plugin "github.com/hashicorp/go-plugin" | 8 | plugin "github.com/hashicorp/go-plugin" |
7 | "github.com/hashicorp/terraform/plugin/discovery" | 9 | "github.com/hashicorp/terraform/plugin/discovery" |
8 | ) | 10 | ) |
@@ -10,11 +12,18 @@ import ( | |||
10 | // ClientConfig returns a configuration object that can be used to instantiate | 12 | // ClientConfig returns a configuration object that can be used to instantiate |
11 | // a client for the plugin described by the given metadata. | 13 | // a client for the plugin described by the given metadata. |
12 | func ClientConfig(m discovery.PluginMeta) *plugin.ClientConfig { | 14 | func ClientConfig(m discovery.PluginMeta) *plugin.ClientConfig { |
15 | logger := hclog.New(&hclog.LoggerOptions{ | ||
16 | Name: "plugin", | ||
17 | Level: hclog.Trace, | ||
18 | Output: os.Stderr, | ||
19 | }) | ||
20 | |||
13 | return &plugin.ClientConfig{ | 21 | return &plugin.ClientConfig{ |
14 | Cmd: exec.Command(m.Path), | 22 | Cmd: exec.Command(m.Path), |
15 | HandshakeConfig: Handshake, | 23 | HandshakeConfig: Handshake, |
16 | Managed: true, | 24 | Managed: true, |
17 | Plugins: PluginMap, | 25 | Plugins: PluginMap, |
26 | Logger: logger, | ||
18 | } | 27 | } |
19 | } | 28 | } |
20 | 29 | ||
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/find.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/find.go index f5bc4c1..f053312 100644 --- a/vendor/github.com/hashicorp/terraform/plugin/discovery/find.go +++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/find.go | |||
@@ -3,6 +3,7 @@ package discovery | |||
3 | import ( | 3 | import ( |
4 | "io/ioutil" | 4 | "io/ioutil" |
5 | "log" | 5 | "log" |
6 | "os" | ||
6 | "path/filepath" | 7 | "path/filepath" |
7 | "strings" | 8 | "strings" |
8 | ) | 9 | ) |
@@ -59,7 +60,6 @@ func findPluginPaths(kind string, dirs []string) []string { | |||
59 | fullName := item.Name() | 60 | fullName := item.Name() |
60 | 61 | ||
61 | if !strings.HasPrefix(fullName, prefix) { | 62 | if !strings.HasPrefix(fullName, prefix) { |
62 | log.Printf("[DEBUG] skipping %q, not a %s", fullName, kind) | ||
63 | continue | 63 | continue |
64 | } | 64 | } |
65 | 65 | ||
@@ -71,6 +71,12 @@ func findPluginPaths(kind string, dirs []string) []string { | |||
71 | continue | 71 | continue |
72 | } | 72 | } |
73 | 73 | ||
74 | // Check that the file we found is usable | ||
75 | if !pathIsFile(absPath) { | ||
76 | log.Printf("[ERROR] ignoring non-file %s", absPath) | ||
77 | continue | ||
78 | } | ||
79 | |||
74 | log.Printf("[DEBUG] found %s %q", kind, fullName) | 80 | log.Printf("[DEBUG] found %s %q", kind, fullName) |
75 | ret = append(ret, filepath.Clean(absPath)) | 81 | ret = append(ret, filepath.Clean(absPath)) |
76 | continue | 82 | continue |
@@ -83,7 +89,13 @@ func findPluginPaths(kind string, dirs []string) []string { | |||
83 | continue | 89 | continue |
84 | } | 90 | } |
85 | 91 | ||
86 | log.Printf("[WARNING] found legacy %s %q", kind, fullName) | 92 | // Check that the file we found is usable |
93 | if !pathIsFile(absPath) { | ||
94 | log.Printf("[ERROR] ignoring non-file %s", absPath) | ||
95 | continue | ||
96 | } | ||
97 | |||
98 | log.Printf("[WARN] found legacy %s %q", kind, fullName) | ||
87 | 99 | ||
88 | ret = append(ret, filepath.Clean(absPath)) | 100 | ret = append(ret, filepath.Clean(absPath)) |
89 | } | 101 | } |
@@ -92,6 +104,17 @@ func findPluginPaths(kind string, dirs []string) []string { | |||
92 | return ret | 104 | return ret |
93 | } | 105 | } |
94 | 106 | ||
107 | // Returns true if and only if the given path refers to a file or a symlink | ||
108 | // to a file. | ||
109 | func pathIsFile(path string) bool { | ||
110 | info, err := os.Stat(path) | ||
111 | if err != nil { | ||
112 | return false | ||
113 | } | ||
114 | |||
115 | return !info.IsDir() | ||
116 | } | ||
117 | |||
95 | // ResolvePluginPaths takes a list of paths to plugin executables (as returned | 118 | // ResolvePluginPaths takes a list of paths to plugin executables (as returned |
96 | // by e.g. FindPluginPaths) and produces a PluginMetaSet describing the | 119 | // by e.g. FindPluginPaths) and produces a PluginMetaSet describing the |
97 | // referenced plugins. | 120 | // referenced plugins. |
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go index 241b5cb..815640f 100644 --- a/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go +++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go | |||
@@ -3,19 +3,22 @@ package discovery | |||
3 | import ( | 3 | import ( |
4 | "errors" | 4 | "errors" |
5 | "fmt" | 5 | "fmt" |
6 | "io" | ||
6 | "io/ioutil" | 7 | "io/ioutil" |
7 | "log" | 8 | "log" |
8 | "net/http" | 9 | "net/http" |
9 | "os" | 10 | "os" |
11 | "path/filepath" | ||
10 | "runtime" | 12 | "runtime" |
11 | "strconv" | 13 | "strconv" |
12 | "strings" | 14 | "strings" |
13 | 15 | ||
14 | "golang.org/x/net/html" | 16 | "golang.org/x/net/html" |
15 | 17 | ||
16 | cleanhttp "github.com/hashicorp/go-cleanhttp" | ||
17 | getter "github.com/hashicorp/go-getter" | 18 | getter "github.com/hashicorp/go-getter" |
18 | multierror "github.com/hashicorp/go-multierror" | 19 | multierror "github.com/hashicorp/go-multierror" |
20 | "github.com/hashicorp/terraform/httpclient" | ||
21 | "github.com/mitchellh/cli" | ||
19 | ) | 22 | ) |
20 | 23 | ||
21 | // Releases are located by parsing the html listing from releases.hashicorp.com. | 24 | // Releases are located by parsing the html listing from releases.hashicorp.com. |
@@ -30,7 +33,19 @@ const protocolVersionHeader = "x-terraform-protocol-version" | |||
30 | 33 | ||
31 | var releaseHost = "https://releases.hashicorp.com" | 34 | var releaseHost = "https://releases.hashicorp.com" |
32 | 35 | ||
33 | var httpClient = cleanhttp.DefaultClient() | 36 | var httpClient *http.Client |
37 | |||
38 | func init() { | ||
39 | httpClient = httpclient.New() | ||
40 | |||
41 | httpGetter := &getter.HttpGetter{ | ||
42 | Client: httpClient, | ||
43 | Netrc: true, | ||
44 | } | ||
45 | |||
46 | getter.Getters["http"] = httpGetter | ||
47 | getter.Getters["https"] = httpGetter | ||
48 | } | ||
34 | 49 | ||
35 | // An Installer maintains a local cache of plugins by downloading plugins | 50 | // An Installer maintains a local cache of plugins by downloading plugins |
36 | // from an online repository. | 51 | // from an online repository. |
@@ -47,6 +62,10 @@ type Installer interface { | |||
47 | type ProviderInstaller struct { | 62 | type ProviderInstaller struct { |
48 | Dir string | 63 | Dir string |
49 | 64 | ||
65 | // Cache is used to access and update a local cache of plugins if non-nil. | ||
66 | // Can be nil to disable caching. | ||
67 | Cache PluginCache | ||
68 | |||
50 | PluginProtocolVersion uint | 69 | PluginProtocolVersion uint |
51 | 70 | ||
52 | // OS and Arch specify the OS and architecture that should be used when | 71 | // OS and Arch specify the OS and architecture that should be used when |
@@ -58,6 +77,8 @@ type ProviderInstaller struct { | |||
58 | 77 | ||
59 | // Skip checksum and signature verification | 78 | // Skip checksum and signature verification |
60 | SkipVerify bool | 79 | SkipVerify bool |
80 | |||
81 | Ui cli.Ui // Ui for output | ||
61 | } | 82 | } |
62 | 83 | ||
63 | // Get is part of an implementation of type Installer, and attempts to download | 84 | // Get is part of an implementation of type Installer, and attempts to download |
@@ -98,6 +119,12 @@ func (i *ProviderInstaller) Get(provider string, req Constraints) (PluginMeta, e | |||
98 | // sort them newest to oldest | 119 | // sort them newest to oldest |
99 | Versions(versions).Sort() | 120 | Versions(versions).Sort() |
100 | 121 | ||
122 | // Ensure that our installation directory exists | ||
123 | err = os.MkdirAll(i.Dir, os.ModePerm) | ||
124 | if err != nil { | ||
125 | return PluginMeta{}, fmt.Errorf("failed to create plugin dir %s: %s", i.Dir, err) | ||
126 | } | ||
127 | |||
101 | // take the first matching plugin we find | 128 | // take the first matching plugin we find |
102 | for _, v := range versions { | 129 | for _, v := range versions { |
103 | url := i.providerURL(provider, v.String()) | 130 | url := i.providerURL(provider, v.String()) |
@@ -116,8 +143,9 @@ func (i *ProviderInstaller) Get(provider string, req Constraints) (PluginMeta, e | |||
116 | 143 | ||
117 | log.Printf("[DEBUG] fetching provider info for %s version %s", provider, v) | 144 | log.Printf("[DEBUG] fetching provider info for %s version %s", provider, v) |
118 | if checkPlugin(url, i.PluginProtocolVersion) { | 145 | if checkPlugin(url, i.PluginProtocolVersion) { |
119 | log.Printf("[DEBUG] getting provider %q version %q at %s", provider, v, url) | 146 | i.Ui.Info(fmt.Sprintf("- Downloading plugin for provider %q (%s)...", provider, v.String())) |
120 | err := getter.Get(i.Dir, url) | 147 | log.Printf("[DEBUG] getting provider %q version %q", provider, v) |
148 | err := i.install(provider, v, url) | ||
121 | if err != nil { | 149 | if err != nil { |
122 | return PluginMeta{}, err | 150 | return PluginMeta{}, err |
123 | } | 151 | } |
@@ -164,6 +192,98 @@ func (i *ProviderInstaller) Get(provider string, req Constraints) (PluginMeta, e | |||
164 | return PluginMeta{}, ErrorNoVersionCompatible | 192 | return PluginMeta{}, ErrorNoVersionCompatible |
165 | } | 193 | } |
166 | 194 | ||
195 | func (i *ProviderInstaller) install(provider string, version Version, url string) error { | ||
196 | if i.Cache != nil { | ||
197 | log.Printf("[DEBUG] looking for provider %s %s in plugin cache", provider, version) | ||
198 | cached := i.Cache.CachedPluginPath("provider", provider, version) | ||
199 | if cached == "" { | ||
200 | log.Printf("[DEBUG] %s %s not yet in cache, so downloading %s", provider, version, url) | ||
201 | err := getter.Get(i.Cache.InstallDir(), url) | ||
202 | if err != nil { | ||
203 | return err | ||
204 | } | ||
205 | // should now be in cache | ||
206 | cached = i.Cache.CachedPluginPath("provider", provider, version) | ||
207 | if cached == "" { | ||
208 | // should never happen if the getter is behaving properly | ||
209 | // and the plugins are packaged properly. | ||
210 | return fmt.Errorf("failed to find downloaded plugin in cache %s", i.Cache.InstallDir()) | ||
211 | } | ||
212 | } | ||
213 | |||
214 | // Link or copy the cached binary into our install dir so the | ||
215 | // normal resolution machinery can find it. | ||
216 | filename := filepath.Base(cached) | ||
217 | targetPath := filepath.Join(i.Dir, filename) | ||
218 | |||
219 | log.Printf("[DEBUG] installing %s %s to %s from local cache %s", provider, version, targetPath, cached) | ||
220 | |||
221 | // Delete if we can. If there's nothing there already then no harm done. | ||
222 | // This is important because we can't create a link if there's | ||
223 | // already a file of the same name present. | ||
224 | // (any other error here we'll catch below when we try to write here) | ||
225 | os.Remove(targetPath) | ||
226 | |||
227 | // We don't attempt linking on Windows because links are not | ||
228 | // comprehensively supported by all tools/apps in Windows and | ||
229 | // so we choose to be conservative to avoid creating any | ||
230 | // weird issues for Windows users. | ||
231 | linkErr := errors.New("link not supported for Windows") // placeholder error, never actually returned | ||
232 | if runtime.GOOS != "windows" { | ||
233 | // Try hard linking first. Hard links are preferable because this | ||
234 | // creates a self-contained directory that doesn't depend on the | ||
235 | // cache after install. | ||
236 | linkErr = os.Link(cached, targetPath) | ||
237 | |||
238 | // If that failed, try a symlink. This _does_ depend on the cache | ||
239 | // after install, so the user must manage the cache more carefully | ||
240 | // in this case, but avoids creating redundant copies of the | ||
241 | // plugins on disk. | ||
242 | if linkErr != nil { | ||
243 | linkErr = os.Symlink(cached, targetPath) | ||
244 | } | ||
245 | } | ||
246 | |||
247 | // If we still have an error then we'll try a copy as a fallback. | ||
248 | // In this case either the OS is Windows or the target filesystem | ||
249 | // can't support symlinks. | ||
250 | if linkErr != nil { | ||
251 | srcFile, err := os.Open(cached) | ||
252 | if err != nil { | ||
253 | return fmt.Errorf("failed to open cached plugin %s: %s", cached, err) | ||
254 | } | ||
255 | defer srcFile.Close() | ||
256 | |||
257 | destFile, err := os.OpenFile(targetPath, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, os.ModePerm) | ||
258 | if err != nil { | ||
259 | return fmt.Errorf("failed to create %s: %s", targetPath, err) | ||
260 | } | ||
261 | |||
262 | _, err = io.Copy(destFile, srcFile) | ||
263 | if err != nil { | ||
264 | destFile.Close() | ||
265 | return fmt.Errorf("failed to copy cached plugin from %s to %s: %s", cached, targetPath, err) | ||
266 | } | ||
267 | |||
268 | err = destFile.Close() | ||
269 | if err != nil { | ||
270 | return fmt.Errorf("error creating %s: %s", targetPath, err) | ||
271 | } | ||
272 | } | ||
273 | |||
274 | // One way or another, by the time we get here we should have either | ||
275 | // a link or a copy of the cached plugin within i.Dir, as expected. | ||
276 | } else { | ||
277 | log.Printf("[DEBUG] plugin cache is disabled, so downloading %s %s from %s", provider, version, url) | ||
278 | err := getter.Get(i.Dir, url) | ||
279 | if err != nil { | ||
280 | return err | ||
281 | } | ||
282 | } | ||
283 | |||
284 | return nil | ||
285 | } | ||
286 | |||
167 | func (i *ProviderInstaller) PurgeUnused(used map[string]PluginMeta) (PluginMetaSet, error) { | 287 | func (i *ProviderInstaller) PurgeUnused(used map[string]PluginMeta) (PluginMetaSet, error) { |
168 | purge := make(PluginMetaSet) | 288 | purge := make(PluginMetaSet) |
169 | 289 | ||
@@ -261,7 +381,7 @@ func checkPlugin(url string, pluginProtocolVersion uint) bool { | |||
261 | if proto == "" { | 381 | if proto == "" { |
262 | // The header isn't present, but we don't make this error fatal since | 382 | // The header isn't present, but we don't make this error fatal since |
263 | // the latest version will probably work. | 383 | // the latest version will probably work. |
264 | log.Printf("[WARNING] missing %s from: %s", protocolVersionHeader, url) | 384 | log.Printf("[WARN] missing %s from: %s", protocolVersionHeader, url) |
265 | return true | 385 | return true |
266 | } | 386 | } |
267 | 387 | ||
@@ -422,3 +542,7 @@ func getFile(url string) ([]byte, error) { | |||
422 | } | 542 | } |
423 | return data, nil | 543 | return data, nil |
424 | } | 544 | } |
545 | |||
546 | func GetReleaseHost() string { | ||
547 | return releaseHost | ||
548 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/get_cache.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/get_cache.go new file mode 100644 index 0000000..1a10042 --- /dev/null +++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/get_cache.go | |||
@@ -0,0 +1,48 @@ | |||
1 | package discovery | ||
2 | |||
3 | // PluginCache is an interface implemented by objects that are able to maintain | ||
4 | // a cache of plugins. | ||
5 | type PluginCache interface { | ||
6 | // CachedPluginPath returns a path where the requested plugin is already | ||
7 | // cached, or an empty string if the requested plugin is not yet cached. | ||
8 | CachedPluginPath(kind string, name string, version Version) string | ||
9 | |||
10 | // InstallDir returns the directory that new plugins should be installed into | ||
11 | // in order to populate the cache. This directory should be used as the | ||
12 | // first argument to getter.Get when downloading plugins with go-getter. | ||
13 | // | ||
14 | // After installing into this directory, use CachedPluginPath to obtain the | ||
15 | // path where the plugin was installed. | ||
16 | InstallDir() string | ||
17 | } | ||
18 | |||
19 | // NewLocalPluginCache returns a PluginCache that caches plugins in a | ||
20 | // given local directory. | ||
21 | func NewLocalPluginCache(dir string) PluginCache { | ||
22 | return &pluginCache{ | ||
23 | Dir: dir, | ||
24 | } | ||
25 | } | ||
26 | |||
27 | type pluginCache struct { | ||
28 | Dir string | ||
29 | } | ||
30 | |||
31 | func (c *pluginCache) CachedPluginPath(kind string, name string, version Version) string { | ||
32 | allPlugins := FindPlugins(kind, []string{c.Dir}) | ||
33 | plugins := allPlugins.WithName(name).WithVersion(version) | ||
34 | |||
35 | if plugins.Count() == 0 { | ||
36 | // nothing cached | ||
37 | return "" | ||
38 | } | ||
39 | |||
40 | // There should generally be only one plugin here; if there's more than | ||
41 | // one match for some reason then we'll just choose one arbitrarily. | ||
42 | plugin := plugins.Newest() | ||
43 | return plugin.Path | ||
44 | } | ||
45 | |||
46 | func (c *pluginCache) InstallDir() string { | ||
47 | return c.Dir | ||
48 | } | ||
diff --git a/vendor/github.com/hashicorp/terraform/plugin/resource_provider.go b/vendor/github.com/hashicorp/terraform/plugin/resource_provider.go index 473f786..d6a433c 100644 --- a/vendor/github.com/hashicorp/terraform/plugin/resource_provider.go +++ b/vendor/github.com/hashicorp/terraform/plugin/resource_provider.go | |||
@@ -41,6 +41,24 @@ func (p *ResourceProvider) Stop() error { | |||
41 | return err | 41 | return err |
42 | } | 42 | } |
43 | 43 | ||
44 | func (p *ResourceProvider) GetSchema(req *terraform.ProviderSchemaRequest) (*terraform.ProviderSchema, error) { | ||
45 | var result ResourceProviderGetSchemaResponse | ||
46 | args := &ResourceProviderGetSchemaArgs{ | ||
47 | Req: req, | ||
48 | } | ||
49 | |||
50 | err := p.Client.Call("Plugin.GetSchema", args, &result) | ||
51 | if err != nil { | ||
52 | return nil, err | ||
53 | } | ||
54 | |||
55 | if result.Error != nil { | ||
56 | err = result.Error | ||
57 | } | ||
58 | |||
59 | return result.Schema, err | ||
60 | } | ||
61 | |||
44 | func (p *ResourceProvider) Input( | 62 | func (p *ResourceProvider) Input( |
45 | input terraform.UIInput, | 63 | input terraform.UIInput, |
46 | c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) { | 64 | c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) { |
@@ -312,6 +330,15 @@ type ResourceProviderStopResponse struct { | |||
312 | Error *plugin.BasicError | 330 | Error *plugin.BasicError |
313 | } | 331 | } |
314 | 332 | ||
333 | type ResourceProviderGetSchemaArgs struct { | ||
334 | Req *terraform.ProviderSchemaRequest | ||
335 | } | ||
336 | |||
337 | type ResourceProviderGetSchemaResponse struct { | ||
338 | Schema *terraform.ProviderSchema | ||
339 | Error *plugin.BasicError | ||
340 | } | ||
341 | |||
315 | type ResourceProviderConfigureResponse struct { | 342 | type ResourceProviderConfigureResponse struct { |
316 | Error *plugin.BasicError | 343 | Error *plugin.BasicError |
317 | } | 344 | } |
@@ -418,6 +445,18 @@ func (s *ResourceProviderServer) Stop( | |||
418 | return nil | 445 | return nil |
419 | } | 446 | } |
420 | 447 | ||
448 | func (s *ResourceProviderServer) GetSchema( | ||
449 | args *ResourceProviderGetSchemaArgs, | ||
450 | result *ResourceProviderGetSchemaResponse, | ||
451 | ) error { | ||
452 | schema, err := s.Provider.GetSchema(args.Req) | ||
453 | result.Schema = schema | ||
454 | if err != nil { | ||
455 | result.Error = plugin.NewBasicError(err) | ||
456 | } | ||
457 | return nil | ||
458 | } | ||
459 | |||
421 | func (s *ResourceProviderServer) Input( | 460 | func (s *ResourceProviderServer) Input( |
422 | args *ResourceProviderInputArgs, | 461 | args *ResourceProviderInputArgs, |
423 | reply *ResourceProviderInputResponse) error { | 462 | reply *ResourceProviderInputResponse) error { |