github.com/skyscape-cloud-services/terraform@v0.9.2-0.20170609144644-7ece028a1747/plugin/resource_provisioner.go (about)

     1  package plugin
     2  
     3  import (
     4  	"net/rpc"
     5  
     6  	"github.com/hashicorp/go-plugin"
     7  	"github.com/hashicorp/terraform/terraform"
     8  )
     9  
    10  // ResourceProvisionerPlugin is the plugin.Plugin implementation.
    11  type ResourceProvisionerPlugin struct {
    12  	F func() terraform.ResourceProvisioner
    13  }
    14  
    15  func (p *ResourceProvisionerPlugin) Server(b *plugin.MuxBroker) (interface{}, error) {
    16  	return &ResourceProvisionerServer{Broker: b, Provisioner: p.F()}, nil
    17  }
    18  
    19  func (p *ResourceProvisionerPlugin) Client(
    20  	b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
    21  	return &ResourceProvisioner{Broker: b, Client: c}, nil
    22  }
    23  
    24  // ResourceProvisioner is an implementation of terraform.ResourceProvisioner
    25  // that communicates over RPC.
    26  type ResourceProvisioner struct {
    27  	Broker *plugin.MuxBroker
    28  	Client *rpc.Client
    29  }
    30  
    31  func (p *ResourceProvisioner) Validate(c *terraform.ResourceConfig) ([]string, []error) {
    32  	var resp ResourceProvisionerValidateResponse
    33  	args := ResourceProvisionerValidateArgs{
    34  		Config: c,
    35  	}
    36  
    37  	err := p.Client.Call("Plugin.Validate", &args, &resp)
    38  	if err != nil {
    39  		return nil, []error{err}
    40  	}
    41  
    42  	var errs []error
    43  	if len(resp.Errors) > 0 {
    44  		errs = make([]error, len(resp.Errors))
    45  		for i, err := range resp.Errors {
    46  			errs[i] = err
    47  		}
    48  	}
    49  
    50  	return resp.Warnings, errs
    51  }
    52  
    53  func (p *ResourceProvisioner) Apply(
    54  	output terraform.UIOutput,
    55  	s *terraform.InstanceState,
    56  	c *terraform.ResourceConfig) error {
    57  	id := p.Broker.NextId()
    58  	go p.Broker.AcceptAndServe(id, &UIOutputServer{
    59  		UIOutput: output,
    60  	})
    61  
    62  	var resp ResourceProvisionerApplyResponse
    63  	args := &ResourceProvisionerApplyArgs{
    64  		OutputId: id,
    65  		State:    s,
    66  		Config:   c,
    67  	}
    68  
    69  	err := p.Client.Call("Plugin.Apply", args, &resp)
    70  	if err != nil {
    71  		return err
    72  	}
    73  	if resp.Error != nil {
    74  		err = resp.Error
    75  	}
    76  
    77  	return err
    78  }
    79  
    80  func (p *ResourceProvisioner) Stop() error {
    81  	var resp ResourceProvisionerStopResponse
    82  	err := p.Client.Call("Plugin.Stop", new(interface{}), &resp)
    83  	if err != nil {
    84  		return err
    85  	}
    86  	if resp.Error != nil {
    87  		err = resp.Error
    88  	}
    89  
    90  	return err
    91  }
    92  
    93  func (p *ResourceProvisioner) Close() error {
    94  	return p.Client.Close()
    95  }
    96  
    97  type ResourceProvisionerValidateArgs struct {
    98  	Config *terraform.ResourceConfig
    99  }
   100  
   101  type ResourceProvisionerValidateResponse struct {
   102  	Warnings []string
   103  	Errors   []*plugin.BasicError
   104  }
   105  
   106  type ResourceProvisionerApplyArgs struct {
   107  	OutputId uint32
   108  	State    *terraform.InstanceState
   109  	Config   *terraform.ResourceConfig
   110  }
   111  
   112  type ResourceProvisionerApplyResponse struct {
   113  	Error *plugin.BasicError
   114  }
   115  
   116  type ResourceProvisionerStopResponse struct {
   117  	Error *plugin.BasicError
   118  }
   119  
   120  // ResourceProvisionerServer is a net/rpc compatible structure for serving
   121  // a ResourceProvisioner. This should not be used directly.
   122  type ResourceProvisionerServer struct {
   123  	Broker      *plugin.MuxBroker
   124  	Provisioner terraform.ResourceProvisioner
   125  }
   126  
   127  func (s *ResourceProvisionerServer) Apply(
   128  	args *ResourceProvisionerApplyArgs,
   129  	result *ResourceProvisionerApplyResponse) error {
   130  	conn, err := s.Broker.Dial(args.OutputId)
   131  	if err != nil {
   132  		*result = ResourceProvisionerApplyResponse{
   133  			Error: plugin.NewBasicError(err),
   134  		}
   135  		return nil
   136  	}
   137  	client := rpc.NewClient(conn)
   138  	defer client.Close()
   139  
   140  	output := &UIOutput{Client: client}
   141  
   142  	err = s.Provisioner.Apply(output, args.State, args.Config)
   143  	*result = ResourceProvisionerApplyResponse{
   144  		Error: plugin.NewBasicError(err),
   145  	}
   146  	return nil
   147  }
   148  
   149  func (s *ResourceProvisionerServer) Validate(
   150  	args *ResourceProvisionerValidateArgs,
   151  	reply *ResourceProvisionerValidateResponse) error {
   152  	warns, errs := s.Provisioner.Validate(args.Config)
   153  	berrs := make([]*plugin.BasicError, len(errs))
   154  	for i, err := range errs {
   155  		berrs[i] = plugin.NewBasicError(err)
   156  	}
   157  	*reply = ResourceProvisionerValidateResponse{
   158  		Warnings: warns,
   159  		Errors:   berrs,
   160  	}
   161  	return nil
   162  }
   163  
   164  func (s *ResourceProvisionerServer) Stop(
   165  	_ interface{},
   166  	reply *ResourceProvisionerStopResponse) error {
   167  	err := s.Provisioner.Stop()
   168  	*reply = ResourceProvisionerStopResponse{
   169  		Error: plugin.NewBasicError(err),
   170  	}
   171  
   172  	return nil
   173  }