aboutsummaryrefslogtreecommitdiffhomepage
path: root/vendor/github.com/hashicorp/terraform/plugin
diff options
context:
space:
mode:
authorNathan Dench <ndenc2@gmail.com>2019-05-24 15:16:44 +1000
committerNathan Dench <ndenc2@gmail.com>2019-05-24 15:16:44 +1000
commit107c1cdb09c575aa2f61d97f48d8587eb6bada4c (patch)
treeca7d008643efc555c388baeaf1d986e0b6b3e28c /vendor/github.com/hashicorp/terraform/plugin
parent844b5a68d8af4791755b8f0ad293cc99f5959183 (diff)
downloadterraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.gz
terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.tar.zst
terraform-provider-statuscake-107c1cdb09c575aa2f61d97f48d8587eb6bada4c.zip
Upgrade to 0.12
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/plugin')
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/client.go12
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/convert/diagnostics.go132
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/convert/schema.go154
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/error.go34
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/get.go607
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/hashicorp.go34
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/meta_set.go2
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/requirements.go6
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/signature.go42
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/version.go5
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/discovery/version_set.go5
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/grpc_provider.go562
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/grpc_provisioner.go178
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/plugin.go9
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/resource_provider.go7
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/resource_provisioner.go13
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/serve.go87
-rw-r--r--vendor/github.com/hashicorp/terraform/plugin/ui_input.go7
18 files changed, 1598 insertions, 298 deletions
diff --git a/vendor/github.com/hashicorp/terraform/plugin/client.go b/vendor/github.com/hashicorp/terraform/plugin/client.go
index 7e2f4fe..0eab538 100644
--- a/vendor/github.com/hashicorp/terraform/plugin/client.go
+++ b/vendor/github.com/hashicorp/terraform/plugin/client.go
@@ -19,11 +19,13 @@ func ClientConfig(m discovery.PluginMeta) *plugin.ClientConfig {
19 }) 19 })
20 20
21 return &plugin.ClientConfig{ 21 return &plugin.ClientConfig{
22 Cmd: exec.Command(m.Path), 22 Cmd: exec.Command(m.Path),
23 HandshakeConfig: Handshake, 23 HandshakeConfig: Handshake,
24 Managed: true, 24 VersionedPlugins: VersionedPlugins,
25 Plugins: PluginMap, 25 Managed: true,
26 Logger: logger, 26 Logger: logger,
27 AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
28 AutoMTLS: true,
27 } 29 }
28} 30}
29 31
diff --git a/vendor/github.com/hashicorp/terraform/plugin/convert/diagnostics.go b/vendor/github.com/hashicorp/terraform/plugin/convert/diagnostics.go
new file mode 100644
index 0000000..51cb2fe
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/plugin/convert/diagnostics.go
@@ -0,0 +1,132 @@
1package convert
2
3import (
4 proto "github.com/hashicorp/terraform/internal/tfplugin5"
5 "github.com/hashicorp/terraform/tfdiags"
6 "github.com/zclconf/go-cty/cty"
7)
8
9// WarnsAndErrorsToProto converts the warnings and errors return by the legacy
10// provider to protobuf diagnostics.
11func WarnsAndErrsToProto(warns []string, errs []error) (diags []*proto.Diagnostic) {
12 for _, w := range warns {
13 diags = AppendProtoDiag(diags, w)
14 }
15
16 for _, e := range errs {
17 diags = AppendProtoDiag(diags, e)
18 }
19
20 return diags
21}
22
23// AppendProtoDiag appends a new diagnostic from a warning string or an error.
24// This panics if d is not a string or error.
25func AppendProtoDiag(diags []*proto.Diagnostic, d interface{}) []*proto.Diagnostic {
26 switch d := d.(type) {
27 case cty.PathError:
28 ap := PathToAttributePath(d.Path)
29 diags = append(diags, &proto.Diagnostic{
30 Severity: proto.Diagnostic_ERROR,
31 Summary: d.Error(),
32 Attribute: ap,
33 })
34 case error:
35 diags = append(diags, &proto.Diagnostic{
36 Severity: proto.Diagnostic_ERROR,
37 Summary: d.Error(),
38 })
39 case string:
40 diags = append(diags, &proto.Diagnostic{
41 Severity: proto.Diagnostic_WARNING,
42 Summary: d,
43 })
44 case *proto.Diagnostic:
45 diags = append(diags, d)
46 case []*proto.Diagnostic:
47 diags = append(diags, d...)
48 }
49 return diags
50}
51
52// ProtoToDiagnostics converts a list of proto.Diagnostics to a tf.Diagnostics.
53func ProtoToDiagnostics(ds []*proto.Diagnostic) tfdiags.Diagnostics {
54 var diags tfdiags.Diagnostics
55 for _, d := range ds {
56 var severity tfdiags.Severity
57
58 switch d.Severity {
59 case proto.Diagnostic_ERROR:
60 severity = tfdiags.Error
61 case proto.Diagnostic_WARNING:
62 severity = tfdiags.Warning
63 }
64
65 var newDiag tfdiags.Diagnostic
66
67 // if there's an attribute path, we need to create a AttributeValue diagnostic
68 if d.Attribute != nil {
69 path := AttributePathToPath(d.Attribute)
70 newDiag = tfdiags.AttributeValue(severity, d.Summary, d.Detail, path)
71 } else {
72 newDiag = tfdiags.WholeContainingBody(severity, d.Summary, d.Detail)
73 }
74
75 diags = diags.Append(newDiag)
76 }
77
78 return diags
79}
80
81// AttributePathToPath takes the proto encoded path and converts it to a cty.Path
82func AttributePathToPath(ap *proto.AttributePath) cty.Path {
83 var p cty.Path
84 for _, step := range ap.Steps {
85 switch selector := step.Selector.(type) {
86 case *proto.AttributePath_Step_AttributeName:
87 p = p.GetAttr(selector.AttributeName)
88 case *proto.AttributePath_Step_ElementKeyString:
89 p = p.Index(cty.StringVal(selector.ElementKeyString))
90 case *proto.AttributePath_Step_ElementKeyInt:
91 p = p.Index(cty.NumberIntVal(selector.ElementKeyInt))
92 }
93 }
94 return p
95}
96
97// AttributePathToPath takes a cty.Path and converts it to a proto-encoded path.
98func PathToAttributePath(p cty.Path) *proto.AttributePath {
99 ap := &proto.AttributePath{}
100 for _, step := range p {
101 switch selector := step.(type) {
102 case cty.GetAttrStep:
103 ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
104 Selector: &proto.AttributePath_Step_AttributeName{
105 AttributeName: selector.Name,
106 },
107 })
108 case cty.IndexStep:
109 key := selector.Key
110 switch key.Type() {
111 case cty.String:
112 ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
113 Selector: &proto.AttributePath_Step_ElementKeyString{
114 ElementKeyString: key.AsString(),
115 },
116 })
117 case cty.Number:
118 v, _ := key.AsBigFloat().Int64()
119 ap.Steps = append(ap.Steps, &proto.AttributePath_Step{
120 Selector: &proto.AttributePath_Step_ElementKeyInt{
121 ElementKeyInt: v,
122 },
123 })
124 default:
125 // We'll bail early if we encounter anything else, and just
126 // return the valid prefix.
127 return ap
128 }
129 }
130 }
131 return ap
132}
diff --git a/vendor/github.com/hashicorp/terraform/plugin/convert/schema.go b/vendor/github.com/hashicorp/terraform/plugin/convert/schema.go
new file mode 100644
index 0000000..6a45f54
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/plugin/convert/schema.go
@@ -0,0 +1,154 @@
1package convert
2
3import (
4 "encoding/json"
5 "reflect"
6 "sort"
7
8 "github.com/hashicorp/terraform/configs/configschema"
9 proto "github.com/hashicorp/terraform/internal/tfplugin5"
10 "github.com/hashicorp/terraform/providers"
11)
12
13// ConfigSchemaToProto takes a *configschema.Block and converts it to a
14// proto.Schema_Block for a grpc response.
15func ConfigSchemaToProto(b *configschema.Block) *proto.Schema_Block {
16 block := &proto.Schema_Block{}
17
18 for _, name := range sortedKeys(b.Attributes) {
19 a := b.Attributes[name]
20 attr := &proto.Schema_Attribute{
21 Name: name,
22 Description: a.Description,
23 Optional: a.Optional,
24 Computed: a.Computed,
25 Required: a.Required,
26 Sensitive: a.Sensitive,
27 }
28
29 ty, err := json.Marshal(a.Type)
30 if err != nil {
31 panic(err)
32 }
33
34 attr.Type = ty
35
36 block.Attributes = append(block.Attributes, attr)
37 }
38
39 for _, name := range sortedKeys(b.BlockTypes) {
40 b := b.BlockTypes[name]
41 block.BlockTypes = append(block.BlockTypes, protoSchemaNestedBlock(name, b))
42 }
43
44 return block
45}
46
47func protoSchemaNestedBlock(name string, b *configschema.NestedBlock) *proto.Schema_NestedBlock {
48 var nesting proto.Schema_NestedBlock_NestingMode
49 switch b.Nesting {
50 case configschema.NestingSingle:
51 nesting = proto.Schema_NestedBlock_SINGLE
52 case configschema.NestingGroup:
53 nesting = proto.Schema_NestedBlock_GROUP
54 case configschema.NestingList:
55 nesting = proto.Schema_NestedBlock_LIST
56 case configschema.NestingSet:
57 nesting = proto.Schema_NestedBlock_SET
58 case configschema.NestingMap:
59 nesting = proto.Schema_NestedBlock_MAP
60 default:
61 nesting = proto.Schema_NestedBlock_INVALID
62 }
63 return &proto.Schema_NestedBlock{
64 TypeName: name,
65 Block: ConfigSchemaToProto(&b.Block),
66 Nesting: nesting,
67 MinItems: int64(b.MinItems),
68 MaxItems: int64(b.MaxItems),
69 }
70}
71
72// ProtoToProviderSchema takes a proto.Schema and converts it to a providers.Schema.
73func ProtoToProviderSchema(s *proto.Schema) providers.Schema {
74 return providers.Schema{
75 Version: s.Version,
76 Block: ProtoToConfigSchema(s.Block),
77 }
78}
79
80// ProtoToConfigSchema takes the GetSchcema_Block from a grpc response and converts it
81// to a terraform *configschema.Block.
82func ProtoToConfigSchema(b *proto.Schema_Block) *configschema.Block {
83 block := &configschema.Block{
84 Attributes: make(map[string]*configschema.Attribute),
85 BlockTypes: make(map[string]*configschema.NestedBlock),
86 }
87
88 for _, a := range b.Attributes {
89 attr := &configschema.Attribute{
90 Description: a.Description,
91 Required: a.Required,
92 Optional: a.Optional,
93 Computed: a.Computed,
94 Sensitive: a.Sensitive,
95 }
96
97 if err := json.Unmarshal(a.Type, &attr.Type); err != nil {
98 panic(err)
99 }
100
101 block.Attributes[a.Name] = attr
102 }
103
104 for _, b := range b.BlockTypes {
105 block.BlockTypes[b.TypeName] = schemaNestedBlock(b)
106 }
107
108 return block
109}
110
111func schemaNestedBlock(b *proto.Schema_NestedBlock) *configschema.NestedBlock {
112 var nesting configschema.NestingMode
113 switch b.Nesting {
114 case proto.Schema_NestedBlock_SINGLE:
115 nesting = configschema.NestingSingle
116 case proto.Schema_NestedBlock_GROUP:
117 nesting = configschema.NestingGroup
118 case proto.Schema_NestedBlock_LIST:
119 nesting = configschema.NestingList
120 case proto.Schema_NestedBlock_MAP:
121 nesting = configschema.NestingMap
122 case proto.Schema_NestedBlock_SET:
123 nesting = configschema.NestingSet
124 default:
125 // In all other cases we'll leave it as the zero value (invalid) and
126 // let the caller validate it and deal with this.
127 }
128
129 nb := &configschema.NestedBlock{
130 Nesting: nesting,
131 MinItems: int(b.MinItems),
132 MaxItems: int(b.MaxItems),
133 }
134
135 nested := ProtoToConfigSchema(b.Block)
136 nb.Block = *nested
137 return nb
138}
139
140// sortedKeys returns the lexically sorted keys from the given map. This is
141// used to make schema conversions are deterministic. This panics if map keys
142// are not a string.
143func sortedKeys(m interface{}) []string {
144 v := reflect.ValueOf(m)
145 keys := make([]string, v.Len())
146
147 mapKeys := v.MapKeys()
148 for i, k := range mapKeys {
149 keys[i] = k.Interface().(string)
150 }
151
152 sort.Strings(keys)
153 return keys
154}
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/error.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/error.go
index df855a7..729e970 100644
--- a/vendor/github.com/hashicorp/terraform/plugin/discovery/error.go
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/error.go
@@ -22,9 +22,43 @@ const ErrorNoSuitableVersion = Error("no suitable version is available")
22// version of Terraform. 22// version of Terraform.
23const ErrorNoVersionCompatible = Error("no available version is compatible with this version of Terraform") 23const ErrorNoVersionCompatible = Error("no available version is compatible with this version of Terraform")
24 24
25// ErrorVersionIncompatible indicates that all of the versions within the
26// constraints are not compatible with the current version of Terrafrom, though
27// there does exist a version outside of the constaints that is compatible.
28const ErrorVersionIncompatible = Error("incompatible provider version")
29
25// ErrorNoSuchProvider indicates that no provider exists with a name given 30// ErrorNoSuchProvider indicates that no provider exists with a name given
26const ErrorNoSuchProvider = Error("no provider exists with the given name") 31const ErrorNoSuchProvider = Error("no provider exists with the given name")
27 32
33// ErrorNoVersionCompatibleWithPlatform indicates that all of the available
34// versions that otherwise met constraints are not compatible with the
35// requested platform
36const ErrorNoVersionCompatibleWithPlatform = Error("no available version is compatible for the requested platform")
37
38// ErrorMissingChecksumVerification indicates that either the provider
39// distribution is missing the SHA256SUMS file or the checksum file does
40// not contain a checksum for the binary plugin
41const ErrorMissingChecksumVerification = Error("unable to verify checksum")
42
43// ErrorChecksumVerification indicates that the current checksum of the
44// provider plugin has changed since the initial release and is not trusted
45// to download
46const ErrorChecksumVerification = Error("unexpected plugin checksum")
47
48// ErrorSignatureVerification indicates that the digital signature for a
49// provider distribution could not be verified for one of the following
50// reasons: missing signature file, missing public key, or the signature
51// was not signed by any known key for the publisher
52const ErrorSignatureVerification = Error("unable to verify signature")
53
54// ErrorServiceUnreachable indicates that the network was unable to connect
55// to the registry service
56const ErrorServiceUnreachable = Error("registry service is unreachable")
57
58// ErrorPublicRegistryUnreachable indicates that the network was unable to connect
59// to the public registry in particular, so we can show a link to the statuspage
60const ErrorPublicRegistryUnreachable = Error("registry service is unreachable, check https://status.hashicorp.com/ for status updates")
61
28func (err Error) Error() string { 62func (err Error) Error() string {
29 return string(err) 63 return string(err)
30} 64}
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go
index 815640f..b1d01fb 100644
--- a/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/get.go
@@ -13,28 +13,27 @@ import (
13 "strconv" 13 "strconv"
14 "strings" 14 "strings"
15 15
16 "golang.org/x/net/html" 16 "github.com/hashicorp/errwrap"
17
18 getter "github.com/hashicorp/go-getter" 17 getter "github.com/hashicorp/go-getter"
19 multierror "github.com/hashicorp/go-multierror" 18 multierror "github.com/hashicorp/go-multierror"
20 "github.com/hashicorp/terraform/httpclient" 19 "github.com/hashicorp/terraform/httpclient"
20 "github.com/hashicorp/terraform/registry"
21 "github.com/hashicorp/terraform/registry/regsrc"
22 "github.com/hashicorp/terraform/registry/response"
23 "github.com/hashicorp/terraform/svchost/disco"
24 "github.com/hashicorp/terraform/tfdiags"
25 tfversion "github.com/hashicorp/terraform/version"
21 "github.com/mitchellh/cli" 26 "github.com/mitchellh/cli"
22) 27)
23 28
24// Releases are located by parsing the html listing from releases.hashicorp.com. 29// Releases are located by querying the terraform registry.
25//
26// The URL for releases follows the pattern:
27// https://releases.hashicorp.com/terraform-provider-name/<x.y.z>/terraform-provider-name_<x.y.z>_<os>_<arch>.<ext>
28//
29// The plugin protocol version will be saved with the release and returned in
30// the header X-TERRAFORM_PROTOCOL_VERSION.
31 30
32const protocolVersionHeader = "x-terraform-protocol-version" 31const protocolVersionHeader = "x-terraform-protocol-version"
33 32
34var releaseHost = "https://releases.hashicorp.com"
35
36var httpClient *http.Client 33var httpClient *http.Client
37 34
35var errVersionNotFound = errors.New("version not found")
36
38func init() { 37func init() {
39 httpClient = httpclient.New() 38 httpClient = httpclient.New()
40 39
@@ -50,7 +49,7 @@ func init() {
50// An Installer maintains a local cache of plugins by downloading plugins 49// An Installer maintains a local cache of plugins by downloading plugins
51// from an online repository. 50// from an online repository.
52type Installer interface { 51type Installer interface {
53 Get(name string, req Constraints) (PluginMeta, error) 52 Get(name string, req Constraints) (PluginMeta, tfdiags.Diagnostics, error)
54 PurgeUnused(used map[string]PluginMeta) (removed PluginMetaSet, err error) 53 PurgeUnused(used map[string]PluginMeta) (removed PluginMetaSet, err error)
55} 54}
56 55
@@ -79,6 +78,13 @@ type ProviderInstaller struct {
79 SkipVerify bool 78 SkipVerify bool
80 79
81 Ui cli.Ui // Ui for output 80 Ui cli.Ui // Ui for output
81
82 // Services is a required *disco.Disco, which may have services and
83 // credentials pre-loaded.
84 Services *disco.Disco
85
86 // registry client
87 registry *registry.Client
82} 88}
83 89
84// Get is part of an implementation of type Installer, and attempts to download 90// Get is part of an implementation of type Installer, and attempts to download
@@ -100,96 +106,170 @@ type ProviderInstaller struct {
100// are produced under the assumption that if presented to the user they will 106// are produced under the assumption that if presented to the user they will
101// be presented alongside context about what is being installed, and thus the 107// be presented alongside context about what is being installed, and thus the
102// error messages do not redundantly include such information. 108// error messages do not redundantly include such information.
103func (i *ProviderInstaller) Get(provider string, req Constraints) (PluginMeta, error) { 109func (i *ProviderInstaller) Get(provider string, req Constraints) (PluginMeta, tfdiags.Diagnostics, error) {
104 versions, err := i.listProviderVersions(provider) 110 var diags tfdiags.Diagnostics
111
112 // a little bit of initialization.
113 if i.OS == "" {
114 i.OS = runtime.GOOS
115 }
116 if i.Arch == "" {
117 i.Arch = runtime.GOARCH
118 }
119 if i.registry == nil {
120 i.registry = registry.NewClient(i.Services, nil)
121 }
122
123 // get a full listing of versions for the requested provider
124 allVersions, err := i.listProviderVersions(provider)
125
105 // TODO: return multiple errors 126 // TODO: return multiple errors
106 if err != nil { 127 if err != nil {
107 return PluginMeta{}, err 128 log.Printf("[DEBUG] %s", err)
129 if registry.IsServiceUnreachable(err) {
130 registryHost, err := i.hostname()
131 if err == nil && registryHost == regsrc.PublicRegistryHost.Raw {
132 return PluginMeta{}, diags, ErrorPublicRegistryUnreachable
133 }
134 return PluginMeta{}, diags, ErrorServiceUnreachable
135 }
136 if registry.IsServiceNotProvided(err) {
137 return PluginMeta{}, diags, err
138 }
139 return PluginMeta{}, diags, ErrorNoSuchProvider
108 } 140 }
109 141
110 if len(versions) == 0 { 142 // Add any warnings from the response to diags
111 return PluginMeta{}, ErrorNoSuitableVersion 143 for _, warning := range allVersions.Warnings {
144 hostname, err := i.hostname()
145 if err != nil {
146 return PluginMeta{}, diags, err
147 }
148 diag := tfdiags.SimpleWarning(fmt.Sprintf("%s: %s", hostname, warning))
149 diags = diags.Append(diag)
112 } 150 }
113 151
114 versions = allowedVersions(versions, req) 152 if len(allVersions.Versions) == 0 {
153 return PluginMeta{}, diags, ErrorNoSuitableVersion
154 }
155 providerSource := allVersions.ID
156
157 // Filter the list of plugin versions to those which meet the version constraints
158 versions := allowedVersions(allVersions, req)
115 if len(versions) == 0 { 159 if len(versions) == 0 {
116 return PluginMeta{}, ErrorNoSuitableVersion 160 return PluginMeta{}, diags, ErrorNoSuitableVersion
117 } 161 }
118 162
119 // sort them newest to oldest 163 // sort them newest to oldest. The newest version wins!
120 Versions(versions).Sort() 164 response.ProviderVersionCollection(versions).Sort()
121 165
122 // Ensure that our installation directory exists 166 // if the chosen provider version does not support the requested platform,
123 err = os.MkdirAll(i.Dir, os.ModePerm) 167 // filter the list of acceptable versions to those that support that platform
124 if err != nil { 168 if err := i.checkPlatformCompatibility(versions[0]); err != nil {
125 return PluginMeta{}, fmt.Errorf("failed to create plugin dir %s: %s", i.Dir, err) 169 versions = i.platformCompatibleVersions(versions)
170 if len(versions) == 0 {
171 return PluginMeta{}, diags, ErrorNoVersionCompatibleWithPlatform
172 }
126 } 173 }
127 174
128 // take the first matching plugin we find 175 // we now have a winning platform-compatible version
129 for _, v := range versions { 176 versionMeta := versions[0]
130 url := i.providerURL(provider, v.String()) 177 v := VersionStr(versionMeta.Version).MustParse()
131 178
132 if !i.SkipVerify { 179 // check protocol compatibility
133 sha256, err := i.getProviderChecksum(provider, v.String()) 180 if err := i.checkPluginProtocol(versionMeta); err != nil {
134 if err != nil { 181 closestMatch, err := i.findClosestProtocolCompatibleVersion(allVersions.Versions)
135 return PluginMeta{}, err 182 if err != nil {
136 } 183 // No operation here if we can't find a version with compatible protocol
184 return PluginMeta{}, diags, err
185 }
137 186
138 // add the checksum parameter for go-getter to verify the download for us. 187 // Prompt version suggestion to UI based on closest protocol match
139 if sha256 != "" { 188 var errMsg string
140 url = url + "?checksum=sha256:" + sha256 189 closestVersion := VersionStr(closestMatch.Version).MustParse()
141 } 190 if v.NewerThan(closestVersion) {
191 errMsg = providerProtocolTooNew
192 } else {
193 errMsg = providerProtocolTooOld
142 } 194 }
143 195
144 log.Printf("[DEBUG] fetching provider info for %s version %s", provider, v) 196 constraintStr := req.String()
145 if checkPlugin(url, i.PluginProtocolVersion) { 197 if constraintStr == "" {
146 i.Ui.Info(fmt.Sprintf("- Downloading plugin for provider %q (%s)...", provider, v.String())) 198 constraintStr = "(any version)"
147 log.Printf("[DEBUG] getting provider %q version %q", provider, v) 199 }
148 err := i.install(provider, v, url)
149 if err != nil {
150 return PluginMeta{}, err
151 }
152 200
153 // Find what we just installed 201 return PluginMeta{}, diags, errwrap.Wrap(ErrorVersionIncompatible, fmt.Errorf(fmt.Sprintf(
154 // (This is weird, because go-getter doesn't directly return 202 errMsg, provider, v.String(), tfversion.String(),
155 // information about what was extracted, and we just extracted 203 closestVersion.String(), closestVersion.MinorUpgradeConstraintStr(), constraintStr)))
156 // the archive directly into a shared dir here.) 204 }
157 log.Printf("[DEBUG] looking for the %s %s plugin we just installed", provider, v)
158 metas := FindPlugins("provider", []string{i.Dir})
159 log.Printf("[DEBUG] all plugins found %#v", metas)
160 metas, _ = metas.ValidateVersions()
161 metas = metas.WithName(provider).WithVersion(v)
162 log.Printf("[DEBUG] filtered plugins %#v", metas)
163 if metas.Count() == 0 {
164 // This should never happen. Suggests that the release archive
165 // contains an executable file whose name doesn't match the
166 // expected convention.
167 return PluginMeta{}, fmt.Errorf(
168 "failed to find installed plugin version %s; this is a bug in Terraform and should be reported",
169 v,
170 )
171 }
172 205
173 if metas.Count() > 1 { 206 downloadURLs, err := i.listProviderDownloadURLs(providerSource, versionMeta.Version)
174 // This should also never happen, and suggests that a 207 providerURL := downloadURLs.DownloadURL
175 // particular version was re-released with a different 208
176 // executable filename. We consider releases as immutable, so 209 if !i.SkipVerify {
177 // this is an error. 210 // Terraform verifies the integrity of a provider release before downloading
178 return PluginMeta{}, fmt.Errorf( 211 // the plugin binary. The digital signature (SHA256SUMS.sig) on the
179 "multiple plugins installed for version %s; this is a bug in Terraform and should be reported", 212 // release distribution (SHA256SUMS) is verified with the public key of the
180 v, 213 // publisher provided in the Terraform Registry response, ensuring that
181 ) 214 // everything is as intended by the publisher. The checksum of the provider
182 } 215 // plugin is expected in the SHA256SUMS file and is double checked to match
216 // the checksum of the original published release to the Registry. This
217 // enforces immutability of releases between the Registry and the plugin's
218 // host location. Lastly, the integrity of the binary is verified upon
219 // download matches the Registry and signed checksum.
220 sha256, err := i.getProviderChecksum(downloadURLs)
221 if err != nil {
222 return PluginMeta{}, diags, err
223 }
183 224
184 // By now we know we have exactly one meta, and so "Newest" will 225 // add the checksum parameter for go-getter to verify the download for us.
185 // return that one. 226 if sha256 != "" {
186 return metas.Newest(), nil 227 providerURL = providerURL + "?checksum=sha256:" + sha256
187 } 228 }
229 }
230
231 printedProviderName := fmt.Sprintf("%q (%s)", provider, providerSource)
232 i.Ui.Info(fmt.Sprintf("- Downloading plugin for provider %s %s...", printedProviderName, versionMeta.Version))
233 log.Printf("[DEBUG] getting provider %s version %q", printedProviderName, versionMeta.Version)
234 err = i.install(provider, v, providerURL)
235 if err != nil {
236 return PluginMeta{}, diags, err
237 }
238
239 // Find what we just installed
240 // (This is weird, because go-getter doesn't directly return
241 // information about what was extracted, and we just extracted
242 // the archive directly into a shared dir here.)
243 log.Printf("[DEBUG] looking for the %s %s plugin we just installed", provider, versionMeta.Version)
244 metas := FindPlugins("provider", []string{i.Dir})
245 log.Printf("[DEBUG] all plugins found %#v", metas)
246 metas, _ = metas.ValidateVersions()
247 metas = metas.WithName(provider).WithVersion(v)
248 log.Printf("[DEBUG] filtered plugins %#v", metas)
249 if metas.Count() == 0 {
250 // This should never happen. Suggests that the release archive
251 // contains an executable file whose name doesn't match the
252 // expected convention.
253 return PluginMeta{}, diags, fmt.Errorf(
254 "failed to find installed plugin version %s; this is a bug in Terraform and should be reported",
255 versionMeta.Version,
256 )
257 }
188 258
189 log.Printf("[INFO] incompatible ProtocolVersion for %s version %s", provider, v) 259 if metas.Count() > 1 {
260 // This should also never happen, and suggests that a
261 // particular version was re-released with a different
262 // executable filename. We consider releases as immutable, so
263 // this is an error.
264 return PluginMeta{}, diags, fmt.Errorf(
265 "multiple plugins installed for version %s; this is a bug in Terraform and should be reported",
266 versionMeta.Version,
267 )
190 } 268 }
191 269
192 return PluginMeta{}, ErrorNoVersionCompatible 270 // By now we know we have exactly one meta, and so "Newest" will
271 // return that one.
272 return metas.Newest(), diags, nil
193} 273}
194 274
195func (i *ProviderInstaller) install(provider string, version Version, url string) error { 275func (i *ProviderInstaller) install(provider string, version Version, url string) error {
@@ -215,6 +295,14 @@ func (i *ProviderInstaller) install(provider string, version Version, url string
215 // normal resolution machinery can find it. 295 // normal resolution machinery can find it.
216 filename := filepath.Base(cached) 296 filename := filepath.Base(cached)
217 targetPath := filepath.Join(i.Dir, filename) 297 targetPath := filepath.Join(i.Dir, filename)
298 // check if the target dir exists, and create it if not
299 var err error
300 if _, StatErr := os.Stat(i.Dir); os.IsNotExist(StatErr) {
301 err = os.MkdirAll(i.Dir, 0700)
302 }
303 if err != nil {
304 return err
305 }
218 306
219 log.Printf("[DEBUG] installing %s %s to %s from local cache %s", provider, version, targetPath, cached) 307 log.Printf("[DEBUG] installing %s %s to %s from local cache %s", provider, version, targetPath, cached)
220 308
@@ -280,7 +368,6 @@ func (i *ProviderInstaller) install(provider string, version Version, url string
280 return err 368 return err
281 } 369 }
282 } 370 }
283
284 return nil 371 return nil
285} 372}
286 373
@@ -316,182 +403,222 @@ func (i *ProviderInstaller) PurgeUnused(used map[string]PluginMeta) (PluginMetaS
316 return removed, errs 403 return removed, errs
317} 404}
318 405
319// Plugins are referred to by the short name, but all URLs and files will use 406func (i *ProviderInstaller) getProviderChecksum(resp *response.TerraformProviderPlatformLocation) (string, error) {
320// the full name prefixed with terraform-<plugin_type>- 407 // Get SHA256SUMS file.
321func (i *ProviderInstaller) providerName(name string) string { 408 shasums, err := getFile(resp.ShasumsURL)
322 return "terraform-provider-" + name 409 if err != nil {
323} 410 log.Printf("[ERROR] error fetching checksums from %q: %s", resp.ShasumsURL, err)
411 return "", ErrorMissingChecksumVerification
412 }
324 413
325func (i *ProviderInstaller) providerFileName(name, version string) string { 414 // Get SHA256SUMS.sig file.
326 os := i.OS 415 signature, err := getFile(resp.ShasumsSignatureURL)
327 arch := i.Arch 416 if err != nil {
328 if os == "" { 417 log.Printf("[ERROR] error fetching checksums signature from %q: %s", resp.ShasumsSignatureURL, err)
329 os = runtime.GOOS 418 return "", ErrorSignatureVerification
330 } 419 }
331 if arch == "" { 420
332 arch = runtime.GOARCH 421 // Verify the GPG signature returned from the Registry.
422 asciiArmor := resp.SigningKeys.GPGASCIIArmor()
423 signer, err := verifySig(shasums, signature, asciiArmor)
424 if err != nil {
425 log.Printf("[ERROR] error verifying signature: %s", err)
426 return "", ErrorSignatureVerification
333 } 427 }
334 return fmt.Sprintf("%s_%s_%s_%s.zip", i.providerName(name), version, os, arch)
335}
336 428
337// providerVersionsURL returns the path to the released versions directory for the provider: 429 // Also verify the GPG signature against the HashiCorp public key. This is
338// https://releases.hashicorp.com/terraform-provider-name/ 430 // a temporary additional check until a more robust key verification
339func (i *ProviderInstaller) providerVersionsURL(name string) string { 431 // process is added in a future release.
340 return releaseHost + "/" + i.providerName(name) + "/" 432 _, err = verifySig(shasums, signature, HashicorpPublicKey)
341} 433 if err != nil {
434 log.Printf("[ERROR] error verifying signature against HashiCorp public key: %s", err)
435 return "", ErrorSignatureVerification
436 }
342 437
343// providerURL returns the full path to the provider file, using the current OS 438 // Display identity for GPG key which succeeded verifying the signature.
344// and ARCH: 439 // This could also be used to display to the user with i.Ui.Info().
345// .../terraform-provider-name_<x.y.z>/terraform-provider-name_<x.y.z>_<os>_<arch>.<ext> 440 identities := []string{}
346func (i *ProviderInstaller) providerURL(name, version string) string { 441 for k := range signer.Identities {
347 return fmt.Sprintf("%s%s/%s", i.providerVersionsURL(name), version, i.providerFileName(name, version)) 442 identities = append(identities, k)
348} 443 }
444 identity := strings.Join(identities, ", ")
445 log.Printf("[DEBUG] verified GPG signature with key from %s", identity)
446
447 // Extract checksum for this os/arch platform binary and verify against Registry
448 checksum := checksumForFile(shasums, resp.Filename)
449 if checksum == "" {
450 log.Printf("[ERROR] missing checksum for %s from source %s", resp.Filename, resp.ShasumsURL)
451 return "", ErrorMissingChecksumVerification
452 } else if checksum != resp.Shasum {
453 log.Printf("[ERROR] unexpected checksum for %s from source %q", resp.Filename, resp.ShasumsURL)
454 return "", ErrorChecksumVerification
455 }
349 456
350func (i *ProviderInstaller) providerChecksumURL(name, version string) string { 457 return checksum, nil
351 fileName := fmt.Sprintf("%s_%s_SHA256SUMS", i.providerName(name), version)
352 u := fmt.Sprintf("%s%s/%s", i.providerVersionsURL(name), version, fileName)
353 return u
354} 458}
355 459
356func (i *ProviderInstaller) getProviderChecksum(name, version string) (string, error) { 460func (i *ProviderInstaller) hostname() (string, error) {
357 checksums, err := getPluginSHA256SUMs(i.providerChecksumURL(name, version)) 461 provider := regsrc.NewTerraformProvider("", i.OS, i.Arch)
462 svchost, err := provider.SvcHost()
358 if err != nil { 463 if err != nil {
359 return "", err 464 return "", err
360 } 465 }
361 466
362 return checksumForFile(checksums, i.providerFileName(name, version)), nil 467 return svchost.ForDisplay(), nil
363} 468}
364 469
365// Return the plugin version by making a HEAD request to the provided url. 470// list all versions available for the named provider
366// If the header is not present, we assume the latest version will be 471func (i *ProviderInstaller) listProviderVersions(name string) (*response.TerraformProviderVersions, error) {
367// compatible, and leave the check for discovery or execution. 472 provider := regsrc.NewTerraformProvider(name, i.OS, i.Arch)
368func checkPlugin(url string, pluginProtocolVersion uint) bool { 473 versions, err := i.registry.TerraformProviderVersions(provider)
369 resp, err := httpClient.Head(url) 474 return versions, err
370 if err != nil { 475}
371 log.Printf("[ERROR] error fetching plugin headers: %s", err)
372 return false
373 }
374 476
375 if resp.StatusCode != http.StatusOK { 477func (i *ProviderInstaller) listProviderDownloadURLs(name, version string) (*response.TerraformProviderPlatformLocation, error) {
376 log.Println("[ERROR] non-200 status fetching plugin headers:", resp.Status) 478 urls, err := i.registry.TerraformProviderLocation(regsrc.NewTerraformProvider(name, i.OS, i.Arch), version)
377 return false 479 if urls == nil {
480 return nil, fmt.Errorf("No download urls found for provider %s", name)
378 } 481 }
482 return urls, err
483}
484
485// findClosestProtocolCompatibleVersion searches for the provider version with the closest protocol match.
486// Prerelease versions are filtered.
487func (i *ProviderInstaller) findClosestProtocolCompatibleVersion(versions []*response.TerraformProviderVersion) (*response.TerraformProviderVersion, error) {
488 // Loop through all the provider versions to find the earliest and latest
489 // versions that match the installer protocol to then select the closest of the two
490 var latest, earliest *response.TerraformProviderVersion
491 for _, version := range versions {
492 // Prereleases are filtered and will not be suggested
493 v, err := VersionStr(version.Version).Parse()
494 if err != nil || v.IsPrerelease() {
495 continue
496 }
379 497
380 proto := resp.Header.Get(protocolVersionHeader) 498 if err := i.checkPluginProtocol(version); err == nil {
381 if proto == "" { 499 if earliest == nil {
382 // The header isn't present, but we don't make this error fatal since 500 // Found the first provider version with compatible protocol
383 // the latest version will probably work. 501 earliest = version
384 log.Printf("[WARN] missing %s from: %s", protocolVersionHeader, url) 502 }
385 return true 503 // Update the latest protocol compatible version
504 latest = version
505 }
506 }
507 if earliest == nil {
508 // No compatible protocol was found for any version
509 return nil, ErrorNoVersionCompatible
386 } 510 }
387 511
388 protoVersion, err := strconv.Atoi(proto) 512 // Convert protocols to comparable types
513 protoString := strconv.Itoa(int(i.PluginProtocolVersion))
514 protocolVersion, err := VersionStr(protoString).Parse()
389 if err != nil { 515 if err != nil {
390 log.Printf("[ERROR] invalid ProtocolVersion: %s", proto) 516 return nil, fmt.Errorf("invalid plugin protocol version: %q", i.PluginProtocolVersion)
391 return false
392 } 517 }
393 518
394 return protoVersion == int(pluginProtocolVersion) 519 earliestVersionProtocol, err := VersionStr(earliest.Protocols[0]).Parse()
395}
396
397// list the version available for the named plugin
398func (i *ProviderInstaller) listProviderVersions(name string) ([]Version, error) {
399 versions, err := listPluginVersions(i.providerVersionsURL(name))
400 if err != nil { 520 if err != nil {
401 // listPluginVersions returns a verbose error message indicating
402 // what was being accessed and what failed
403 return nil, err 521 return nil, err
404 } 522 }
405 return versions, nil
406}
407
408var errVersionNotFound = errors.New("version not found")
409 523
410// take the list of available versions for a plugin, and filter out those that 524 // Compare installer protocol version with the first protocol listed of the earliest match
411// don't fit the constraints. 525 // [A, B] where A is assumed the earliest compatible major version of the protocol pair
412func allowedVersions(available []Version, required Constraints) []Version { 526 if protocolVersion.NewerThan(earliestVersionProtocol) {
413 var allowed []Version 527 // Provider protocols are too old, the closest version is the earliest compatible version
414 528 return earliest, nil
415 for _, v := range available {
416 if required.Allows(v) {
417 allowed = append(allowed, v)
418 }
419 } 529 }
420 530
421 return allowed 531 // Provider protocols are too new, the closest version is the latest compatible version
532 return latest, nil
422} 533}
423 534
424// return a list of the plugin versions at the given URL 535func (i *ProviderInstaller) checkPluginProtocol(versionMeta *response.TerraformProviderVersion) error {
425func listPluginVersions(url string) ([]Version, error) { 536 // TODO: should this be a different error? We should probably differentiate between
426 resp, err := httpClient.Get(url) 537 // no compatible versions and no protocol versions listed at all
538 if len(versionMeta.Protocols) == 0 {
539 return fmt.Errorf("no plugin protocol versions listed")
540 }
541
542 protoString := strconv.Itoa(int(i.PluginProtocolVersion))
543 protocolVersion, err := VersionStr(protoString).Parse()
427 if err != nil { 544 if err != nil {
428 // http library produces a verbose error message that includes the 545 return fmt.Errorf("invalid plugin protocol version: %q", i.PluginProtocolVersion)
429 // URL being accessed, etc. 546 }
430 return nil, err 547 protocolConstraint, err := protocolVersion.MinorUpgradeConstraintStr().Parse()
548 if err != nil {
549 // This should not fail if the preceding function succeeded.
550 return fmt.Errorf("invalid plugin protocol version: %q", protocolVersion.String())
431 } 551 }
432 defer resp.Body.Close()
433 552
434 if resp.StatusCode != http.StatusOK { 553 for _, p := range versionMeta.Protocols {
435 body, _ := ioutil.ReadAll(resp.Body) 554 proPro, err := VersionStr(p).Parse()
436 log.Printf("[ERROR] failed to fetch plugin versions from %s\n%s\n%s", url, resp.Status, body) 555 if err != nil {
437 556 // invalid protocol reported by the registry. Move along.
438 switch resp.StatusCode { 557 log.Printf("[WARN] invalid provider protocol version %q found in the registry", versionMeta.Version)
439 case http.StatusNotFound, http.StatusForbidden: 558 continue
440 // These are treated as indicative of the given name not being 559 }
441 // a valid provider name at all. 560 // success!
442 return nil, ErrorNoSuchProvider 561 if protocolConstraint.Allows(proPro) {
443 562 return nil
444 default:
445 // All other errors are assumed to be operational problems.
446 return nil, fmt.Errorf("error accessing %s: %s", url, resp.Status)
447 } 563 }
448
449 } 564 }
450 565
451 body, err := html.Parse(resp.Body) 566 return ErrorNoVersionCompatible
452 if err != nil { 567}
453 log.Fatal(err) 568
569// REVIEWER QUESTION (again): this ends up swallowing a bunch of errors from
570// checkPluginProtocol. Do they need to be percolated up better, or would
571// debug messages would suffice in these situations?
572func (i *ProviderInstaller) findPlatformCompatibleVersion(versions []*response.TerraformProviderVersion) (*response.TerraformProviderVersion, error) {
573 for _, version := range versions {
574 if err := i.checkPlatformCompatibility(version); err == nil {
575 return version, nil
576 }
454 } 577 }
455 578
456 names := []string{} 579 return nil, ErrorNoVersionCompatibleWithPlatform
580}
457 581
458 // all we need to do is list links on the directory listing page that look like plugins 582// platformCompatibleVersions returns a list of provider versions that are
459 var f func(*html.Node) 583// compatible with the requested platform.
460 f = func(n *html.Node) { 584func (i *ProviderInstaller) platformCompatibleVersions(versions []*response.TerraformProviderVersion) []*response.TerraformProviderVersion {
461 if n.Type == html.ElementNode && n.Data == "a" { 585 var v []*response.TerraformProviderVersion
462 c := n.FirstChild 586 for _, version := range versions {
463 if c != nil && c.Type == html.TextNode && strings.HasPrefix(c.Data, "terraform-") { 587 if err := i.checkPlatformCompatibility(version); err == nil {
464 names = append(names, c.Data) 588 v = append(v, version)
465 return
466 }
467 }
468 for c := n.FirstChild; c != nil; c = c.NextSibling {
469 f(c)
470 } 589 }
471 } 590 }
472 f(body) 591 return v
592}
473 593
474 return versionsFromNames(names), nil 594func (i *ProviderInstaller) checkPlatformCompatibility(versionMeta *response.TerraformProviderVersion) error {
595 if len(versionMeta.Platforms) == 0 {
596 return fmt.Errorf("no supported provider platforms listed")
597 }
598 for _, p := range versionMeta.Platforms {
599 if p.Arch == i.Arch && p.OS == i.OS {
600 return nil
601 }
602 }
603 return fmt.Errorf("version %s does not support the requested platform %s_%s", versionMeta.Version, i.OS, i.Arch)
475} 604}
476 605
477// parse the list of directory names into a sorted list of available versions 606// take the list of available versions for a plugin, and filter out those that
478func versionsFromNames(names []string) []Version { 607// don't fit the constraints.
479 var versions []Version 608func allowedVersions(available *response.TerraformProviderVersions, required Constraints) []*response.TerraformProviderVersion {
480 for _, name := range names { 609 var allowed []*response.TerraformProviderVersion
481 parts := strings.SplitN(name, "_", 2)
482 if len(parts) == 2 && parts[1] != "" {
483 v, err := VersionStr(parts[1]).Parse()
484 if err != nil {
485 // filter invalid versions scraped from the page
486 log.Printf("[WARN] invalid version found for %q: %s", name, err)
487 continue
488 }
489 610
490 versions = append(versions, v) 611 for _, v := range available.Versions {
612 version, err := VersionStr(v.Version).Parse()
613 if err != nil {
614 log.Printf("[WARN] invalid version found for %q: %s", available.ID, err)
615 continue
616 }
617 if required.Allows(version) {
618 allowed = append(allowed, v)
491 } 619 }
492 } 620 }
493 621 return allowed
494 return versions
495} 622}
496 623
497func checksumForFile(sums []byte, name string) string { 624func checksumForFile(sums []byte, name string) string {
@@ -504,27 +631,6 @@ func checksumForFile(sums []byte, name string) string {
504 return "" 631 return ""
505} 632}
506 633
507// fetch the SHA256SUMS file provided, and verify its signature.
508func getPluginSHA256SUMs(sumsURL string) ([]byte, error) {
509 sigURL := sumsURL + ".sig"
510
511 sums, err := getFile(sumsURL)
512 if err != nil {
513 return nil, fmt.Errorf("error fetching checksums: %s", err)
514 }
515
516 sig, err := getFile(sigURL)
517 if err != nil {
518 return nil, fmt.Errorf("error fetching checksums signature: %s", err)
519 }
520
521 if err := verifySig(sums, sig); err != nil {
522 return nil, err
523 }
524
525 return sums, nil
526}
527
528func getFile(url string) ([]byte, error) { 634func getFile(url string) ([]byte, error) {
529 resp, err := httpClient.Get(url) 635 resp, err := httpClient.Get(url)
530 if err != nil { 636 if err != nil {
@@ -543,6 +649,41 @@ func getFile(url string) ([]byte, error) {
543 return data, nil 649 return data, nil
544} 650}
545 651
546func GetReleaseHost() string { 652// providerProtocolTooOld is a message sent to the CLI UI if the provider's
547 return releaseHost 653// supported protocol versions are too old for the user's version of terraform,
548} 654// but an older version of the provider is compatible.
655const providerProtocolTooOld = `
656[reset][bold][red]Provider %q v%s is not compatible with Terraform %s.[reset][red]
657
658Provider version %s is the earliest compatible version. Select it with
659the following version constraint:
660
661 version = %q
662
663Terraform checked all of the plugin versions matching the given constraint:
664 %s
665
666Consult the documentation for this provider for more information on
667compatibility between provider and Terraform versions.
668`
669
670// providerProtocolTooNew is a message sent to the CLI UI if the provider's
671// supported protocol versions are too new for the user's version of terraform,
672// and the user could either upgrade terraform or choose an older version of the
673// provider
674const providerProtocolTooNew = `
675[reset][bold][red]Provider %q v%s is not compatible with Terraform %s.[reset][red]
676
677Provider version %s is the latest compatible version. Select it with
678the following constraint:
679
680 version = %q
681
682Terraform checked all of the plugin versions matching the given constraint:
683 %s
684
685Consult the documentation for this provider for more information on
686compatibility between provider and Terraform versions.
687
688Alternatively, upgrade to the latest version of Terraform for compatibility with newer provider releases.
689`
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/hashicorp.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/hashicorp.go
new file mode 100644
index 0000000..4622ca0
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/hashicorp.go
@@ -0,0 +1,34 @@
1package discovery
2
3// HashicorpPublicKey is the HashiCorp public key, also available at
4// https://www.hashicorp.com/security
5const HashicorpPublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
6Version: GnuPG v1
7
8mQENBFMORM0BCADBRyKO1MhCirazOSVwcfTr1xUxjPvfxD3hjUwHtjsOy/bT6p9f
9W2mRPfwnq2JB5As+paL3UGDsSRDnK9KAxQb0NNF4+eVhr/EJ18s3wwXXDMjpIifq
10fIm2WyH3G+aRLTLPIpscUNKDyxFOUbsmgXAmJ46Re1fn8uKxKRHbfa39aeuEYWFA
113drdL1WoUngvED7f+RnKBK2G6ZEpO+LDovQk19xGjiMTtPJrjMjZJ3QXqPvx5wca
12KSZLr4lMTuoTI/ZXyZy5bD4tShiZz6KcyX27cD70q2iRcEZ0poLKHyEIDAi3TM5k
13SwbbWBFd5RNPOR0qzrb/0p9ksKK48IIfH2FvABEBAAG0K0hhc2hpQ29ycCBTZWN1
14cml0eSA8c2VjdXJpdHlAaGFzaGljb3JwLmNvbT6JATgEEwECACIFAlMORM0CGwMG
15CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEFGFLYc0j/xMyWIIAIPhcVqiQ59n
16Jc07gjUX0SWBJAxEG1lKxfzS4Xp+57h2xxTpdotGQ1fZwsihaIqow337YHQI3q0i
17SqV534Ms+j/tU7X8sq11xFJIeEVG8PASRCwmryUwghFKPlHETQ8jJ+Y8+1asRydi
18psP3B/5Mjhqv/uOK+Vy3zAyIpyDOMtIpOVfjSpCplVRdtSTFWBu9Em7j5I2HMn1w
19sJZnJgXKpybpibGiiTtmnFLOwibmprSu04rsnP4ncdC2XRD4wIjoyA+4PKgX3sCO
20klEzKryWYBmLkJOMDdo52LttP3279s7XrkLEE7ia0fXa2c12EQ0f0DQ1tGUvyVEW
21WmJVccm5bq25AQ0EUw5EzQEIANaPUY04/g7AmYkOMjaCZ6iTp9hB5Rsj/4ee/ln9
22wArzRO9+3eejLWh53FoN1rO+su7tiXJA5YAzVy6tuolrqjM8DBztPxdLBbEi4V+j
232tK0dATdBQBHEh3OJApO2UBtcjaZBT31zrG9K55D+CrcgIVEHAKY8Cb4kLBkb5wM
24skn+DrASKU0BNIV1qRsxfiUdQHZfSqtp004nrql1lbFMLFEuiY8FZrkkQ9qduixo
25mTT6f34/oiY+Jam3zCK7RDN/OjuWheIPGj/Qbx9JuNiwgX6yRj7OE1tjUx6d8g9y
260H1fmLJbb3WZZbuuGFnK6qrE3bGeY8+AWaJAZ37wpWh1p0cAEQEAAYkBHwQYAQIA
27CQUCUw5EzQIbDAAKCRBRhS2HNI/8TJntCAClU7TOO/X053eKF1jqNW4A1qpxctVc
28z8eTcY8Om5O4f6a/rfxfNFKn9Qyja/OG1xWNobETy7MiMXYjaa8uUx5iFy6kMVaP
290BXJ59NLZjMARGw6lVTYDTIvzqqqwLxgliSDfSnqUhubGwvykANPO+93BBx89MRG
30unNoYGXtPlhNFrAsB1VR8+EyKLv2HQtGCPSFBhrjuzH3gxGibNDDdFQLxxuJWepJ
31EK1UbTS4ms0NgZ2Uknqn1WRU1Ki7rE4sTy68iZtWpKQXZEJa0IGnuI2sSINGcXCJ
32oEIgXTMyCILo34Fa/C6VCm2WBgz9zZO8/rHIiQm1J5zqz0DrDwKBUM9C
33=LYpS
34-----END PGP PUBLIC KEY BLOCK-----`
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/meta_set.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/meta_set.go
index 181ea1f..3a99289 100644
--- a/vendor/github.com/hashicorp/terraform/plugin/discovery/meta_set.go
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/meta_set.go
@@ -63,7 +63,7 @@ func (s PluginMetaSet) WithName(name string) PluginMetaSet {
63// WithVersion returns the subset of metas that have the given version. 63// WithVersion returns the subset of metas that have the given version.
64// 64//
65// This should be used only with the "valid" result from ValidateVersions; 65// This should be used only with the "valid" result from ValidateVersions;
66// it will ignore any plugin metas that have a invalid version strings. 66// it will ignore any plugin metas that have invalid version strings.
67func (s PluginMetaSet) WithVersion(version Version) PluginMetaSet { 67func (s PluginMetaSet) WithVersion(version Version) PluginMetaSet {
68 ns := make(PluginMetaSet) 68 ns := make(PluginMetaSet)
69 for p := range s { 69 for p := range s {
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/requirements.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/requirements.go
index 75430fd..0466ab2 100644
--- a/vendor/github.com/hashicorp/terraform/plugin/discovery/requirements.go
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/requirements.go
@@ -4,6 +4,12 @@ import (
4 "bytes" 4 "bytes"
5) 5)
6 6
7// PluginInstallProtocolVersion is the protocol version TF-core
8// supports to communicate with servers, and is used to resolve
9// plugin discovery with terraform registry, in addition to
10// any specified plugin version constraints
11const PluginInstallProtocolVersion = 5
12
7// PluginRequirements describes a set of plugins (assumed to be of a consistent 13// PluginRequirements describes a set of plugins (assumed to be of a consistent
8// kind) that are required to exist and have versions within the given 14// kind) that are required to exist and have versions within the given
9// corresponding sets. 15// corresponding sets.
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/signature.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/signature.go
index b6686a5..7bbae50 100644
--- a/vendor/github.com/hashicorp/terraform/plugin/discovery/signature.go
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/signature.go
@@ -2,7 +2,6 @@ package discovery
2 2
3import ( 3import (
4 "bytes" 4 "bytes"
5 "log"
6 "strings" 5 "strings"
7 6
8 "golang.org/x/crypto/openpgp" 7 "golang.org/x/crypto/openpgp"
@@ -10,44 +9,11 @@ import (
10 9
11// Verify the data using the provided openpgp detached signature and the 10// Verify the data using the provided openpgp detached signature and the
12// embedded hashicorp public key. 11// embedded hashicorp public key.
13func verifySig(data, sig []byte) error { 12func verifySig(data, sig []byte, armor string) (*openpgp.Entity, error) {
14 el, err := openpgp.ReadArmoredKeyRing(strings.NewReader(hashiPublicKey)) 13 el, err := openpgp.ReadArmoredKeyRing(strings.NewReader(armor))
15 if err != nil { 14 if err != nil {
16 log.Fatal(err) 15 return nil, err
17 } 16 }
18 17
19 _, err = openpgp.CheckDetachedSignature(el, bytes.NewReader(data), bytes.NewReader(sig)) 18 return openpgp.CheckDetachedSignature(el, bytes.NewReader(data), bytes.NewReader(sig))
20 return err
21} 19}
22
23// this is the public key that signs the checksums file for releases.
24const hashiPublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK-----
25Version: GnuPG v1
26
27mQENBFMORM0BCADBRyKO1MhCirazOSVwcfTr1xUxjPvfxD3hjUwHtjsOy/bT6p9f
28W2mRPfwnq2JB5As+paL3UGDsSRDnK9KAxQb0NNF4+eVhr/EJ18s3wwXXDMjpIifq
29fIm2WyH3G+aRLTLPIpscUNKDyxFOUbsmgXAmJ46Re1fn8uKxKRHbfa39aeuEYWFA
303drdL1WoUngvED7f+RnKBK2G6ZEpO+LDovQk19xGjiMTtPJrjMjZJ3QXqPvx5wca
31KSZLr4lMTuoTI/ZXyZy5bD4tShiZz6KcyX27cD70q2iRcEZ0poLKHyEIDAi3TM5k
32SwbbWBFd5RNPOR0qzrb/0p9ksKK48IIfH2FvABEBAAG0K0hhc2hpQ29ycCBTZWN1
33cml0eSA8c2VjdXJpdHlAaGFzaGljb3JwLmNvbT6JATgEEwECACIFAlMORM0CGwMG
34CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEFGFLYc0j/xMyWIIAIPhcVqiQ59n
35Jc07gjUX0SWBJAxEG1lKxfzS4Xp+57h2xxTpdotGQ1fZwsihaIqow337YHQI3q0i
36SqV534Ms+j/tU7X8sq11xFJIeEVG8PASRCwmryUwghFKPlHETQ8jJ+Y8+1asRydi
37psP3B/5Mjhqv/uOK+Vy3zAyIpyDOMtIpOVfjSpCplVRdtSTFWBu9Em7j5I2HMn1w
38sJZnJgXKpybpibGiiTtmnFLOwibmprSu04rsnP4ncdC2XRD4wIjoyA+4PKgX3sCO
39klEzKryWYBmLkJOMDdo52LttP3279s7XrkLEE7ia0fXa2c12EQ0f0DQ1tGUvyVEW
40WmJVccm5bq25AQ0EUw5EzQEIANaPUY04/g7AmYkOMjaCZ6iTp9hB5Rsj/4ee/ln9
41wArzRO9+3eejLWh53FoN1rO+su7tiXJA5YAzVy6tuolrqjM8DBztPxdLBbEi4V+j
422tK0dATdBQBHEh3OJApO2UBtcjaZBT31zrG9K55D+CrcgIVEHAKY8Cb4kLBkb5wM
43skn+DrASKU0BNIV1qRsxfiUdQHZfSqtp004nrql1lbFMLFEuiY8FZrkkQ9qduixo
44mTT6f34/oiY+Jam3zCK7RDN/OjuWheIPGj/Qbx9JuNiwgX6yRj7OE1tjUx6d8g9y
450H1fmLJbb3WZZbuuGFnK6qrE3bGeY8+AWaJAZ37wpWh1p0cAEQEAAYkBHwQYAQIA
46CQUCUw5EzQIbDAAKCRBRhS2HNI/8TJntCAClU7TOO/X053eKF1jqNW4A1qpxctVc
47z8eTcY8Om5O4f6a/rfxfNFKn9Qyja/OG1xWNobETy7MiMXYjaa8uUx5iFy6kMVaP
480BXJ59NLZjMARGw6lVTYDTIvzqqqwLxgliSDfSnqUhubGwvykANPO+93BBx89MRG
49unNoYGXtPlhNFrAsB1VR8+EyKLv2HQtGCPSFBhrjuzH3gxGibNDDdFQLxxuJWepJ
50EK1UbTS4ms0NgZ2Uknqn1WRU1Ki7rE4sTy68iZtWpKQXZEJa0IGnuI2sSINGcXCJ
51oEIgXTMyCILo34Fa/C6VCm2WBgz9zZO8/rHIiQm1J5zqz0DrDwKBUM9C
52=LYpS
53-----END PGP PUBLIC KEY BLOCK-----`
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/version.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/version.go
index 8fad58d..4311d51 100644
--- a/vendor/github.com/hashicorp/terraform/plugin/discovery/version.go
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/version.go
@@ -55,6 +55,11 @@ func (v Version) Equal(other Version) bool {
55 return v.raw.Equal(other.raw) 55 return v.raw.Equal(other.raw)
56} 56}
57 57
58// IsPrerelease determines if version is a prerelease
59func (v Version) IsPrerelease() bool {
60 return v.raw.Prerelease() != ""
61}
62
58// MinorUpgradeConstraintStr returns a ConstraintStr that would permit 63// MinorUpgradeConstraintStr returns a ConstraintStr that would permit
59// minor upgrades relative to the receiving version. 64// minor upgrades relative to the receiving version.
60func (v Version) MinorUpgradeConstraintStr() ConstraintStr { 65func (v Version) MinorUpgradeConstraintStr() ConstraintStr {
diff --git a/vendor/github.com/hashicorp/terraform/plugin/discovery/version_set.go b/vendor/github.com/hashicorp/terraform/plugin/discovery/version_set.go
index 0aefd75..de02f5e 100644
--- a/vendor/github.com/hashicorp/terraform/plugin/discovery/version_set.go
+++ b/vendor/github.com/hashicorp/terraform/plugin/discovery/version_set.go
@@ -36,6 +36,11 @@ type Constraints struct {
36 raw version.Constraints 36 raw version.Constraints
37} 37}
38 38
39// NewConstraints creates a Constraints based on a version.Constraints.
40func NewConstraints(c version.Constraints) Constraints {
41 return Constraints{c}
42}
43
39// AllVersions is a Constraints containing all versions 44// AllVersions is a Constraints containing all versions
40var AllVersions Constraints 45var AllVersions Constraints
41 46
diff --git a/vendor/github.com/hashicorp/terraform/plugin/grpc_provider.go b/vendor/github.com/hashicorp/terraform/plugin/grpc_provider.go
new file mode 100644
index 0000000..ae9a400
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/plugin/grpc_provider.go
@@ -0,0 +1,562 @@
1package plugin
2
3import (
4 "context"
5 "errors"
6 "log"
7 "sync"
8
9 "github.com/zclconf/go-cty/cty"
10
11 plugin "github.com/hashicorp/go-plugin"
12 proto "github.com/hashicorp/terraform/internal/tfplugin5"
13 "github.com/hashicorp/terraform/plugin/convert"
14 "github.com/hashicorp/terraform/providers"
15 "github.com/hashicorp/terraform/version"
16 "github.com/zclconf/go-cty/cty/msgpack"
17 "google.golang.org/grpc"
18)
19
20// GRPCProviderPlugin implements plugin.GRPCPlugin for the go-plugin package.
21type GRPCProviderPlugin struct {
22 plugin.Plugin
23 GRPCProvider func() proto.ProviderServer
24}
25
26func (p *GRPCProviderPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
27 return &GRPCProvider{
28 client: proto.NewProviderClient(c),
29 ctx: ctx,
30 }, nil
31}
32
33func (p *GRPCProviderPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
34 proto.RegisterProviderServer(s, p.GRPCProvider())
35 return nil
36}
37
38// GRPCProvider handles the client, or core side of the plugin rpc connection.
39// The GRPCProvider methods are mostly a translation layer between the
40// terraform provioders types and the grpc proto types, directly converting
41// between the two.
42type GRPCProvider struct {
43 // PluginClient provides a reference to the plugin.Client which controls the plugin process.
44 // This allows the GRPCProvider a way to shutdown the plugin process.
45 PluginClient *plugin.Client
46
47 // TestServer contains a grpc.Server to close when the GRPCProvider is being
48 // used in an end to end test of a provider.
49 TestServer *grpc.Server
50
51 // Proto client use to make the grpc service calls.
52 client proto.ProviderClient
53
54 // this context is created by the plugin package, and is canceled when the
55 // plugin process ends.
56 ctx context.Context
57
58 // schema stores the schema for this provider. This is used to properly
59 // serialize the state for requests.
60 mu sync.Mutex
61 schemas providers.GetSchemaResponse
62}
63
64// getSchema is used internally to get the saved provider schema. The schema
65// should have already been fetched from the provider, but we have to
66// synchronize access to avoid being called concurrently with GetSchema.
67func (p *GRPCProvider) getSchema() providers.GetSchemaResponse {
68 p.mu.Lock()
69 // unlock inline in case GetSchema needs to be called
70 if p.schemas.Provider.Block != nil {
71 p.mu.Unlock()
72 return p.schemas
73 }
74 p.mu.Unlock()
75
76 // the schema should have been fetched already, but give it another shot
77 // just in case things are being called out of order. This may happen for
78 // tests.
79 schemas := p.GetSchema()
80 if schemas.Diagnostics.HasErrors() {
81 panic(schemas.Diagnostics.Err())
82 }
83
84 return schemas
85}
86
87// getResourceSchema is a helper to extract the schema for a resource, and
88// panics if the schema is not available.
89func (p *GRPCProvider) getResourceSchema(name string) providers.Schema {
90 schema := p.getSchema()
91 resSchema, ok := schema.ResourceTypes[name]
92 if !ok {
93 panic("unknown resource type " + name)
94 }
95 return resSchema
96}
97
98// gettDatasourceSchema is a helper to extract the schema for a datasource, and
99// panics if that schema is not available.
100func (p *GRPCProvider) getDatasourceSchema(name string) providers.Schema {
101 schema := p.getSchema()
102 dataSchema, ok := schema.DataSources[name]
103 if !ok {
104 panic("unknown data source " + name)
105 }
106 return dataSchema
107}
108
109func (p *GRPCProvider) GetSchema() (resp providers.GetSchemaResponse) {
110 log.Printf("[TRACE] GRPCProvider: GetSchema")
111 p.mu.Lock()
112 defer p.mu.Unlock()
113
114 if p.schemas.Provider.Block != nil {
115 return p.schemas
116 }
117
118 resp.ResourceTypes = make(map[string]providers.Schema)
119 resp.DataSources = make(map[string]providers.Schema)
120
121 // Some providers may generate quite large schemas, and the internal default
122 // grpc response size limit is 4MB. 64MB should cover most any use case, and
123 // if we get providers nearing that we may want to consider a finer-grained
124 // API to fetch individual resource schemas.
125 // Note: this option is marked as EXPERIMENTAL in the grpc API.
126 const maxRecvSize = 64 << 20
127 protoResp, err := p.client.GetSchema(p.ctx, new(proto.GetProviderSchema_Request), grpc.MaxRecvMsgSizeCallOption{MaxRecvMsgSize: maxRecvSize})
128 if err != nil {
129 resp.Diagnostics = resp.Diagnostics.Append(err)
130 return resp
131 }
132
133 resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
134
135 if protoResp.Provider == nil {
136 resp.Diagnostics = resp.Diagnostics.Append(errors.New("missing provider schema"))
137 return resp
138 }
139
140 resp.Provider = convert.ProtoToProviderSchema(protoResp.Provider)
141
142 for name, res := range protoResp.ResourceSchemas {
143 resp.ResourceTypes[name] = convert.ProtoToProviderSchema(res)
144 }
145
146 for name, data := range protoResp.DataSourceSchemas {
147 resp.DataSources[name] = convert.ProtoToProviderSchema(data)
148 }
149
150 p.schemas = resp
151
152 return resp
153}
154
155func (p *GRPCProvider) PrepareProviderConfig(r providers.PrepareProviderConfigRequest) (resp providers.PrepareProviderConfigResponse) {
156 log.Printf("[TRACE] GRPCProvider: PrepareProviderConfig")
157
158 schema := p.getSchema()
159 ty := schema.Provider.Block.ImpliedType()
160
161 mp, err := msgpack.Marshal(r.Config, ty)
162 if err != nil {
163 resp.Diagnostics = resp.Diagnostics.Append(err)
164 return resp
165 }
166
167 protoReq := &proto.PrepareProviderConfig_Request{
168 Config: &proto.DynamicValue{Msgpack: mp},
169 }
170
171 protoResp, err := p.client.PrepareProviderConfig(p.ctx, protoReq)
172 if err != nil {
173 resp.Diagnostics = resp.Diagnostics.Append(err)
174 return resp
175 }
176
177 config := cty.NullVal(ty)
178 if protoResp.PreparedConfig != nil {
179 config, err = msgpack.Unmarshal(protoResp.PreparedConfig.Msgpack, ty)
180 if err != nil {
181 resp.Diagnostics = resp.Diagnostics.Append(err)
182 return resp
183 }
184 }
185 resp.PreparedConfig = config
186
187 resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
188 return resp
189}
190
191func (p *GRPCProvider) ValidateResourceTypeConfig(r providers.ValidateResourceTypeConfigRequest) (resp providers.ValidateResourceTypeConfigResponse) {
192 log.Printf("[TRACE] GRPCProvider: ValidateResourceTypeConfig")
193 resourceSchema := p.getResourceSchema(r.TypeName)
194
195 mp, err := msgpack.Marshal(r.Config, resourceSchema.Block.ImpliedType())
196 if err != nil {
197 resp.Diagnostics = resp.Diagnostics.Append(err)
198 return resp
199 }
200
201 protoReq := &proto.ValidateResourceTypeConfig_Request{
202 TypeName: r.TypeName,
203 Config: &proto.DynamicValue{Msgpack: mp},
204 }
205
206 protoResp, err := p.client.ValidateResourceTypeConfig(p.ctx, protoReq)
207 if err != nil {
208 resp.Diagnostics = resp.Diagnostics.Append(err)
209 return resp
210 }
211
212 resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
213 return resp
214}
215
216func (p *GRPCProvider) ValidateDataSourceConfig(r providers.ValidateDataSourceConfigRequest) (resp providers.ValidateDataSourceConfigResponse) {
217 log.Printf("[TRACE] GRPCProvider: ValidateDataSourceConfig")
218
219 dataSchema := p.getDatasourceSchema(r.TypeName)
220
221 mp, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType())
222 if err != nil {
223 resp.Diagnostics = resp.Diagnostics.Append(err)
224 return resp
225 }
226
227 protoReq := &proto.ValidateDataSourceConfig_Request{
228 TypeName: r.TypeName,
229 Config: &proto.DynamicValue{Msgpack: mp},
230 }
231
232 protoResp, err := p.client.ValidateDataSourceConfig(p.ctx, protoReq)
233 if err != nil {
234 resp.Diagnostics = resp.Diagnostics.Append(err)
235 return resp
236 }
237 resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
238 return resp
239}
240
241func (p *GRPCProvider) UpgradeResourceState(r providers.UpgradeResourceStateRequest) (resp providers.UpgradeResourceStateResponse) {
242 log.Printf("[TRACE] GRPCProvider: UpgradeResourceState")
243
244 resSchema := p.getResourceSchema(r.TypeName)
245
246 protoReq := &proto.UpgradeResourceState_Request{
247 TypeName: r.TypeName,
248 Version: int64(r.Version),
249 RawState: &proto.RawState{
250 Json: r.RawStateJSON,
251 Flatmap: r.RawStateFlatmap,
252 },
253 }
254
255 protoResp, err := p.client.UpgradeResourceState(p.ctx, protoReq)
256 if err != nil {
257 resp.Diagnostics = resp.Diagnostics.Append(err)
258 return resp
259 }
260 resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
261
262 state := cty.NullVal(resSchema.Block.ImpliedType())
263 if protoResp.UpgradedState != nil {
264 state, err = msgpack.Unmarshal(protoResp.UpgradedState.Msgpack, resSchema.Block.ImpliedType())
265 if err != nil {
266 resp.Diagnostics = resp.Diagnostics.Append(err)
267 return resp
268 }
269 }
270
271 resp.UpgradedState = state
272 return resp
273}
274
275func (p *GRPCProvider) Configure(r providers.ConfigureRequest) (resp providers.ConfigureResponse) {
276 log.Printf("[TRACE] GRPCProvider: Configure")
277
278 schema := p.getSchema()
279
280 var mp []byte
281
282 // we don't have anything to marshal if there's no config
283 mp, err := msgpack.Marshal(r.Config, schema.Provider.Block.ImpliedType())
284 if err != nil {
285 resp.Diagnostics = resp.Diagnostics.Append(err)
286 return resp
287 }
288
289 protoReq := &proto.Configure_Request{
290 TerraformVersion: version.Version,
291 Config: &proto.DynamicValue{
292 Msgpack: mp,
293 },
294 }
295
296 protoResp, err := p.client.Configure(p.ctx, protoReq)
297 if err != nil {
298 resp.Diagnostics = resp.Diagnostics.Append(err)
299 return resp
300 }
301 resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
302 return resp
303}
304
305func (p *GRPCProvider) Stop() error {
306 log.Printf("[TRACE] GRPCProvider: Stop")
307
308 resp, err := p.client.Stop(p.ctx, new(proto.Stop_Request))
309 if err != nil {
310 return err
311 }
312
313 if resp.Error != "" {
314 return errors.New(resp.Error)
315 }
316 return nil
317}
318
319func (p *GRPCProvider) ReadResource(r providers.ReadResourceRequest) (resp providers.ReadResourceResponse) {
320 log.Printf("[TRACE] GRPCProvider: ReadResource")
321
322 resSchema := p.getResourceSchema(r.TypeName)
323
324 mp, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
325 if err != nil {
326 resp.Diagnostics = resp.Diagnostics.Append(err)
327 return resp
328 }
329
330 protoReq := &proto.ReadResource_Request{
331 TypeName: r.TypeName,
332 CurrentState: &proto.DynamicValue{Msgpack: mp},
333 }
334
335 protoResp, err := p.client.ReadResource(p.ctx, protoReq)
336 if err != nil {
337 resp.Diagnostics = resp.Diagnostics.Append(err)
338 return resp
339 }
340 resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
341
342 state := cty.NullVal(resSchema.Block.ImpliedType())
343 if protoResp.NewState != nil {
344 state, err = msgpack.Unmarshal(protoResp.NewState.Msgpack, resSchema.Block.ImpliedType())
345 if err != nil {
346 resp.Diagnostics = resp.Diagnostics.Append(err)
347 return resp
348 }
349 }
350 resp.NewState = state
351
352 return resp
353}
354
355func (p *GRPCProvider) PlanResourceChange(r providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
356 log.Printf("[TRACE] GRPCProvider: PlanResourceChange")
357
358 resSchema := p.getResourceSchema(r.TypeName)
359
360 priorMP, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
361 if err != nil {
362 resp.Diagnostics = resp.Diagnostics.Append(err)
363 return resp
364 }
365
366 configMP, err := msgpack.Marshal(r.Config, resSchema.Block.ImpliedType())
367 if err != nil {
368 resp.Diagnostics = resp.Diagnostics.Append(err)
369 return resp
370 }
371
372 propMP, err := msgpack.Marshal(r.ProposedNewState, resSchema.Block.ImpliedType())
373 if err != nil {
374 resp.Diagnostics = resp.Diagnostics.Append(err)
375 return resp
376 }
377
378 protoReq := &proto.PlanResourceChange_Request{
379 TypeName: r.TypeName,
380 PriorState: &proto.DynamicValue{Msgpack: priorMP},
381 Config: &proto.DynamicValue{Msgpack: configMP},
382 ProposedNewState: &proto.DynamicValue{Msgpack: propMP},
383 PriorPrivate: r.PriorPrivate,
384 }
385
386 protoResp, err := p.client.PlanResourceChange(p.ctx, protoReq)
387 if err != nil {
388 resp.Diagnostics = resp.Diagnostics.Append(err)
389 return resp
390 }
391 resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
392
393 state := cty.NullVal(resSchema.Block.ImpliedType())
394 if protoResp.PlannedState != nil {
395 state, err = msgpack.Unmarshal(protoResp.PlannedState.Msgpack, resSchema.Block.ImpliedType())
396 if err != nil {
397 resp.Diagnostics = resp.Diagnostics.Append(err)
398 return resp
399 }
400 }
401 resp.PlannedState = state
402
403 for _, p := range protoResp.RequiresReplace {
404 resp.RequiresReplace = append(resp.RequiresReplace, convert.AttributePathToPath(p))
405 }
406
407 resp.PlannedPrivate = protoResp.PlannedPrivate
408
409 resp.LegacyTypeSystem = protoResp.LegacyTypeSystem
410
411 return resp
412}
413
414func (p *GRPCProvider) ApplyResourceChange(r providers.ApplyResourceChangeRequest) (resp providers.ApplyResourceChangeResponse) {
415 log.Printf("[TRACE] GRPCProvider: ApplyResourceChange")
416
417 resSchema := p.getResourceSchema(r.TypeName)
418
419 priorMP, err := msgpack.Marshal(r.PriorState, resSchema.Block.ImpliedType())
420 if err != nil {
421 resp.Diagnostics = resp.Diagnostics.Append(err)
422 return resp
423 }
424 plannedMP, err := msgpack.Marshal(r.PlannedState, resSchema.Block.ImpliedType())
425 if err != nil {
426 resp.Diagnostics = resp.Diagnostics.Append(err)
427 return resp
428 }
429 configMP, err := msgpack.Marshal(r.Config, resSchema.Block.ImpliedType())
430 if err != nil {
431 resp.Diagnostics = resp.Diagnostics.Append(err)
432 return resp
433 }
434
435 protoReq := &proto.ApplyResourceChange_Request{
436 TypeName: r.TypeName,
437 PriorState: &proto.DynamicValue{Msgpack: priorMP},
438 PlannedState: &proto.DynamicValue{Msgpack: plannedMP},
439 Config: &proto.DynamicValue{Msgpack: configMP},
440 PlannedPrivate: r.PlannedPrivate,
441 }
442
443 protoResp, err := p.client.ApplyResourceChange(p.ctx, protoReq)
444 if err != nil {
445 resp.Diagnostics = resp.Diagnostics.Append(err)
446 return resp
447 }
448 resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
449
450 resp.Private = protoResp.Private
451
452 state := cty.NullVal(resSchema.Block.ImpliedType())
453 if protoResp.NewState != nil {
454 state, err = msgpack.Unmarshal(protoResp.NewState.Msgpack, resSchema.Block.ImpliedType())
455 if err != nil {
456 resp.Diagnostics = resp.Diagnostics.Append(err)
457 return resp
458 }
459 }
460 resp.NewState = state
461
462 resp.LegacyTypeSystem = protoResp.LegacyTypeSystem
463
464 return resp
465}
466
467func (p *GRPCProvider) ImportResourceState(r providers.ImportResourceStateRequest) (resp providers.ImportResourceStateResponse) {
468 log.Printf("[TRACE] GRPCProvider: ImportResourceState")
469
470 protoReq := &proto.ImportResourceState_Request{
471 TypeName: r.TypeName,
472 Id: r.ID,
473 }
474
475 protoResp, err := p.client.ImportResourceState(p.ctx, protoReq)
476 if err != nil {
477 resp.Diagnostics = resp.Diagnostics.Append(err)
478 return resp
479 }
480 resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
481
482 for _, imported := range protoResp.ImportedResources {
483 resource := providers.ImportedResource{
484 TypeName: imported.TypeName,
485 Private: imported.Private,
486 }
487
488 resSchema := p.getResourceSchema(resource.TypeName)
489 state := cty.NullVal(resSchema.Block.ImpliedType())
490 if imported.State != nil {
491 state, err = msgpack.Unmarshal(imported.State.Msgpack, resSchema.Block.ImpliedType())
492 if err != nil {
493 resp.Diagnostics = resp.Diagnostics.Append(err)
494 return resp
495 }
496 }
497 resource.State = state
498 resp.ImportedResources = append(resp.ImportedResources, resource)
499 }
500
501 return resp
502}
503
504func (p *GRPCProvider) ReadDataSource(r providers.ReadDataSourceRequest) (resp providers.ReadDataSourceResponse) {
505 log.Printf("[TRACE] GRPCProvider: ReadDataSource")
506
507 dataSchema := p.getDatasourceSchema(r.TypeName)
508
509 config, err := msgpack.Marshal(r.Config, dataSchema.Block.ImpliedType())
510 if err != nil {
511 resp.Diagnostics = resp.Diagnostics.Append(err)
512 return resp
513 }
514
515 protoReq := &proto.ReadDataSource_Request{
516 TypeName: r.TypeName,
517 Config: &proto.DynamicValue{
518 Msgpack: config,
519 },
520 }
521
522 protoResp, err := p.client.ReadDataSource(p.ctx, protoReq)
523 if err != nil {
524 resp.Diagnostics = resp.Diagnostics.Append(err)
525 return resp
526 }
527 resp.Diagnostics = resp.Diagnostics.Append(convert.ProtoToDiagnostics(protoResp.Diagnostics))
528
529 state := cty.NullVal(dataSchema.Block.ImpliedType())
530 if protoResp.State != nil {
531 state, err = msgpack.Unmarshal(protoResp.State.Msgpack, dataSchema.Block.ImpliedType())
532 if err != nil {
533 resp.Diagnostics = resp.Diagnostics.Append(err)
534 return resp
535 }
536 }
537 resp.State = state
538
539 return resp
540}
541
542// closing the grpc connection is final, and terraform will call it at the end of every phase.
543func (p *GRPCProvider) Close() error {
544 log.Printf("[TRACE] GRPCProvider: Close")
545
546 // Make sure to stop the server if we're not running within go-plugin.
547 if p.TestServer != nil {
548 p.TestServer.Stop()
549 }
550
551 // Check this since it's not automatically inserted during plugin creation.
552 // It's currently only inserted by the command package, because that is
553 // where the factory is built and is the only point with access to the
554 // plugin.Client.
555 if p.PluginClient == nil {
556 log.Println("[DEBUG] provider has no plugin.Client")
557 return nil
558 }
559
560 p.PluginClient.Kill()
561 return nil
562}
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 @@
1package plugin
2
3import (
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.
21type GRPCProvisionerPlugin struct {
22 plugin.Plugin
23 GRPCProvisioner func() proto.ProvisionerServer
24}
25
26func (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
33func (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
39type 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
52func (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
81func (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
106func (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
158func (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
169func (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}
diff --git a/vendor/github.com/hashicorp/terraform/plugin/plugin.go b/vendor/github.com/hashicorp/terraform/plugin/plugin.go
index 00fa7b2..e4fb577 100644
--- a/vendor/github.com/hashicorp/terraform/plugin/plugin.go
+++ b/vendor/github.com/hashicorp/terraform/plugin/plugin.go
@@ -6,8 +6,9 @@ import (
6 6
7// See serve.go for serving plugins 7// See serve.go for serving plugins
8 8
9// PluginMap should be used by clients for the map of plugins. 9var VersionedPlugins = map[int]plugin.PluginSet{
10var PluginMap = map[string]plugin.Plugin{ 10 5: {
11 "provider": &ResourceProviderPlugin{}, 11 "provider": &GRPCProviderPlugin{},
12 "provisioner": &ResourceProvisionerPlugin{}, 12 "provisioner": &GRPCProvisionerPlugin{},
13 },
13} 14}
diff --git a/vendor/github.com/hashicorp/terraform/plugin/resource_provider.go b/vendor/github.com/hashicorp/terraform/plugin/resource_provider.go
index d6a433c..459661a 100644
--- a/vendor/github.com/hashicorp/terraform/plugin/resource_provider.go
+++ b/vendor/github.com/hashicorp/terraform/plugin/resource_provider.go
@@ -9,11 +9,14 @@ import (
9 9
10// ResourceProviderPlugin is the plugin.Plugin implementation. 10// ResourceProviderPlugin is the plugin.Plugin implementation.
11type ResourceProviderPlugin struct { 11type ResourceProviderPlugin struct {
12 F func() terraform.ResourceProvider 12 ResourceProvider func() terraform.ResourceProvider
13} 13}
14 14
15func (p *ResourceProviderPlugin) Server(b *plugin.MuxBroker) (interface{}, error) { 15func (p *ResourceProviderPlugin) Server(b *plugin.MuxBroker) (interface{}, error) {
16 return &ResourceProviderServer{Broker: b, Provider: p.F()}, nil 16 return &ResourceProviderServer{
17 Broker: b,
18 Provider: p.ResourceProvider(),
19 }, nil
17} 20}
18 21
19func (p *ResourceProviderPlugin) Client( 22func (p *ResourceProviderPlugin) Client(
diff --git a/vendor/github.com/hashicorp/terraform/plugin/resource_provisioner.go b/vendor/github.com/hashicorp/terraform/plugin/resource_provisioner.go
index 8fce9d8..f0cc341 100644
--- a/vendor/github.com/hashicorp/terraform/plugin/resource_provisioner.go
+++ b/vendor/github.com/hashicorp/terraform/plugin/resource_provisioner.go
@@ -4,16 +4,20 @@ import (
4 "net/rpc" 4 "net/rpc"
5 5
6 "github.com/hashicorp/go-plugin" 6 "github.com/hashicorp/go-plugin"
7 "github.com/hashicorp/terraform/configs/configschema"
7 "github.com/hashicorp/terraform/terraform" 8 "github.com/hashicorp/terraform/terraform"
8) 9)
9 10
10// ResourceProvisionerPlugin is the plugin.Plugin implementation. 11// ResourceProvisionerPlugin is the plugin.Plugin implementation.
11type ResourceProvisionerPlugin struct { 12type ResourceProvisionerPlugin struct {
12 F func() terraform.ResourceProvisioner 13 ResourceProvisioner func() terraform.ResourceProvisioner
13} 14}
14 15
15func (p *ResourceProvisionerPlugin) Server(b *plugin.MuxBroker) (interface{}, error) { 16func (p *ResourceProvisionerPlugin) Server(b *plugin.MuxBroker) (interface{}, error) {
16 return &ResourceProvisionerServer{Broker: b, Provisioner: p.F()}, nil 17 return &ResourceProvisionerServer{
18 Broker: b,
19 Provisioner: p.ResourceProvisioner(),
20 }, nil
17} 21}
18 22
19func (p *ResourceProvisionerPlugin) Client( 23func (p *ResourceProvisionerPlugin) Client(
@@ -28,6 +32,11 @@ type ResourceProvisioner struct {
28 Client *rpc.Client 32 Client *rpc.Client
29} 33}
30 34
35func (p *ResourceProvisioner) GetConfigSchema() (*configschema.Block, error) {
36 panic("not implemented")
37 return nil, nil
38}
39
31func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) ([]string, []error) { 40func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) ([]string, []error) {
32 var resp ResourceProvisionerValidateResponse 41 var resp ResourceProvisionerValidateResponse
33 args := ResourceProvisionerValidateArgs{ 42 args := ResourceProvisionerValidateArgs{
diff --git a/vendor/github.com/hashicorp/terraform/plugin/serve.go b/vendor/github.com/hashicorp/terraform/plugin/serve.go
index 2028a61..8d056c5 100644
--- a/vendor/github.com/hashicorp/terraform/plugin/serve.go
+++ b/vendor/github.com/hashicorp/terraform/plugin/serve.go
@@ -2,14 +2,23 @@ package plugin
2 2
3import ( 3import (
4 "github.com/hashicorp/go-plugin" 4 "github.com/hashicorp/go-plugin"
5 grpcplugin "github.com/hashicorp/terraform/helper/plugin"
6 proto "github.com/hashicorp/terraform/internal/tfplugin5"
5 "github.com/hashicorp/terraform/terraform" 7 "github.com/hashicorp/terraform/terraform"
6) 8)
7 9
8// The constants below are the names of the plugins that can be dispensed
9// from the plugin server.
10const ( 10const (
11 // The constants below are the names of the plugins that can be dispensed
12 // from the plugin server.
11 ProviderPluginName = "provider" 13 ProviderPluginName = "provider"
12 ProvisionerPluginName = "provisioner" 14 ProvisionerPluginName = "provisioner"
15
16 // DefaultProtocolVersion is the protocol version assumed for legacy clients that don't specify
17 // a particular version during their handshake. This is the version used when Terraform 0.10
18 // and 0.11 launch plugins that were built with support for both versions 4 and 5, and must
19 // stay unchanged at 4 until we intentionally build plugins that are not compatible with 0.10 and
20 // 0.11.
21 DefaultProtocolVersion = 4
13) 22)
14 23
15// Handshake is the HandshakeConfig used to configure clients and servers. 24// Handshake is the HandshakeConfig used to configure clients and servers.
@@ -19,7 +28,7 @@ var Handshake = plugin.HandshakeConfig{
19 // one or the other that makes it so that they can't safely communicate. 28 // one or the other that makes it so that they can't safely communicate.
20 // This could be adding a new interface value, it could be how 29 // This could be adding a new interface value, it could be how
21 // helper/schema computes diffs, etc. 30 // helper/schema computes diffs, etc.
22 ProtocolVersion: 4, 31 ProtocolVersion: DefaultProtocolVersion,
23 32
24 // The magic cookie values should NEVER be changed. 33 // The magic cookie values should NEVER be changed.
25 MagicCookieKey: "TF_PLUGIN_MAGIC_COOKIE", 34 MagicCookieKey: "TF_PLUGIN_MAGIC_COOKIE",
@@ -28,27 +37,85 @@ var Handshake = plugin.HandshakeConfig{
28 37
29type ProviderFunc func() terraform.ResourceProvider 38type ProviderFunc func() terraform.ResourceProvider
30type ProvisionerFunc func() terraform.ResourceProvisioner 39type ProvisionerFunc func() terraform.ResourceProvisioner
40type GRPCProviderFunc func() proto.ProviderServer
41type GRPCProvisionerFunc func() proto.ProvisionerServer
31 42
32// ServeOpts are the configurations to serve a plugin. 43// ServeOpts are the configurations to serve a plugin.
33type ServeOpts struct { 44type ServeOpts struct {
34 ProviderFunc ProviderFunc 45 ProviderFunc ProviderFunc
35 ProvisionerFunc ProvisionerFunc 46 ProvisionerFunc ProvisionerFunc
47
48 // Wrapped versions of the above plugins will automatically shimmed and
49 // added to the GRPC functions when possible.
50 GRPCProviderFunc GRPCProviderFunc
51 GRPCProvisionerFunc GRPCProvisionerFunc
36} 52}
37 53
38// Serve serves a plugin. This function never returns and should be the final 54// Serve serves a plugin. This function never returns and should be the final
39// function called in the main function of the plugin. 55// function called in the main function of the plugin.
40func Serve(opts *ServeOpts) { 56func Serve(opts *ServeOpts) {
57 // since the plugins may not yet be aware of the new protocol, we
58 // automatically wrap the plugins in the grpc shims.
59 if opts.GRPCProviderFunc == nil && opts.ProviderFunc != nil {
60 provider := grpcplugin.NewGRPCProviderServerShim(opts.ProviderFunc())
61 // this is almost always going to be a *schema.Provider, but check that
62 // we got back a valid provider just in case.
63 if provider != nil {
64 opts.GRPCProviderFunc = func() proto.ProviderServer {
65 return provider
66 }
67 }
68 }
69 if opts.GRPCProvisionerFunc == nil && opts.ProvisionerFunc != nil {
70 provisioner := grpcplugin.NewGRPCProvisionerServerShim(opts.ProvisionerFunc())
71 if provisioner != nil {
72 opts.GRPCProvisionerFunc = func() proto.ProvisionerServer {
73 return provisioner
74 }
75 }
76 }
77
41 plugin.Serve(&plugin.ServeConfig{ 78 plugin.Serve(&plugin.ServeConfig{
42 HandshakeConfig: Handshake, 79 HandshakeConfig: Handshake,
43 Plugins: pluginMap(opts), 80 VersionedPlugins: pluginSet(opts),
81 GRPCServer: plugin.DefaultGRPCServer,
44 }) 82 })
45} 83}
46 84
47// pluginMap returns the map[string]plugin.Plugin to use for configuring a plugin 85// pluginMap returns the legacy map[string]plugin.Plugin to use for configuring
48// server or client. 86// a plugin server or client.
49func pluginMap(opts *ServeOpts) map[string]plugin.Plugin { 87func legacyPluginMap(opts *ServeOpts) map[string]plugin.Plugin {
50 return map[string]plugin.Plugin{ 88 return map[string]plugin.Plugin{
51 "provider": &ResourceProviderPlugin{F: opts.ProviderFunc}, 89 "provider": &ResourceProviderPlugin{
52 "provisioner": &ResourceProvisionerPlugin{F: opts.ProvisionerFunc}, 90 ResourceProvider: opts.ProviderFunc,
91 },
92 "provisioner": &ResourceProvisionerPlugin{
93 ResourceProvisioner: opts.ProvisionerFunc,
94 },
95 }
96}
97
98func pluginSet(opts *ServeOpts) map[int]plugin.PluginSet {
99 // Set the legacy netrpc plugins at version 4.
100 // The oldest version is returned in when executed by a legacy go-plugin
101 // client.
102 plugins := map[int]plugin.PluginSet{
103 4: legacyPluginMap(opts),
104 }
105
106 // add the new protocol versions if they're configured
107 if opts.GRPCProviderFunc != nil || opts.GRPCProvisionerFunc != nil {
108 plugins[5] = plugin.PluginSet{}
109 if opts.GRPCProviderFunc != nil {
110 plugins[5]["provider"] = &GRPCProviderPlugin{
111 GRPCProvider: opts.GRPCProviderFunc,
112 }
113 }
114 if opts.GRPCProvisionerFunc != nil {
115 plugins[5]["provisioner"] = &GRPCProvisionerPlugin{
116 GRPCProvisioner: opts.GRPCProvisionerFunc,
117 }
118 }
53 } 119 }
120 return plugins
54} 121}
diff --git a/vendor/github.com/hashicorp/terraform/plugin/ui_input.go b/vendor/github.com/hashicorp/terraform/plugin/ui_input.go
index 493efc0..3469e6a 100644
--- a/vendor/github.com/hashicorp/terraform/plugin/ui_input.go
+++ b/vendor/github.com/hashicorp/terraform/plugin/ui_input.go
@@ -1,19 +1,20 @@
1package plugin 1package plugin
2 2
3import ( 3import (
4 "context"
4 "net/rpc" 5 "net/rpc"
5 6
6 "github.com/hashicorp/go-plugin" 7 "github.com/hashicorp/go-plugin"
7 "github.com/hashicorp/terraform/terraform" 8 "github.com/hashicorp/terraform/terraform"
8) 9)
9 10
10// UIInput is an implementatin of terraform.UIInput that communicates 11// UIInput is an implementation of terraform.UIInput that communicates
11// over RPC. 12// over RPC.
12type UIInput struct { 13type UIInput struct {
13 Client *rpc.Client 14 Client *rpc.Client
14} 15}
15 16
16func (i *UIInput) Input(opts *terraform.InputOpts) (string, error) { 17func (i *UIInput) Input(ctx context.Context, opts *terraform.InputOpts) (string, error) {
17 var resp UIInputInputResponse 18 var resp UIInputInputResponse
18 err := i.Client.Call("Plugin.Input", opts, &resp) 19 err := i.Client.Call("Plugin.Input", opts, &resp)
19 if err != nil { 20 if err != nil {
@@ -41,7 +42,7 @@ type UIInputServer struct {
41func (s *UIInputServer) Input( 42func (s *UIInputServer) Input(
42 opts *terraform.InputOpts, 43 opts *terraform.InputOpts,
43 reply *UIInputInputResponse) error { 44 reply *UIInputInputResponse) error {
44 value, err := s.UIInput.Input(opts) 45 value, err := s.UIInput.Input(context.Background(), opts)
45 *reply = UIInputInputResponse{ 46 *reply = UIInputInputResponse{
46 Value: value, 47 Value: value,
47 Error: plugin.NewBasicError(err), 48 Error: plugin.NewBasicError(err),