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