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