update to start a new process for each plugin

Modify the plugin factories to create a new plugin process for each
individual plugin.
This commit is contained in:
James Bardin 2018-10-02 16:06:12 -04:00 committed by Martin Atkins
parent 35b375d3ee
commit 795161f615
4 changed files with 64 additions and 29 deletions

View File

@ -84,8 +84,7 @@ func (r *multiVersionProviderResolver) ResolveProviders(
continue continue
} }
client := tfplugin.Client(newest) factories[name] = providerFactory(newest)
factories[name] = providerFactory(client)
} else { } else {
msg := fmt.Sprintf("provider.%s: no suitable version installed", name) msg := fmt.Sprintf("provider.%s: no suitable version installed", name)
@ -332,7 +331,7 @@ func (m *Meta) provisionerFactories() map[string]terraform.ProvisionerFactory {
log.Printf("[WARN] failed to build command line for internal plugin %q: %s", name, err) log.Printf("[WARN] failed to build command line for internal plugin %q: %s", name, err)
continue continue
} }
factories[name] = provisionerFactory(client) factories[name] = internalProvisionerFactory(client)
} }
byName := plugins.ByName() byName := plugins.ByName()
@ -341,8 +340,8 @@ func (m *Meta) provisionerFactories() map[string]terraform.ProvisionerFactory {
// by name, we're guaranteed that the metas in our set all have // by name, we're guaranteed that the metas in our set all have
// valid versions and that there's at least one meta. // valid versions and that there's at least one meta.
newest := metas.Newest() newest := metas.Newest()
client := tfplugin.Client(newest)
factories[name] = provisionerFactory(client) factories[name] = provisionerFactory(newest)
} }
return factories return factories
@ -369,8 +368,9 @@ func internalPluginClient(kind, name string) (*plugin.Client, error) {
return plugin.NewClient(cfg), nil return plugin.NewClient(cfg), nil
} }
func providerFactory(client *plugin.Client) providers.Factory { func providerFactory(meta discovery.PluginMeta) providers.Factory {
return func() (providers.Interface, error) { return func() (providers.Interface, error) {
client := tfplugin.Client(meta)
// Request the RPC client so we can get the provider // Request the RPC client so we can get the provider
// so we can build the actual RPC-implemented provider. // so we can build the actual RPC-implemented provider.
rpcClient, err := client.Client() rpcClient, err := client.Client()
@ -383,12 +383,27 @@ func providerFactory(client *plugin.Client) providers.Factory {
return nil, err return nil, err
} }
return raw.(providers.Interface), nil // store the client so that the plugin can kill the child process
p := raw.(*tfplugin.GRPCProvider)
p.PluginClient = client
return p, nil
} }
} }
func provisionerFactory(client *plugin.Client) terraform.ProvisionerFactory { func provisionerFactory(meta discovery.PluginMeta) terraform.ProvisionerFactory {
return func() (provisioners.Interface, error) { return func() (provisioners.Interface, error) {
client := tfplugin.Client(meta)
return newProvisionerClient(client)
}
}
func internalProvisionerFactory(client *plugin.Client) terraform.ProvisionerFactory {
return func() (provisioners.Interface, error) {
return newProvisionerClient(client)
}
}
func newProvisionerClient(client *plugin.Client) (provisioners.Interface, error) {
// Request the RPC client so we can get the provisioner // Request the RPC client so we can get the provisioner
// so we can build the actual RPC-implemented provisioner. // so we can build the actual RPC-implemented provisioner.
rpcClient, err := client.Client() rpcClient, err := client.Client()
@ -401,6 +416,8 @@ func provisionerFactory(client *plugin.Client) terraform.ProvisionerFactory {
return nil, err return nil, err
} }
return raw.(provisioners.Interface), nil // store the client so that the plugin can kill the child process
} p := raw.(*tfplugin.GRPCProvisioner)
p.PluginClient = client
return p, nil
} }

View File

@ -25,7 +25,6 @@ type GRPCProviderPlugin struct {
func (p *GRPCProviderPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) { func (p *GRPCProviderPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
return &GRPCProvider{ return &GRPCProvider{
conn: c,
client: proto.NewProviderClient(c), client: proto.NewProviderClient(c),
ctx: ctx, ctx: ctx,
}, nil }, nil
@ -41,7 +40,11 @@ func (p *GRPCProviderPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Serve
// terraform provioders types and the grpc proto types, directly converting // terraform provioders types and the grpc proto types, directly converting
// between the two. // between the two.
type GRPCProvider struct { type GRPCProvider struct {
conn *grpc.ClientConn // PluginClient provides a reference to the plugin.Client which controls the plugin process.
// This allows the GRPCProvider a way to shutdown the plugin process.
PluginClient *plugin.Client
// Proto client use to make the grpc service calls.
client proto.ProviderClient client proto.ProviderClient
// this context is created by the plugin package, and is canceled when the // this context is created by the plugin package, and is canceled when the
@ -495,8 +498,13 @@ func (p *GRPCProvider) ReadDataSource(r providers.ReadDataSourceRequest) (resp p
} }
// closing the grpc connection is final, and terraform will call it at the end of every phase. // closing the grpc connection is final, and terraform will call it at the end of every phase.
// FIXME: do we need this, and if so, how do we fix it?
func (p *GRPCProvider) Close() error { func (p *GRPCProvider) Close() error {
log.Printf("[TRACE] GRPCProvider: Close") // check this since it's not automatically inserted during plugin creation
if p.PluginClient == nil {
log.Println("[DEBUG] provider has no plugin.Client")
return nil
}
p.PluginClient.Kill()
return nil return nil
} }

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"io" "io"
"log"
"sync" "sync"
plugin "github.com/hashicorp/go-plugin" plugin "github.com/hashicorp/go-plugin"
@ -24,7 +25,6 @@ type GRPCProvisionerPlugin struct {
func (p *GRPCProvisionerPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) { func (p *GRPCProvisionerPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
return &GRPCProvisioner{ return &GRPCProvisioner{
conn: c,
client: proto.NewProvisionerClient(c), client: proto.NewProvisionerClient(c),
ctx: ctx, ctx: ctx,
}, nil }, nil
@ -37,7 +37,10 @@ func (p *GRPCProvisionerPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Se
// provisioners.Interface grpc implementation // provisioners.Interface grpc implementation
type GRPCProvisioner struct { type GRPCProvisioner struct {
conn *grpc.ClientConn // PluginClient provides a reference to the plugin.Client which controls the plugin process.
// This allows the GRPCProvider a way to shutdown the plugin process.
PluginClient *plugin.Client
client proto.ProvisionerClient client proto.ProvisionerClient
ctx context.Context ctx context.Context
@ -163,5 +166,12 @@ func (p *GRPCProvisioner) Stop() error {
} }
func (p *GRPCProvisioner) Close() error { func (p *GRPCProvisioner) Close() error {
// check this since it's not automatically inserted during plugin creation
if p.PluginClient == nil {
log.Println("[DEBUG] provider has no plugin.Client")
return nil
}
p.PluginClient.Kill()
return nil return nil
} }

View File

@ -33,7 +33,7 @@ type basicComponentFactory struct {
func (c *basicComponentFactory) ResourceProviders() []string { func (c *basicComponentFactory) ResourceProviders() []string {
result := make([]string, len(c.providers)) result := make([]string, len(c.providers))
for k, _ := range c.providers { for k := range c.providers {
result = append(result, k) result = append(result, k)
} }
@ -42,7 +42,7 @@ func (c *basicComponentFactory) ResourceProviders() []string {
func (c *basicComponentFactory) ResourceProvisioners() []string { func (c *basicComponentFactory) ResourceProvisioners() []string {
result := make([]string, len(c.provisioners)) result := make([]string, len(c.provisioners))
for k, _ := range c.provisioners { for k := range c.provisioners {
result = append(result, k) result = append(result, k)
} }