github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/plugin/resource_provider.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  // ResourceProviderPlugin is the plugin.Plugin implementation.
    11  type ResourceProviderPlugin struct {
    12  	F func() terraform.ResourceProvider
    13  }
    14  
    15  func (p *ResourceProviderPlugin) Server(b *plugin.MuxBroker) (interface{}, error) {
    16  	return &ResourceProviderServer{Broker: b, Provider: p.F()}, nil
    17  }
    18  
    19  func (p *ResourceProviderPlugin) Client(
    20  	b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
    21  	return &ResourceProvider{Broker: b, Client: c}, nil
    22  }
    23  
    24  // ResourceProvider is an implementation of terraform.ResourceProvider
    25  // that communicates over RPC.
    26  type ResourceProvider struct {
    27  	Broker *plugin.MuxBroker
    28  	Client *rpc.Client
    29  }
    30  
    31  func (p *ResourceProvider) Stop() error {
    32  	var resp ResourceProviderStopResponse
    33  	err := p.Client.Call("Plugin.Stop", new(interface{}), &resp)
    34  	if err != nil {
    35  		return err
    36  	}
    37  	if resp.Error != nil {
    38  		err = resp.Error
    39  	}
    40  
    41  	return err
    42  }
    43  
    44  func (p *ResourceProvider) Input(
    45  	input terraform.UIInput,
    46  	c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) {
    47  	id := p.Broker.NextId()
    48  	go p.Broker.AcceptAndServe(id, &UIInputServer{
    49  		UIInput: input,
    50  	})
    51  
    52  	var resp ResourceProviderInputResponse
    53  	args := ResourceProviderInputArgs{
    54  		InputId: id,
    55  		Config:  c,
    56  	}
    57  
    58  	err := p.Client.Call("Plugin.Input", &args, &resp)
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	if resp.Error != nil {
    63  		err = resp.Error
    64  		return nil, err
    65  	}
    66  
    67  	return resp.Config, nil
    68  }
    69  
    70  func (p *ResourceProvider) Validate(c *terraform.ResourceConfig) ([]string, []error) {
    71  	var resp ResourceProviderValidateResponse
    72  	args := ResourceProviderValidateArgs{
    73  		Config: c,
    74  	}
    75  
    76  	err := p.Client.Call("Plugin.Validate", &args, &resp)
    77  	if err != nil {
    78  		return nil, []error{err}
    79  	}
    80  
    81  	var errs []error
    82  	if len(resp.Errors) > 0 {
    83  		errs = make([]error, len(resp.Errors))
    84  		for i, err := range resp.Errors {
    85  			errs[i] = err
    86  		}
    87  	}
    88  
    89  	return resp.Warnings, errs
    90  }
    91  
    92  func (p *ResourceProvider) ValidateResource(
    93  	t string, c *terraform.ResourceConfig) ([]string, []error) {
    94  	var resp ResourceProviderValidateResourceResponse
    95  	args := ResourceProviderValidateResourceArgs{
    96  		Config: c,
    97  		Type:   t,
    98  	}
    99  
   100  	err := p.Client.Call("Plugin.ValidateResource", &args, &resp)
   101  	if err != nil {
   102  		return nil, []error{err}
   103  	}
   104  
   105  	var errs []error
   106  	if len(resp.Errors) > 0 {
   107  		errs = make([]error, len(resp.Errors))
   108  		for i, err := range resp.Errors {
   109  			errs[i] = err
   110  		}
   111  	}
   112  
   113  	return resp.Warnings, errs
   114  }
   115  
   116  func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error {
   117  	var resp ResourceProviderConfigureResponse
   118  	err := p.Client.Call("Plugin.Configure", c, &resp)
   119  	if err != nil {
   120  		return err
   121  	}
   122  	if resp.Error != nil {
   123  		err = resp.Error
   124  	}
   125  
   126  	return err
   127  }
   128  
   129  func (p *ResourceProvider) Apply(
   130  	info *terraform.InstanceInfo,
   131  	s *terraform.InstanceState,
   132  	d *terraform.InstanceDiff) (*terraform.InstanceState, error) {
   133  	var resp ResourceProviderApplyResponse
   134  	args := &ResourceProviderApplyArgs{
   135  		Info:  info,
   136  		State: s,
   137  		Diff:  d,
   138  	}
   139  
   140  	err := p.Client.Call("Plugin.Apply", args, &resp)
   141  	if err != nil {
   142  		return nil, err
   143  	}
   144  	if resp.Error != nil {
   145  		err = resp.Error
   146  	}
   147  
   148  	return resp.State, err
   149  }
   150  
   151  func (p *ResourceProvider) Diff(
   152  	info *terraform.InstanceInfo,
   153  	s *terraform.InstanceState,
   154  	c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
   155  	var resp ResourceProviderDiffResponse
   156  	args := &ResourceProviderDiffArgs{
   157  		Info:   info,
   158  		State:  s,
   159  		Config: c,
   160  	}
   161  	err := p.Client.Call("Plugin.Diff", args, &resp)
   162  	if err != nil {
   163  		return nil, err
   164  	}
   165  	if resp.Error != nil {
   166  		err = resp.Error
   167  	}
   168  
   169  	return resp.Diff, err
   170  }
   171  
   172  func (p *ResourceProvider) ValidateDataSource(
   173  	t string, c *terraform.ResourceConfig) ([]string, []error) {
   174  	var resp ResourceProviderValidateResourceResponse
   175  	args := ResourceProviderValidateResourceArgs{
   176  		Config: c,
   177  		Type:   t,
   178  	}
   179  
   180  	err := p.Client.Call("Plugin.ValidateDataSource", &args, &resp)
   181  	if err != nil {
   182  		return nil, []error{err}
   183  	}
   184  
   185  	var errs []error
   186  	if len(resp.Errors) > 0 {
   187  		errs = make([]error, len(resp.Errors))
   188  		for i, err := range resp.Errors {
   189  			errs[i] = err
   190  		}
   191  	}
   192  
   193  	return resp.Warnings, errs
   194  }
   195  
   196  func (p *ResourceProvider) Refresh(
   197  	info *terraform.InstanceInfo,
   198  	s *terraform.InstanceState) (*terraform.InstanceState, error) {
   199  	var resp ResourceProviderRefreshResponse
   200  	args := &ResourceProviderRefreshArgs{
   201  		Info:  info,
   202  		State: s,
   203  	}
   204  
   205  	err := p.Client.Call("Plugin.Refresh", args, &resp)
   206  	if err != nil {
   207  		return nil, err
   208  	}
   209  	if resp.Error != nil {
   210  		err = resp.Error
   211  	}
   212  
   213  	return resp.State, err
   214  }
   215  
   216  func (p *ResourceProvider) ImportState(
   217  	info *terraform.InstanceInfo,
   218  	id string) ([]*terraform.InstanceState, error) {
   219  	var resp ResourceProviderImportStateResponse
   220  	args := &ResourceProviderImportStateArgs{
   221  		Info: info,
   222  		Id:   id,
   223  	}
   224  
   225  	err := p.Client.Call("Plugin.ImportState", args, &resp)
   226  	if err != nil {
   227  		return nil, err
   228  	}
   229  	if resp.Error != nil {
   230  		err = resp.Error
   231  	}
   232  
   233  	return resp.State, err
   234  }
   235  
   236  func (p *ResourceProvider) Resources() []terraform.ResourceType {
   237  	var result []terraform.ResourceType
   238  
   239  	err := p.Client.Call("Plugin.Resources", new(interface{}), &result)
   240  	if err != nil {
   241  		// TODO: panic, log, what?
   242  		return nil
   243  	}
   244  
   245  	return result
   246  }
   247  
   248  func (p *ResourceProvider) ReadDataDiff(
   249  	info *terraform.InstanceInfo,
   250  	c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
   251  	var resp ResourceProviderReadDataDiffResponse
   252  	args := &ResourceProviderReadDataDiffArgs{
   253  		Info:   info,
   254  		Config: c,
   255  	}
   256  
   257  	err := p.Client.Call("Plugin.ReadDataDiff", args, &resp)
   258  	if err != nil {
   259  		return nil, err
   260  	}
   261  	if resp.Error != nil {
   262  		err = resp.Error
   263  	}
   264  
   265  	return resp.Diff, err
   266  }
   267  
   268  func (p *ResourceProvider) ReadDataApply(
   269  	info *terraform.InstanceInfo,
   270  	d *terraform.InstanceDiff) (*terraform.InstanceState, error) {
   271  	var resp ResourceProviderReadDataApplyResponse
   272  	args := &ResourceProviderReadDataApplyArgs{
   273  		Info: info,
   274  		Diff: d,
   275  	}
   276  
   277  	err := p.Client.Call("Plugin.ReadDataApply", args, &resp)
   278  	if err != nil {
   279  		return nil, err
   280  	}
   281  	if resp.Error != nil {
   282  		err = resp.Error
   283  	}
   284  
   285  	return resp.State, err
   286  }
   287  
   288  func (p *ResourceProvider) DataSources() []terraform.DataSource {
   289  	var result []terraform.DataSource
   290  
   291  	err := p.Client.Call("Plugin.DataSources", new(interface{}), &result)
   292  	if err != nil {
   293  		// TODO: panic, log, what?
   294  		return nil
   295  	}
   296  
   297  	return result
   298  }
   299  
   300  func (p *ResourceProvider) Close() error {
   301  	return p.Client.Close()
   302  }
   303  
   304  // ResourceProviderServer is a net/rpc compatible structure for serving
   305  // a ResourceProvider. This should not be used directly.
   306  type ResourceProviderServer struct {
   307  	Broker   *plugin.MuxBroker
   308  	Provider terraform.ResourceProvider
   309  }
   310  
   311  type ResourceProviderStopResponse struct {
   312  	Error *plugin.BasicError
   313  }
   314  
   315  type ResourceProviderConfigureResponse struct {
   316  	Error *plugin.BasicError
   317  }
   318  
   319  type ResourceProviderInputArgs struct {
   320  	InputId uint32
   321  	Config  *terraform.ResourceConfig
   322  }
   323  
   324  type ResourceProviderInputResponse struct {
   325  	Config *terraform.ResourceConfig
   326  	Error  *plugin.BasicError
   327  }
   328  
   329  type ResourceProviderApplyArgs struct {
   330  	Info  *terraform.InstanceInfo
   331  	State *terraform.InstanceState
   332  	Diff  *terraform.InstanceDiff
   333  }
   334  
   335  type ResourceProviderApplyResponse struct {
   336  	State *terraform.InstanceState
   337  	Error *plugin.BasicError
   338  }
   339  
   340  type ResourceProviderDiffArgs struct {
   341  	Info   *terraform.InstanceInfo
   342  	State  *terraform.InstanceState
   343  	Config *terraform.ResourceConfig
   344  }
   345  
   346  type ResourceProviderDiffResponse struct {
   347  	Diff  *terraform.InstanceDiff
   348  	Error *plugin.BasicError
   349  }
   350  
   351  type ResourceProviderRefreshArgs struct {
   352  	Info  *terraform.InstanceInfo
   353  	State *terraform.InstanceState
   354  }
   355  
   356  type ResourceProviderRefreshResponse struct {
   357  	State *terraform.InstanceState
   358  	Error *plugin.BasicError
   359  }
   360  
   361  type ResourceProviderImportStateArgs struct {
   362  	Info *terraform.InstanceInfo
   363  	Id   string
   364  }
   365  
   366  type ResourceProviderImportStateResponse struct {
   367  	State []*terraform.InstanceState
   368  	Error *plugin.BasicError
   369  }
   370  
   371  type ResourceProviderReadDataApplyArgs struct {
   372  	Info *terraform.InstanceInfo
   373  	Diff *terraform.InstanceDiff
   374  }
   375  
   376  type ResourceProviderReadDataApplyResponse struct {
   377  	State *terraform.InstanceState
   378  	Error *plugin.BasicError
   379  }
   380  
   381  type ResourceProviderReadDataDiffArgs struct {
   382  	Info   *terraform.InstanceInfo
   383  	Config *terraform.ResourceConfig
   384  }
   385  
   386  type ResourceProviderReadDataDiffResponse struct {
   387  	Diff  *terraform.InstanceDiff
   388  	Error *plugin.BasicError
   389  }
   390  
   391  type ResourceProviderValidateArgs struct {
   392  	Config *terraform.ResourceConfig
   393  }
   394  
   395  type ResourceProviderValidateResponse struct {
   396  	Warnings []string
   397  	Errors   []*plugin.BasicError
   398  }
   399  
   400  type ResourceProviderValidateResourceArgs struct {
   401  	Config *terraform.ResourceConfig
   402  	Type   string
   403  }
   404  
   405  type ResourceProviderValidateResourceResponse struct {
   406  	Warnings []string
   407  	Errors   []*plugin.BasicError
   408  }
   409  
   410  func (s *ResourceProviderServer) Stop(
   411  	_ interface{},
   412  	reply *ResourceProviderStopResponse) error {
   413  	err := s.Provider.Stop()
   414  	*reply = ResourceProviderStopResponse{
   415  		Error: plugin.NewBasicError(err),
   416  	}
   417  
   418  	return nil
   419  }
   420  
   421  func (s *ResourceProviderServer) Input(
   422  	args *ResourceProviderInputArgs,
   423  	reply *ResourceProviderInputResponse) error {
   424  	conn, err := s.Broker.Dial(args.InputId)
   425  	if err != nil {
   426  		*reply = ResourceProviderInputResponse{
   427  			Error: plugin.NewBasicError(err),
   428  		}
   429  		return nil
   430  	}
   431  	client := rpc.NewClient(conn)
   432  	defer client.Close()
   433  
   434  	input := &UIInput{Client: client}
   435  
   436  	config, err := s.Provider.Input(input, args.Config)
   437  	*reply = ResourceProviderInputResponse{
   438  		Config: config,
   439  		Error:  plugin.NewBasicError(err),
   440  	}
   441  
   442  	return nil
   443  }
   444  
   445  func (s *ResourceProviderServer) Validate(
   446  	args *ResourceProviderValidateArgs,
   447  	reply *ResourceProviderValidateResponse) error {
   448  	warns, errs := s.Provider.Validate(args.Config)
   449  	berrs := make([]*plugin.BasicError, len(errs))
   450  	for i, err := range errs {
   451  		berrs[i] = plugin.NewBasicError(err)
   452  	}
   453  	*reply = ResourceProviderValidateResponse{
   454  		Warnings: warns,
   455  		Errors:   berrs,
   456  	}
   457  	return nil
   458  }
   459  
   460  func (s *ResourceProviderServer) ValidateResource(
   461  	args *ResourceProviderValidateResourceArgs,
   462  	reply *ResourceProviderValidateResourceResponse) error {
   463  	warns, errs := s.Provider.ValidateResource(args.Type, args.Config)
   464  	berrs := make([]*plugin.BasicError, len(errs))
   465  	for i, err := range errs {
   466  		berrs[i] = plugin.NewBasicError(err)
   467  	}
   468  	*reply = ResourceProviderValidateResourceResponse{
   469  		Warnings: warns,
   470  		Errors:   berrs,
   471  	}
   472  	return nil
   473  }
   474  
   475  func (s *ResourceProviderServer) Configure(
   476  	config *terraform.ResourceConfig,
   477  	reply *ResourceProviderConfigureResponse) error {
   478  	err := s.Provider.Configure(config)
   479  	*reply = ResourceProviderConfigureResponse{
   480  		Error: plugin.NewBasicError(err),
   481  	}
   482  	return nil
   483  }
   484  
   485  func (s *ResourceProviderServer) Apply(
   486  	args *ResourceProviderApplyArgs,
   487  	result *ResourceProviderApplyResponse) error {
   488  	state, err := s.Provider.Apply(args.Info, args.State, args.Diff)
   489  	*result = ResourceProviderApplyResponse{
   490  		State: state,
   491  		Error: plugin.NewBasicError(err),
   492  	}
   493  	return nil
   494  }
   495  
   496  func (s *ResourceProviderServer) Diff(
   497  	args *ResourceProviderDiffArgs,
   498  	result *ResourceProviderDiffResponse) error {
   499  	diff, err := s.Provider.Diff(args.Info, args.State, args.Config)
   500  	*result = ResourceProviderDiffResponse{
   501  		Diff:  diff,
   502  		Error: plugin.NewBasicError(err),
   503  	}
   504  	return nil
   505  }
   506  
   507  func (s *ResourceProviderServer) Refresh(
   508  	args *ResourceProviderRefreshArgs,
   509  	result *ResourceProviderRefreshResponse) error {
   510  	newState, err := s.Provider.Refresh(args.Info, args.State)
   511  	*result = ResourceProviderRefreshResponse{
   512  		State: newState,
   513  		Error: plugin.NewBasicError(err),
   514  	}
   515  	return nil
   516  }
   517  
   518  func (s *ResourceProviderServer) ImportState(
   519  	args *ResourceProviderImportStateArgs,
   520  	result *ResourceProviderImportStateResponse) error {
   521  	states, err := s.Provider.ImportState(args.Info, args.Id)
   522  	*result = ResourceProviderImportStateResponse{
   523  		State: states,
   524  		Error: plugin.NewBasicError(err),
   525  	}
   526  	return nil
   527  }
   528  
   529  func (s *ResourceProviderServer) Resources(
   530  	nothing interface{},
   531  	result *[]terraform.ResourceType) error {
   532  	*result = s.Provider.Resources()
   533  	return nil
   534  }
   535  
   536  func (s *ResourceProviderServer) ValidateDataSource(
   537  	args *ResourceProviderValidateResourceArgs,
   538  	reply *ResourceProviderValidateResourceResponse) error {
   539  	warns, errs := s.Provider.ValidateDataSource(args.Type, args.Config)
   540  	berrs := make([]*plugin.BasicError, len(errs))
   541  	for i, err := range errs {
   542  		berrs[i] = plugin.NewBasicError(err)
   543  	}
   544  	*reply = ResourceProviderValidateResourceResponse{
   545  		Warnings: warns,
   546  		Errors:   berrs,
   547  	}
   548  	return nil
   549  }
   550  
   551  func (s *ResourceProviderServer) ReadDataDiff(
   552  	args *ResourceProviderReadDataDiffArgs,
   553  	result *ResourceProviderReadDataDiffResponse) error {
   554  	diff, err := s.Provider.ReadDataDiff(args.Info, args.Config)
   555  	*result = ResourceProviderReadDataDiffResponse{
   556  		Diff:  diff,
   557  		Error: plugin.NewBasicError(err),
   558  	}
   559  	return nil
   560  }
   561  
   562  func (s *ResourceProviderServer) ReadDataApply(
   563  	args *ResourceProviderReadDataApplyArgs,
   564  	result *ResourceProviderReadDataApplyResponse) error {
   565  	newState, err := s.Provider.ReadDataApply(args.Info, args.Diff)
   566  	*result = ResourceProviderReadDataApplyResponse{
   567  		State: newState,
   568  		Error: plugin.NewBasicError(err),
   569  	}
   570  	return nil
   571  }
   572  
   573  func (s *ResourceProviderServer) DataSources(
   574  	nothing interface{},
   575  	result *[]terraform.DataSource) error {
   576  	*result = s.Provider.DataSources()
   577  	return nil
   578  }