Merge pull request #27078 from hashicorp/jbardin/remove-netrpc-plugin

Remove netrpc plugin
This commit is contained in:
James Bardin 2020-12-02 13:23:29 -05:00 committed by GitHub
commit b2d0e20759
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 2 additions and 2038 deletions

View File

@ -1,76 +0,0 @@
package terraform
import (
"fmt"
"reflect"
)
// remoteStateFlatten takes a structure and turns into a flat map[string]string.
//
// Within the "thing" parameter, only primitive values are allowed. Structs are
// not supported. Therefore, it can only be slices, maps, primitives, and
// any combination of those together.
//
// The difference between this version and the version in package flatmap is that
// we add the count key for maps in this version, and return a normal
// map[string]string instead of a flatmap.Map
func remoteStateFlatten(thing map[string]interface{}) map[string]string {
result := make(map[string]string)
for k, raw := range thing {
flatten(result, k, reflect.ValueOf(raw))
}
return result
}
func flatten(result map[string]string, prefix string, v reflect.Value) {
if v.Kind() == reflect.Interface {
v = v.Elem()
}
switch v.Kind() {
case reflect.Bool:
if v.Bool() {
result[prefix] = "true"
} else {
result[prefix] = "false"
}
case reflect.Int:
result[prefix] = fmt.Sprintf("%d", v.Int())
case reflect.Map:
flattenMap(result, prefix, v)
case reflect.Slice:
flattenSlice(result, prefix, v)
case reflect.String:
result[prefix] = v.String()
default:
panic(fmt.Sprintf("Unknown: %s", v))
}
}
func flattenMap(result map[string]string, prefix string, v reflect.Value) {
mapKeys := v.MapKeys()
result[fmt.Sprintf("%s.%%", prefix)] = fmt.Sprintf("%d", len(mapKeys))
for _, k := range mapKeys {
if k.Kind() == reflect.Interface {
k = k.Elem()
}
if k.Kind() != reflect.String {
panic(fmt.Sprintf("%s: map key is not string: %s", prefix, k))
}
flatten(result, fmt.Sprintf("%s.%s", prefix, k.String()), v.MapIndex(k))
}
}
func flattenSlice(result map[string]string, prefix string, v reflect.Value) {
prefix = prefix + "."
result[prefix+"#"] = fmt.Sprintf("%d", v.Len())
for i := 0; i < v.Len(); i++ {
flatten(result, fmt.Sprintf("%s%d", prefix, i), v.Index(i))
}
}

View File

@ -17,7 +17,7 @@ type Provider struct {
} }
// NewProvider returns a new terraform provider // NewProvider returns a new terraform provider
func NewProvider() *Provider { func NewProvider() providers.Interface {
return &Provider{} return &Provider{}
} }

View File

@ -1,29 +1,10 @@
package terraform package terraform
import ( import (
"testing"
"github.com/hashicorp/terraform/providers"
backendInit "github.com/hashicorp/terraform/backend/init" backendInit "github.com/hashicorp/terraform/backend/init"
) )
var testAccProviders map[string]*Provider
var testAccProvider *Provider
func init() { func init() {
// Initialize the backends // Initialize the backends
backendInit.Init(nil) backendInit.Init(nil)
testAccProvider = NewProvider()
testAccProviders = map[string]*Provider{
"terraform": testAccProvider,
}
}
func TestProvider_impl(t *testing.T) {
var _ providers.Interface = NewProvider()
}
func testAccPreCheck(t *testing.T) {
} }

View File

@ -4,8 +4,6 @@ import (
"github.com/hashicorp/go-plugin" "github.com/hashicorp/go-plugin"
) )
// See serve.go for serving plugins
var VersionedPlugins = map[int]plugin.PluginSet{ var VersionedPlugins = map[int]plugin.PluginSet{
5: { 5: {
"provider": &GRPCProviderPlugin{}, "provider": &GRPCProviderPlugin{},

View File

@ -1,17 +0,0 @@
package plugin
import (
"github.com/hashicorp/terraform/internal/legacy/terraform"
)
func testProviderFixed(p terraform.ResourceProvider) ProviderFunc {
return func() terraform.ResourceProvider {
return p
}
}
func testProvisionerFixed(p terraform.ResourceProvisioner) ProvisionerFunc {
return func() terraform.ResourceProvisioner {
return p
}
}

View File

@ -1,620 +0,0 @@
package plugin
import (
"net/rpc"
plugin "github.com/hashicorp/go-plugin"
"github.com/hashicorp/terraform/internal/legacy/terraform"
)
// ResourceProviderPlugin is the plugin.Plugin implementation.
type ResourceProviderPlugin struct {
ResourceProvider func() terraform.ResourceProvider
}
func (p *ResourceProviderPlugin) Server(b *plugin.MuxBroker) (interface{}, error) {
return &ResourceProviderServer{
Broker: b,
Provider: p.ResourceProvider(),
}, nil
}
func (p *ResourceProviderPlugin) Client(
b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
return &ResourceProvider{Broker: b, Client: c}, nil
}
// ResourceProvider is an implementation of terraform.ResourceProvider
// that communicates over RPC.
type ResourceProvider struct {
Broker *plugin.MuxBroker
Client *rpc.Client
}
func (p *ResourceProvider) Stop() error {
var resp ResourceProviderStopResponse
err := p.Client.Call("Plugin.Stop", new(interface{}), &resp)
if err != nil {
return err
}
if resp.Error != nil {
err = resp.Error
}
return err
}
func (p *ResourceProvider) GetSchema(req *terraform.ProviderSchemaRequest) (*terraform.ProviderSchema, error) {
var result ResourceProviderGetSchemaResponse
args := &ResourceProviderGetSchemaArgs{
Req: req,
}
err := p.Client.Call("Plugin.GetSchema", args, &result)
if err != nil {
return nil, err
}
if result.Error != nil {
err = result.Error
}
return result.Schema, err
}
func (p *ResourceProvider) Input(
input terraform.UIInput,
c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) {
id := p.Broker.NextId()
go p.Broker.AcceptAndServe(id, &UIInputServer{
UIInput: input,
})
var resp ResourceProviderInputResponse
args := ResourceProviderInputArgs{
InputId: id,
Config: c,
}
err := p.Client.Call("Plugin.Input", &args, &resp)
if err != nil {
return nil, err
}
if resp.Error != nil {
err = resp.Error
return nil, err
}
return resp.Config, nil
}
func (p *ResourceProvider) Validate(c *terraform.ResourceConfig) ([]string, []error) {
var resp ResourceProviderValidateResponse
args := ResourceProviderValidateArgs{
Config: c,
}
err := p.Client.Call("Plugin.Validate", &args, &resp)
if err != nil {
return nil, []error{err}
}
var errs []error
if len(resp.Errors) > 0 {
errs = make([]error, len(resp.Errors))
for i, err := range resp.Errors {
errs[i] = err
}
}
return resp.Warnings, errs
}
func (p *ResourceProvider) ValidateResource(
t string, c *terraform.ResourceConfig) ([]string, []error) {
var resp ResourceProviderValidateResourceResponse
args := ResourceProviderValidateResourceArgs{
Config: c,
Type: t,
}
err := p.Client.Call("Plugin.ValidateResource", &args, &resp)
if err != nil {
return nil, []error{err}
}
var errs []error
if len(resp.Errors) > 0 {
errs = make([]error, len(resp.Errors))
for i, err := range resp.Errors {
errs[i] = err
}
}
return resp.Warnings, errs
}
func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error {
var resp ResourceProviderConfigureResponse
err := p.Client.Call("Plugin.Configure", c, &resp)
if err != nil {
return err
}
if resp.Error != nil {
err = resp.Error
}
return err
}
func (p *ResourceProvider) Apply(
info *terraform.InstanceInfo,
s *terraform.InstanceState,
d *terraform.InstanceDiff) (*terraform.InstanceState, error) {
var resp ResourceProviderApplyResponse
args := &ResourceProviderApplyArgs{
Info: info,
State: s,
Diff: d,
}
err := p.Client.Call("Plugin.Apply", args, &resp)
if err != nil {
return nil, err
}
if resp.Error != nil {
err = resp.Error
}
return resp.State, err
}
func (p *ResourceProvider) Diff(
info *terraform.InstanceInfo,
s *terraform.InstanceState,
c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
var resp ResourceProviderDiffResponse
args := &ResourceProviderDiffArgs{
Info: info,
State: s,
Config: c,
}
err := p.Client.Call("Plugin.Diff", args, &resp)
if err != nil {
return nil, err
}
if resp.Error != nil {
err = resp.Error
}
return resp.Diff, err
}
func (p *ResourceProvider) ValidateDataSource(
t string, c *terraform.ResourceConfig) ([]string, []error) {
var resp ResourceProviderValidateResourceResponse
args := ResourceProviderValidateResourceArgs{
Config: c,
Type: t,
}
err := p.Client.Call("Plugin.ValidateDataSource", &args, &resp)
if err != nil {
return nil, []error{err}
}
var errs []error
if len(resp.Errors) > 0 {
errs = make([]error, len(resp.Errors))
for i, err := range resp.Errors {
errs[i] = err
}
}
return resp.Warnings, errs
}
func (p *ResourceProvider) Refresh(
info *terraform.InstanceInfo,
s *terraform.InstanceState) (*terraform.InstanceState, error) {
var resp ResourceProviderRefreshResponse
args := &ResourceProviderRefreshArgs{
Info: info,
State: s,
}
err := p.Client.Call("Plugin.Refresh", args, &resp)
if err != nil {
return nil, err
}
if resp.Error != nil {
err = resp.Error
}
return resp.State, err
}
func (p *ResourceProvider) ImportState(
info *terraform.InstanceInfo,
id string) ([]*terraform.InstanceState, error) {
var resp ResourceProviderImportStateResponse
args := &ResourceProviderImportStateArgs{
Info: info,
Id: id,
}
err := p.Client.Call("Plugin.ImportState", args, &resp)
if err != nil {
return nil, err
}
if resp.Error != nil {
err = resp.Error
}
return resp.State, err
}
func (p *ResourceProvider) Resources() []terraform.ResourceType {
var result []terraform.ResourceType
err := p.Client.Call("Plugin.Resources", new(interface{}), &result)
if err != nil {
// TODO: panic, log, what?
return nil
}
return result
}
func (p *ResourceProvider) ReadDataDiff(
info *terraform.InstanceInfo,
c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
var resp ResourceProviderReadDataDiffResponse
args := &ResourceProviderReadDataDiffArgs{
Info: info,
Config: c,
}
err := p.Client.Call("Plugin.ReadDataDiff", args, &resp)
if err != nil {
return nil, err
}
if resp.Error != nil {
err = resp.Error
}
return resp.Diff, err
}
func (p *ResourceProvider) ReadDataApply(
info *terraform.InstanceInfo,
d *terraform.InstanceDiff) (*terraform.InstanceState, error) {
var resp ResourceProviderReadDataApplyResponse
args := &ResourceProviderReadDataApplyArgs{
Info: info,
Diff: d,
}
err := p.Client.Call("Plugin.ReadDataApply", args, &resp)
if err != nil {
return nil, err
}
if resp.Error != nil {
err = resp.Error
}
return resp.State, err
}
func (p *ResourceProvider) DataSources() []terraform.DataSource {
var result []terraform.DataSource
err := p.Client.Call("Plugin.DataSources", new(interface{}), &result)
if err != nil {
// TODO: panic, log, what?
return nil
}
return result
}
func (p *ResourceProvider) Close() error {
return p.Client.Close()
}
// ResourceProviderServer is a net/rpc compatible structure for serving
// a ResourceProvider. This should not be used directly.
type ResourceProviderServer struct {
Broker *plugin.MuxBroker
Provider terraform.ResourceProvider
}
type ResourceProviderStopResponse struct {
Error *plugin.BasicError
}
type ResourceProviderGetSchemaArgs struct {
Req *terraform.ProviderSchemaRequest
}
type ResourceProviderGetSchemaResponse struct {
Schema *terraform.ProviderSchema
Error *plugin.BasicError
}
type ResourceProviderConfigureResponse struct {
Error *plugin.BasicError
}
type ResourceProviderInputArgs struct {
InputId uint32
Config *terraform.ResourceConfig
}
type ResourceProviderInputResponse struct {
Config *terraform.ResourceConfig
Error *plugin.BasicError
}
type ResourceProviderApplyArgs struct {
Info *terraform.InstanceInfo
State *terraform.InstanceState
Diff *terraform.InstanceDiff
}
type ResourceProviderApplyResponse struct {
State *terraform.InstanceState
Error *plugin.BasicError
}
type ResourceProviderDiffArgs struct {
Info *terraform.InstanceInfo
State *terraform.InstanceState
Config *terraform.ResourceConfig
}
type ResourceProviderDiffResponse struct {
Diff *terraform.InstanceDiff
Error *plugin.BasicError
}
type ResourceProviderRefreshArgs struct {
Info *terraform.InstanceInfo
State *terraform.InstanceState
}
type ResourceProviderRefreshResponse struct {
State *terraform.InstanceState
Error *plugin.BasicError
}
type ResourceProviderImportStateArgs struct {
Info *terraform.InstanceInfo
Id string
}
type ResourceProviderImportStateResponse struct {
State []*terraform.InstanceState
Error *plugin.BasicError
}
type ResourceProviderReadDataApplyArgs struct {
Info *terraform.InstanceInfo
Diff *terraform.InstanceDiff
}
type ResourceProviderReadDataApplyResponse struct {
State *terraform.InstanceState
Error *plugin.BasicError
}
type ResourceProviderReadDataDiffArgs struct {
Info *terraform.InstanceInfo
Config *terraform.ResourceConfig
}
type ResourceProviderReadDataDiffResponse struct {
Diff *terraform.InstanceDiff
Error *plugin.BasicError
}
type ResourceProviderValidateArgs struct {
Config *terraform.ResourceConfig
}
type ResourceProviderValidateResponse struct {
Warnings []string
Errors []*plugin.BasicError
}
type ResourceProviderValidateResourceArgs struct {
Config *terraform.ResourceConfig
Type string
}
type ResourceProviderValidateResourceResponse struct {
Warnings []string
Errors []*plugin.BasicError
}
func (s *ResourceProviderServer) Stop(
_ interface{},
reply *ResourceProviderStopResponse) error {
err := s.Provider.Stop()
*reply = ResourceProviderStopResponse{
Error: plugin.NewBasicError(err),
}
return nil
}
func (s *ResourceProviderServer) GetSchema(
args *ResourceProviderGetSchemaArgs,
result *ResourceProviderGetSchemaResponse,
) error {
schema, err := s.Provider.GetSchema(args.Req)
result.Schema = schema
if err != nil {
result.Error = plugin.NewBasicError(err)
}
return nil
}
func (s *ResourceProviderServer) Input(
args *ResourceProviderInputArgs,
reply *ResourceProviderInputResponse) error {
conn, err := s.Broker.Dial(args.InputId)
if err != nil {
*reply = ResourceProviderInputResponse{
Error: plugin.NewBasicError(err),
}
return nil
}
client := rpc.NewClient(conn)
defer client.Close()
input := &UIInput{Client: client}
config, err := s.Provider.Input(input, args.Config)
*reply = ResourceProviderInputResponse{
Config: config,
Error: plugin.NewBasicError(err),
}
return nil
}
func (s *ResourceProviderServer) Validate(
args *ResourceProviderValidateArgs,
reply *ResourceProviderValidateResponse) error {
warns, errs := s.Provider.Validate(args.Config)
berrs := make([]*plugin.BasicError, len(errs))
for i, err := range errs {
berrs[i] = plugin.NewBasicError(err)
}
*reply = ResourceProviderValidateResponse{
Warnings: warns,
Errors: berrs,
}
return nil
}
func (s *ResourceProviderServer) ValidateResource(
args *ResourceProviderValidateResourceArgs,
reply *ResourceProviderValidateResourceResponse) error {
warns, errs := s.Provider.ValidateResource(args.Type, args.Config)
berrs := make([]*plugin.BasicError, len(errs))
for i, err := range errs {
berrs[i] = plugin.NewBasicError(err)
}
*reply = ResourceProviderValidateResourceResponse{
Warnings: warns,
Errors: berrs,
}
return nil
}
func (s *ResourceProviderServer) Configure(
config *terraform.ResourceConfig,
reply *ResourceProviderConfigureResponse) error {
err := s.Provider.Configure(config)
*reply = ResourceProviderConfigureResponse{
Error: plugin.NewBasicError(err),
}
return nil
}
func (s *ResourceProviderServer) Apply(
args *ResourceProviderApplyArgs,
result *ResourceProviderApplyResponse) error {
state, err := s.Provider.Apply(args.Info, args.State, args.Diff)
*result = ResourceProviderApplyResponse{
State: state,
Error: plugin.NewBasicError(err),
}
return nil
}
func (s *ResourceProviderServer) Diff(
args *ResourceProviderDiffArgs,
result *ResourceProviderDiffResponse) error {
diff, err := s.Provider.Diff(args.Info, args.State, args.Config)
*result = ResourceProviderDiffResponse{
Diff: diff,
Error: plugin.NewBasicError(err),
}
return nil
}
func (s *ResourceProviderServer) Refresh(
args *ResourceProviderRefreshArgs,
result *ResourceProviderRefreshResponse) error {
newState, err := s.Provider.Refresh(args.Info, args.State)
*result = ResourceProviderRefreshResponse{
State: newState,
Error: plugin.NewBasicError(err),
}
return nil
}
func (s *ResourceProviderServer) ImportState(
args *ResourceProviderImportStateArgs,
result *ResourceProviderImportStateResponse) error {
states, err := s.Provider.ImportState(args.Info, args.Id)
*result = ResourceProviderImportStateResponse{
State: states,
Error: plugin.NewBasicError(err),
}
return nil
}
func (s *ResourceProviderServer) Resources(
nothing interface{},
result *[]terraform.ResourceType) error {
*result = s.Provider.Resources()
return nil
}
func (s *ResourceProviderServer) ValidateDataSource(
args *ResourceProviderValidateResourceArgs,
reply *ResourceProviderValidateResourceResponse) error {
warns, errs := s.Provider.ValidateDataSource(args.Type, args.Config)
berrs := make([]*plugin.BasicError, len(errs))
for i, err := range errs {
berrs[i] = plugin.NewBasicError(err)
}
*reply = ResourceProviderValidateResourceResponse{
Warnings: warns,
Errors: berrs,
}
return nil
}
func (s *ResourceProviderServer) ReadDataDiff(
args *ResourceProviderReadDataDiffArgs,
result *ResourceProviderReadDataDiffResponse) error {
diff, err := s.Provider.ReadDataDiff(args.Info, args.Config)
*result = ResourceProviderReadDataDiffResponse{
Diff: diff,
Error: plugin.NewBasicError(err),
}
return nil
}
func (s *ResourceProviderServer) ReadDataApply(
args *ResourceProviderReadDataApplyArgs,
result *ResourceProviderReadDataApplyResponse) error {
newState, err := s.Provider.ReadDataApply(args.Info, args.Diff)
*result = ResourceProviderReadDataApplyResponse{
State: newState,
Error: plugin.NewBasicError(err),
}
return nil
}
func (s *ResourceProviderServer) DataSources(
nothing interface{},
result *[]terraform.DataSource) error {
*result = s.Provider.DataSources()
return nil
}

View File

@ -1,827 +0,0 @@
package plugin
import (
"errors"
"reflect"
"testing"
"github.com/hashicorp/go-plugin"
"github.com/hashicorp/terraform/internal/legacy/terraform"
)
func TestResourceProvider_impl(t *testing.T) {
var _ plugin.Plugin = new(ResourceProviderPlugin)
var _ terraform.ResourceProvider = new(ResourceProvider)
}
func TestResourceProvider_stop(t *testing.T) {
// Create a mock provider
p := new(terraform.MockResourceProvider)
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
// Stop
e := provider.Stop()
if !p.StopCalled {
t.Fatal("stop should be called")
}
if e != nil {
t.Fatalf("bad: %#v", e)
}
}
func TestResourceProvider_stopErrors(t *testing.T) {
p := new(terraform.MockResourceProvider)
p.StopReturnError = errors.New("foo")
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
// Stop
e := provider.Stop()
if !p.StopCalled {
t.Fatal("stop should be called")
}
if e == nil {
t.Fatal("should have error")
}
if e.Error() != "foo" {
t.Fatalf("bad: %s", e)
}
}
func TestResourceProvider_input(t *testing.T) {
// Create a mock provider
p := new(terraform.MockResourceProvider)
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
input := new(terraform.MockUIInput)
expected := &terraform.ResourceConfig{
Raw: map[string]interface{}{"bar": "baz"},
}
p.InputReturnConfig = expected
// Input
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
actual, err := provider.Input(input, config)
if !p.InputCalled {
t.Fatal("input should be called")
}
if !reflect.DeepEqual(p.InputConfig, config) {
t.Fatalf("bad: %#v", p.InputConfig)
}
if err != nil {
t.Fatalf("bad: %#v", err)
}
if !reflect.DeepEqual(actual, expected) {
t.Fatalf("bad: %#v", actual)
}
}
func TestResourceProvider_configure(t *testing.T) {
// Create a mock provider
p := new(terraform.MockResourceProvider)
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
// Configure
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
e := provider.Configure(config)
if !p.ConfigureCalled {
t.Fatal("configure should be called")
}
if !reflect.DeepEqual(p.ConfigureConfig, config) {
t.Fatalf("bad: %#v", p.ConfigureConfig)
}
if e != nil {
t.Fatalf("bad: %#v", e)
}
}
func TestResourceProvider_configure_errors(t *testing.T) {
p := new(terraform.MockResourceProvider)
p.ConfigureReturnError = errors.New("foo")
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
// Configure
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
e := provider.Configure(config)
if !p.ConfigureCalled {
t.Fatal("configure should be called")
}
if !reflect.DeepEqual(p.ConfigureConfig, config) {
t.Fatalf("bad: %#v", p.ConfigureConfig)
}
if e == nil {
t.Fatal("should have error")
}
if e.Error() != "foo" {
t.Fatalf("bad: %s", e)
}
}
func TestResourceProvider_configure_warnings(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
// Configure
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
e := provider.Configure(config)
if !p.ConfigureCalled {
t.Fatal("configure should be called")
}
if !reflect.DeepEqual(p.ConfigureConfig, config) {
t.Fatalf("bad: %#v", p.ConfigureConfig)
}
if e != nil {
t.Fatalf("bad: %#v", e)
}
}
func TestResourceProvider_apply(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
p.ApplyReturn = &terraform.InstanceState{
ID: "bob",
}
// Apply
info := &terraform.InstanceInfo{}
state := &terraform.InstanceState{}
diff := &terraform.InstanceDiff{}
newState, err := provider.Apply(info, state, diff)
if !p.ApplyCalled {
t.Fatal("apply should be called")
}
if !reflect.DeepEqual(p.ApplyDiff, diff) {
t.Fatalf("bad: %#v", p.ApplyDiff)
}
if err != nil {
t.Fatalf("bad: %#v", err)
}
if !reflect.DeepEqual(p.ApplyReturn, newState) {
t.Fatalf("bad: %#v", newState)
}
}
func TestResourceProvider_diff(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
p.DiffReturn = &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"foo": &terraform.ResourceAttrDiff{
Old: "",
New: "bar",
},
},
}
// Diff
info := &terraform.InstanceInfo{}
state := &terraform.InstanceState{}
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
diff, err := provider.Diff(info, state, config)
if !p.DiffCalled {
t.Fatal("diff should be called")
}
if !reflect.DeepEqual(p.DiffDesired, config) {
t.Fatalf("bad: %#v", p.DiffDesired)
}
if err != nil {
t.Fatalf("bad: %#v", err)
}
if !reflect.DeepEqual(p.DiffReturn, diff) {
t.Fatalf("bad: %#v", diff)
}
}
func TestResourceProvider_diff_error(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
p.DiffReturnError = errors.New("foo")
// Diff
info := &terraform.InstanceInfo{}
state := &terraform.InstanceState{}
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
diff, err := provider.Diff(info, state, config)
if !p.DiffCalled {
t.Fatal("diff should be called")
}
if !reflect.DeepEqual(p.DiffDesired, config) {
t.Fatalf("bad: %#v", p.DiffDesired)
}
if err == nil {
t.Fatal("should have error")
}
if diff != nil {
t.Fatal("should not have diff")
}
}
func TestResourceProvider_refresh(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
p.RefreshReturn = &terraform.InstanceState{
ID: "bob",
}
// Refresh
info := &terraform.InstanceInfo{}
state := &terraform.InstanceState{}
newState, err := provider.Refresh(info, state)
if !p.RefreshCalled {
t.Fatal("refresh should be called")
}
if !reflect.DeepEqual(p.RefreshState, state) {
t.Fatalf("bad: %#v", p.RefreshState)
}
if err != nil {
t.Fatalf("bad: %#v", err)
}
if !reflect.DeepEqual(p.RefreshReturn, newState) {
t.Fatalf("bad: %#v", newState)
}
}
func TestResourceProvider_importState(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
p.ImportStateReturn = []*terraform.InstanceState{
&terraform.InstanceState{
ID: "bob",
},
}
// ImportState
info := &terraform.InstanceInfo{}
states, err := provider.ImportState(info, "foo")
if !p.ImportStateCalled {
t.Fatal("ImportState should be called")
}
if !reflect.DeepEqual(p.ImportStateInfo, info) {
t.Fatalf("bad: %#v", p.ImportStateInfo)
}
if err != nil {
t.Fatalf("bad: %#v", err)
}
if !reflect.DeepEqual(p.ImportStateReturn, states) {
t.Fatalf("bad: %#v", states)
}
}
func TestResourceProvider_resources(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
expected := []terraform.ResourceType{
terraform.ResourceType{Name: "foo"},
terraform.ResourceType{Name: "bar", Importable: true},
}
p.ResourcesReturn = expected
// Resources
result := provider.Resources()
if !p.ResourcesCalled {
t.Fatal("resources should be called")
}
if !reflect.DeepEqual(result, expected) {
t.Fatalf("bad: %#v", result)
}
}
func TestResourceProvider_readdataapply(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
p.ReadDataApplyReturn = &terraform.InstanceState{
ID: "bob",
}
// ReadDataApply
info := &terraform.InstanceInfo{}
diff := &terraform.InstanceDiff{}
newState, err := provider.ReadDataApply(info, diff)
if !p.ReadDataApplyCalled {
t.Fatal("ReadDataApply should be called")
}
if !reflect.DeepEqual(p.ReadDataApplyDiff, diff) {
t.Fatalf("bad: %#v", p.ReadDataApplyDiff)
}
if err != nil {
t.Fatalf("bad: %#v", err)
}
if !reflect.DeepEqual(p.ReadDataApplyReturn, newState) {
t.Fatalf("bad: %#v", newState)
}
}
func TestResourceProvider_datasources(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
expected := []terraform.DataSource{
{Name: "foo"},
{Name: "bar"},
}
p.DataSourcesReturn = expected
// DataSources
result := provider.DataSources()
if !p.DataSourcesCalled {
t.Fatal("DataSources should be called")
}
if !reflect.DeepEqual(result, expected) {
t.Fatalf("bad: %#v", result)
}
}
func TestResourceProvider_validate(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
// Configure
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
w, e := provider.Validate(config)
if !p.ValidateCalled {
t.Fatal("configure should be called")
}
if !reflect.DeepEqual(p.ValidateConfig, config) {
t.Fatalf("bad: %#v", p.ValidateConfig)
}
if w != nil {
t.Fatalf("bad: %#v", w)
}
if e != nil {
t.Fatalf("bad: %#v", e)
}
}
func TestResourceProvider_validate_errors(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
p.ValidateReturnErrors = []error{errors.New("foo")}
// Configure
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
w, e := provider.Validate(config)
if !p.ValidateCalled {
t.Fatal("configure should be called")
}
if !reflect.DeepEqual(p.ValidateConfig, config) {
t.Fatalf("bad: %#v", p.ValidateConfig)
}
if w != nil {
t.Fatalf("bad: %#v", w)
}
if len(e) != 1 {
t.Fatalf("bad: %#v", e)
}
if e[0].Error() != "foo" {
t.Fatalf("bad: %#v", e)
}
}
func TestResourceProvider_validate_warns(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
p.ValidateReturnWarns = []string{"foo"}
// Configure
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
w, e := provider.Validate(config)
if !p.ValidateCalled {
t.Fatal("configure should be called")
}
if !reflect.DeepEqual(p.ValidateConfig, config) {
t.Fatalf("bad: %#v", p.ValidateConfig)
}
if e != nil {
t.Fatalf("bad: %#v", e)
}
expected := []string{"foo"}
if !reflect.DeepEqual(w, expected) {
t.Fatalf("bad: %#v", w)
}
}
func TestResourceProvider_validateResource(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
// Configure
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
w, e := provider.ValidateResource("foo", config)
if !p.ValidateResourceCalled {
t.Fatal("configure should be called")
}
if p.ValidateResourceType != "foo" {
t.Fatalf("bad: %#v", p.ValidateResourceType)
}
if !reflect.DeepEqual(p.ValidateResourceConfig, config) {
t.Fatalf("bad: %#v", p.ValidateResourceConfig)
}
if w != nil {
t.Fatalf("bad: %#v", w)
}
if e != nil {
t.Fatalf("bad: %#v", e)
}
}
func TestResourceProvider_validateResource_errors(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
p.ValidateResourceReturnErrors = []error{errors.New("foo")}
// Configure
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
w, e := provider.ValidateResource("foo", config)
if !p.ValidateResourceCalled {
t.Fatal("configure should be called")
}
if p.ValidateResourceType != "foo" {
t.Fatalf("bad: %#v", p.ValidateResourceType)
}
if !reflect.DeepEqual(p.ValidateResourceConfig, config) {
t.Fatalf("bad: %#v", p.ValidateResourceConfig)
}
if w != nil {
t.Fatalf("bad: %#v", w)
}
if len(e) != 1 {
t.Fatalf("bad: %#v", e)
}
if e[0].Error() != "foo" {
t.Fatalf("bad: %#v", e)
}
}
func TestResourceProvider_validateResource_warns(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
p.ValidateResourceReturnWarns = []string{"foo"}
// Configure
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
w, e := provider.ValidateResource("foo", config)
if !p.ValidateResourceCalled {
t.Fatal("configure should be called")
}
if p.ValidateResourceType != "foo" {
t.Fatalf("bad: %#v", p.ValidateResourceType)
}
if !reflect.DeepEqual(p.ValidateResourceConfig, config) {
t.Fatalf("bad: %#v", p.ValidateResourceConfig)
}
if e != nil {
t.Fatalf("bad: %#v", e)
}
expected := []string{"foo"}
if !reflect.DeepEqual(w, expected) {
t.Fatalf("bad: %#v", w)
}
}
func TestResourceProvider_validateDataSource(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
// Configure
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
w, e := provider.ValidateDataSource("foo", config)
if !p.ValidateDataSourceCalled {
t.Fatal("configure should be called")
}
if p.ValidateDataSourceType != "foo" {
t.Fatalf("bad: %#v", p.ValidateDataSourceType)
}
if !reflect.DeepEqual(p.ValidateDataSourceConfig, config) {
t.Fatalf("bad: %#v", p.ValidateDataSourceConfig)
}
if w != nil {
t.Fatalf("bad: %#v", w)
}
if e != nil {
t.Fatalf("bad: %#v", e)
}
}
func TestResourceProvider_close(t *testing.T) {
p := new(terraform.MockResourceProvider)
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProviderFunc: testProviderFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProviderPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvider)
var iface interface{} = provider
pCloser, ok := iface.(terraform.ResourceProviderCloser)
if !ok {
t.Fatal("should be a ResourceProviderCloser")
}
if err := pCloser.Close(); err != nil {
t.Fatalf("failed to close provider: %s", err)
}
// The connection should be closed now, so if we to make a
// new call we should get an error.
err = provider.Configure(&terraform.ResourceConfig{})
if err == nil {
t.Fatal("should have error")
}
}

View File

@ -1,181 +0,0 @@
package plugin
import (
"net/rpc"
"github.com/hashicorp/go-plugin"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/internal/legacy/terraform"
)
// ResourceProvisionerPlugin is the plugin.Plugin implementation.
type ResourceProvisionerPlugin struct {
ResourceProvisioner func() terraform.ResourceProvisioner
}
func (p *ResourceProvisionerPlugin) Server(b *plugin.MuxBroker) (interface{}, error) {
return &ResourceProvisionerServer{
Broker: b,
Provisioner: p.ResourceProvisioner(),
}, nil
}
func (p *ResourceProvisionerPlugin) Client(
b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
return &ResourceProvisioner{Broker: b, Client: c}, nil
}
// ResourceProvisioner is an implementation of terraform.ResourceProvisioner
// that communicates over RPC.
type ResourceProvisioner struct {
Broker *plugin.MuxBroker
Client *rpc.Client
}
func (p *ResourceProvisioner) GetConfigSchema() (*configschema.Block, error) {
panic("not implemented")
}
func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) ([]string, []error) {
var resp ResourceProvisionerValidateResponse
args := ResourceProvisionerValidateArgs{
Config: c,
}
err := p.Client.Call("Plugin.Validate", &args, &resp)
if err != nil {
return nil, []error{err}
}
var errs []error
if len(resp.Errors) > 0 {
errs = make([]error, len(resp.Errors))
for i, err := range resp.Errors {
errs[i] = err
}
}
return resp.Warnings, errs
}
func (p *ResourceProvisioner) Apply(
output terraform.UIOutput,
s *terraform.InstanceState,
c *terraform.ResourceConfig) error {
id := p.Broker.NextId()
go p.Broker.AcceptAndServe(id, &UIOutputServer{
UIOutput: output,
})
var resp ResourceProvisionerApplyResponse
args := &ResourceProvisionerApplyArgs{
OutputId: id,
State: s,
Config: c,
}
err := p.Client.Call("Plugin.Apply", args, &resp)
if err != nil {
return err
}
if resp.Error != nil {
err = resp.Error
}
return err
}
func (p *ResourceProvisioner) Stop() error {
var resp ResourceProvisionerStopResponse
err := p.Client.Call("Plugin.Stop", new(interface{}), &resp)
if err != nil {
return err
}
if resp.Error != nil {
err = resp.Error
}
return err
}
func (p *ResourceProvisioner) Close() error {
return p.Client.Close()
}
type ResourceProvisionerValidateArgs struct {
Config *terraform.ResourceConfig
}
type ResourceProvisionerValidateResponse struct {
Warnings []string
Errors []*plugin.BasicError
}
type ResourceProvisionerApplyArgs struct {
OutputId uint32
State *terraform.InstanceState
Config *terraform.ResourceConfig
}
type ResourceProvisionerApplyResponse struct {
Error *plugin.BasicError
}
type ResourceProvisionerStopResponse struct {
Error *plugin.BasicError
}
// ResourceProvisionerServer is a net/rpc compatible structure for serving
// a ResourceProvisioner. This should not be used directly.
type ResourceProvisionerServer struct {
Broker *plugin.MuxBroker
Provisioner terraform.ResourceProvisioner
}
func (s *ResourceProvisionerServer) Apply(
args *ResourceProvisionerApplyArgs,
result *ResourceProvisionerApplyResponse) error {
conn, err := s.Broker.Dial(args.OutputId)
if err != nil {
*result = ResourceProvisionerApplyResponse{
Error: plugin.NewBasicError(err),
}
return nil
}
client := rpc.NewClient(conn)
defer client.Close()
output := &UIOutput{Client: client}
err = s.Provisioner.Apply(output, args.State, args.Config)
*result = ResourceProvisionerApplyResponse{
Error: plugin.NewBasicError(err),
}
return nil
}
func (s *ResourceProvisionerServer) Validate(
args *ResourceProvisionerValidateArgs,
reply *ResourceProvisionerValidateResponse) error {
warns, errs := s.Provisioner.Validate(args.Config)
berrs := make([]*plugin.BasicError, len(errs))
for i, err := range errs {
berrs[i] = plugin.NewBasicError(err)
}
*reply = ResourceProvisionerValidateResponse{
Warnings: warns,
Errors: berrs,
}
return nil
}
func (s *ResourceProvisionerServer) Stop(
_ interface{},
reply *ResourceProvisionerStopResponse) error {
err := s.Provisioner.Stop()
*reply = ResourceProvisionerStopResponse{
Error: plugin.NewBasicError(err),
}
return nil
}

View File

@ -1,248 +0,0 @@
package plugin
import (
"errors"
"reflect"
"testing"
"github.com/hashicorp/go-plugin"
"github.com/hashicorp/terraform/internal/legacy/terraform"
)
func TestResourceProvisioner_impl(t *testing.T) {
var _ plugin.Plugin = new(ResourceProvisionerPlugin)
var _ terraform.ResourceProvisioner = new(ResourceProvisioner)
}
func TestResourceProvisioner_stop(t *testing.T) {
// Create a mock provider
p := new(terraform.MockResourceProvisioner)
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProvisionerFunc: testProvisionerFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProvisionerPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvisioner)
// Stop
e := provider.Stop()
if !p.StopCalled {
t.Fatal("stop should be called")
}
if e != nil {
t.Fatalf("bad: %#v", e)
}
}
func TestResourceProvisioner_stopErrors(t *testing.T) {
p := new(terraform.MockResourceProvisioner)
p.StopReturnError = errors.New("foo")
// Create a mock provider
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProvisionerFunc: testProvisionerFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProvisionerPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provider := raw.(terraform.ResourceProvisioner)
// Stop
e := provider.Stop()
if !p.StopCalled {
t.Fatal("stop should be called")
}
if e == nil {
t.Fatal("should have error")
}
if e.Error() != "foo" {
t.Fatalf("bad: %s", e)
}
}
func TestResourceProvisioner_apply(t *testing.T) {
// Create a mock provider
p := new(terraform.MockResourceProvisioner)
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProvisionerFunc: testProvisionerFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProvisionerPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provisioner := raw.(terraform.ResourceProvisioner)
// Apply
output := &terraform.MockUIOutput{}
state := &terraform.InstanceState{}
conf := &terraform.ResourceConfig{}
err = provisioner.Apply(output, state, conf)
if !p.ApplyCalled {
t.Fatal("apply should be called")
}
if !reflect.DeepEqual(p.ApplyConfig, conf) {
t.Fatalf("bad: %#v", p.ApplyConfig)
}
if err != nil {
t.Fatalf("bad: %#v", err)
}
}
func TestResourceProvisioner_validate(t *testing.T) {
// Create a mock provider
p := new(terraform.MockResourceProvisioner)
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProvisionerFunc: testProvisionerFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProvisionerPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provisioner := raw.(terraform.ResourceProvisioner)
// Configure
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
w, e := provisioner.Validate(config)
if !p.ValidateCalled {
t.Fatal("configure should be called")
}
if !reflect.DeepEqual(p.ValidateConfig, config) {
t.Fatalf("bad: %#v", p.ValidateConfig)
}
if w != nil {
t.Fatalf("bad: %#v", w)
}
if e != nil {
t.Fatalf("bad: %#v", e)
}
}
func TestResourceProvisioner_validate_errors(t *testing.T) {
// Create a mock provider
p := new(terraform.MockResourceProvisioner)
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProvisionerFunc: testProvisionerFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProvisionerPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provisioner := raw.(terraform.ResourceProvisioner)
p.ValidateReturnErrors = []error{errors.New("foo")}
// Configure
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
w, e := provisioner.Validate(config)
if !p.ValidateCalled {
t.Fatal("configure should be called")
}
if !reflect.DeepEqual(p.ValidateConfig, config) {
t.Fatalf("bad: %#v", p.ValidateConfig)
}
if w != nil {
t.Fatalf("bad: %#v", w)
}
if len(e) != 1 {
t.Fatalf("bad: %#v", e)
}
if e[0].Error() != "foo" {
t.Fatalf("bad: %#v", e)
}
}
func TestResourceProvisioner_validate_warns(t *testing.T) {
// Create a mock provider
p := new(terraform.MockResourceProvisioner)
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProvisionerFunc: testProvisionerFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProvisionerPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provisioner := raw.(terraform.ResourceProvisioner)
p.ValidateReturnWarns = []string{"foo"}
// Configure
config := &terraform.ResourceConfig{
Raw: map[string]interface{}{"foo": "bar"},
}
w, e := provisioner.Validate(config)
if !p.ValidateCalled {
t.Fatal("configure should be called")
}
if !reflect.DeepEqual(p.ValidateConfig, config) {
t.Fatalf("bad: %#v", p.ValidateConfig)
}
if e != nil {
t.Fatalf("bad: %#v", e)
}
expected := []string{"foo"}
if !reflect.DeepEqual(w, expected) {
t.Fatalf("bad: %#v", w)
}
}
func TestResourceProvisioner_close(t *testing.T) {
// Create a mock provider
p := new(terraform.MockResourceProvisioner)
client, _ := plugin.TestPluginRPCConn(t, legacyPluginMap(&ServeOpts{
ProvisionerFunc: testProvisionerFixed(p),
}), nil)
defer client.Close()
// Request the provider
raw, err := client.Dispense(ProvisionerPluginName)
if err != nil {
t.Fatalf("err: %s", err)
}
provisioner := raw.(terraform.ResourceProvisioner)
pCloser, ok := raw.(terraform.ResourceProvisionerCloser)
if !ok {
t.Fatal("should be a ResourceProvisionerCloser")
}
if err := pCloser.Close(); err != nil {
t.Fatalf("failed to close provisioner: %s", err)
}
// The connection should be closed now, so if we to make a
// new call we should get an error.
o := &terraform.MockUIOutput{}
s := &terraform.InstanceState{}
c := &terraform.ResourceConfig{}
err = provisioner.Apply(o, s, c)
if err == nil {
t.Fatal("should have error")
}
}

View File

@ -2,8 +2,6 @@ package plugin
import ( import (
"github.com/hashicorp/go-plugin" "github.com/hashicorp/go-plugin"
grpcplugin "github.com/hashicorp/terraform/internal/legacy/helper/plugin"
"github.com/hashicorp/terraform/internal/legacy/terraform"
proto "github.com/hashicorp/terraform/internal/tfplugin5" proto "github.com/hashicorp/terraform/internal/tfplugin5"
) )
@ -35,16 +33,11 @@ var Handshake = plugin.HandshakeConfig{
MagicCookieValue: "d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2", MagicCookieValue: "d602bf8f470bc67ca7faa0386276bbdd4330efaf76d1a219cb4d6991ca9872b2",
} }
type ProviderFunc func() terraform.ResourceProvider
type ProvisionerFunc func() terraform.ResourceProvisioner
type GRPCProviderFunc func() proto.ProviderServer type GRPCProviderFunc func() proto.ProviderServer
type GRPCProvisionerFunc func() proto.ProvisionerServer type GRPCProvisionerFunc func() proto.ProvisionerServer
// ServeOpts are the configurations to serve a plugin. // ServeOpts are the configurations to serve a plugin.
type ServeOpts struct { type ServeOpts struct {
ProviderFunc ProviderFunc
ProvisionerFunc ProvisionerFunc
// Wrapped versions of the above plugins will automatically shimmed and // Wrapped versions of the above plugins will automatically shimmed and
// added to the GRPC functions when possible. // added to the GRPC functions when possible.
GRPCProviderFunc GRPCProviderFunc GRPCProviderFunc GRPCProviderFunc
@ -54,27 +47,6 @@ type ServeOpts struct {
// Serve serves a plugin. This function never returns and should be the final // Serve serves a plugin. This function never returns and should be the final
// function called in the main function of the plugin. // function called in the main function of the plugin.
func Serve(opts *ServeOpts) { func Serve(opts *ServeOpts) {
// since the plugins may not yet be aware of the new protocol, we
// automatically wrap the plugins in the grpc shims.
if opts.GRPCProviderFunc == nil && opts.ProviderFunc != nil {
provider := grpcplugin.NewGRPCProviderServerShim(opts.ProviderFunc())
// this is almost always going to be a *schema.Provider, but check that
// we got back a valid provider just in case.
if provider != nil {
opts.GRPCProviderFunc = func() proto.ProviderServer {
return provider
}
}
}
if opts.GRPCProvisionerFunc == nil && opts.ProvisionerFunc != nil {
provisioner := grpcplugin.NewGRPCProvisionerServerShim(opts.ProvisionerFunc())
if provisioner != nil {
opts.GRPCProvisionerFunc = func() proto.ProvisionerServer {
return provisioner
}
}
}
plugin.Serve(&plugin.ServeConfig{ plugin.Serve(&plugin.ServeConfig{
HandshakeConfig: Handshake, HandshakeConfig: Handshake,
VersionedPlugins: pluginSet(opts), VersionedPlugins: pluginSet(opts),
@ -82,26 +54,8 @@ func Serve(opts *ServeOpts) {
}) })
} }
// pluginMap returns the legacy map[string]plugin.Plugin to use for configuring
// a plugin server or client.
func legacyPluginMap(opts *ServeOpts) map[string]plugin.Plugin {
return map[string]plugin.Plugin{
"provider": &ResourceProviderPlugin{
ResourceProvider: opts.ProviderFunc,
},
"provisioner": &ResourceProvisionerPlugin{
ResourceProvisioner: opts.ProvisionerFunc,
},
}
}
func pluginSet(opts *ServeOpts) map[int]plugin.PluginSet { func pluginSet(opts *ServeOpts) map[int]plugin.PluginSet {
// Set the legacy netrpc plugins at version 4. plugins := map[int]plugin.PluginSet{}
// The oldest version is returned in when executed by a legacy go-plugin
// client.
plugins := map[int]plugin.PluginSet{
4: legacyPluginMap(opts),
}
// add the new protocol versions if they're configured // add the new protocol versions if they're configured
if opts.GRPCProviderFunc != nil || opts.GRPCProvisionerFunc != nil { if opts.GRPCProviderFunc != nil || opts.GRPCProvisionerFunc != nil {