kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/grpcwrap/provider6.go (about)

     1  package grpcwrap
     2  
     3  import (
     4  	"context"
     5  
     6  	"kubeform.dev/terraform-backend-sdk/plugin6/convert"
     7  	"kubeform.dev/terraform-backend-sdk/providers"
     8  	"kubeform.dev/terraform-backend-sdk/tfplugin6"
     9  	"github.com/zclconf/go-cty/cty"
    10  	ctyjson "github.com/zclconf/go-cty/cty/json"
    11  	"github.com/zclconf/go-cty/cty/msgpack"
    12  )
    13  
    14  // New wraps a providers.Interface to implement a grpc ProviderServer using
    15  // plugin protocol v6. This is useful for creating a test binary out of an
    16  // internal provider implementation.
    17  func Provider6(p providers.Interface) tfplugin6.ProviderServer {
    18  	return &provider6{
    19  		provider: p,
    20  		schema:   p.GetProviderSchema(),
    21  	}
    22  }
    23  
    24  type provider6 struct {
    25  	provider providers.Interface
    26  	schema   providers.GetProviderSchemaResponse
    27  }
    28  
    29  func (p *provider6) GetProviderSchema(_ context.Context, req *tfplugin6.GetProviderSchema_Request) (*tfplugin6.GetProviderSchema_Response, error) {
    30  	resp := &tfplugin6.GetProviderSchema_Response{
    31  		ResourceSchemas:   make(map[string]*tfplugin6.Schema),
    32  		DataSourceSchemas: make(map[string]*tfplugin6.Schema),
    33  	}
    34  
    35  	resp.Provider = &tfplugin6.Schema{
    36  		Block: &tfplugin6.Schema_Block{},
    37  	}
    38  	if p.schema.Provider.Block != nil {
    39  		resp.Provider.Block = convert.ConfigSchemaToProto(p.schema.Provider.Block)
    40  	}
    41  
    42  	resp.ProviderMeta = &tfplugin6.Schema{
    43  		Block: &tfplugin6.Schema_Block{},
    44  	}
    45  	if p.schema.ProviderMeta.Block != nil {
    46  		resp.ProviderMeta.Block = convert.ConfigSchemaToProto(p.schema.ProviderMeta.Block)
    47  	}
    48  
    49  	for typ, res := range p.schema.ResourceTypes {
    50  		resp.ResourceSchemas[typ] = &tfplugin6.Schema{
    51  			Version: res.Version,
    52  			Block:   convert.ConfigSchemaToProto(res.Block),
    53  		}
    54  	}
    55  	for typ, dat := range p.schema.DataSources {
    56  		resp.DataSourceSchemas[typ] = &tfplugin6.Schema{
    57  			Version: dat.Version,
    58  			Block:   convert.ConfigSchemaToProto(dat.Block),
    59  		}
    60  	}
    61  
    62  	// include any diagnostics from the original GetSchema call
    63  	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, p.schema.Diagnostics)
    64  
    65  	return resp, nil
    66  }
    67  
    68  func (p *provider6) ValidateProviderConfig(_ context.Context, req *tfplugin6.ValidateProviderConfig_Request) (*tfplugin6.ValidateProviderConfig_Response, error) {
    69  	resp := &tfplugin6.ValidateProviderConfig_Response{}
    70  	ty := p.schema.Provider.Block.ImpliedType()
    71  
    72  	configVal, err := decodeDynamicValue6(req.Config, ty)
    73  	if err != nil {
    74  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
    75  		return resp, nil
    76  	}
    77  
    78  	prepareResp := p.provider.ValidateProviderConfig(providers.ValidateProviderConfigRequest{
    79  		Config: configVal,
    80  	})
    81  
    82  	// the PreparedConfig value is no longer used
    83  	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, prepareResp.Diagnostics)
    84  	return resp, nil
    85  }
    86  
    87  func (p *provider6) ValidateResourceConfig(_ context.Context, req *tfplugin6.ValidateResourceConfig_Request) (*tfplugin6.ValidateResourceConfig_Response, error) {
    88  	resp := &tfplugin6.ValidateResourceConfig_Response{}
    89  	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
    90  
    91  	configVal, err := decodeDynamicValue6(req.Config, ty)
    92  	if err != nil {
    93  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
    94  		return resp, nil
    95  	}
    96  
    97  	validateResp := p.provider.ValidateResourceConfig(providers.ValidateResourceConfigRequest{
    98  		TypeName: req.TypeName,
    99  		Config:   configVal,
   100  	})
   101  
   102  	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, validateResp.Diagnostics)
   103  	return resp, nil
   104  }
   105  
   106  func (p *provider6) ValidateDataResourceConfig(_ context.Context, req *tfplugin6.ValidateDataResourceConfig_Request) (*tfplugin6.ValidateDataResourceConfig_Response, error) {
   107  	resp := &tfplugin6.ValidateDataResourceConfig_Response{}
   108  	ty := p.schema.DataSources[req.TypeName].Block.ImpliedType()
   109  
   110  	configVal, err := decodeDynamicValue6(req.Config, ty)
   111  	if err != nil {
   112  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   113  		return resp, nil
   114  	}
   115  
   116  	validateResp := p.provider.ValidateDataResourceConfig(providers.ValidateDataResourceConfigRequest{
   117  		TypeName: req.TypeName,
   118  		Config:   configVal,
   119  	})
   120  
   121  	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, validateResp.Diagnostics)
   122  	return resp, nil
   123  }
   124  
   125  func (p *provider6) UpgradeResourceState(_ context.Context, req *tfplugin6.UpgradeResourceState_Request) (*tfplugin6.UpgradeResourceState_Response, error) {
   126  	resp := &tfplugin6.UpgradeResourceState_Response{}
   127  	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
   128  
   129  	upgradeResp := p.provider.UpgradeResourceState(providers.UpgradeResourceStateRequest{
   130  		TypeName:     req.TypeName,
   131  		Version:      req.Version,
   132  		RawStateJSON: req.RawState.Json,
   133  	})
   134  
   135  	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, upgradeResp.Diagnostics)
   136  	if upgradeResp.Diagnostics.HasErrors() {
   137  		return resp, nil
   138  	}
   139  
   140  	dv, err := encodeDynamicValue6(upgradeResp.UpgradedState, ty)
   141  	if err != nil {
   142  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   143  		return resp, nil
   144  	}
   145  
   146  	resp.UpgradedState = dv
   147  
   148  	return resp, nil
   149  }
   150  
   151  func (p *provider6) ConfigureProvider(_ context.Context, req *tfplugin6.ConfigureProvider_Request) (*tfplugin6.ConfigureProvider_Response, error) {
   152  	resp := &tfplugin6.ConfigureProvider_Response{}
   153  	ty := p.schema.Provider.Block.ImpliedType()
   154  
   155  	configVal, err := decodeDynamicValue6(req.Config, ty)
   156  	if err != nil {
   157  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   158  		return resp, nil
   159  	}
   160  
   161  	configureResp := p.provider.ConfigureProvider(providers.ConfigureProviderRequest{
   162  		TerraformVersion: req.TerraformVersion,
   163  		Config:           configVal,
   164  	})
   165  
   166  	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, configureResp.Diagnostics)
   167  	return resp, nil
   168  }
   169  
   170  func (p *provider6) ReadResource(_ context.Context, req *tfplugin6.ReadResource_Request) (*tfplugin6.ReadResource_Response, error) {
   171  	resp := &tfplugin6.ReadResource_Response{}
   172  	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
   173  
   174  	stateVal, err := decodeDynamicValue6(req.CurrentState, ty)
   175  	if err != nil {
   176  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   177  		return resp, nil
   178  	}
   179  
   180  	metaTy := p.schema.ProviderMeta.Block.ImpliedType()
   181  	metaVal, err := decodeDynamicValue6(req.ProviderMeta, metaTy)
   182  	if err != nil {
   183  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   184  		return resp, nil
   185  	}
   186  
   187  	readResp := p.provider.ReadResource(providers.ReadResourceRequest{
   188  		TypeName:     req.TypeName,
   189  		PriorState:   stateVal,
   190  		Private:      req.Private,
   191  		ProviderMeta: metaVal,
   192  	})
   193  	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, readResp.Diagnostics)
   194  	if readResp.Diagnostics.HasErrors() {
   195  		return resp, nil
   196  	}
   197  	resp.Private = readResp.Private
   198  
   199  	dv, err := encodeDynamicValue6(readResp.NewState, ty)
   200  	if err != nil {
   201  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   202  		return resp, nil
   203  	}
   204  	resp.NewState = dv
   205  
   206  	return resp, nil
   207  }
   208  
   209  func (p *provider6) PlanResourceChange(_ context.Context, req *tfplugin6.PlanResourceChange_Request) (*tfplugin6.PlanResourceChange_Response, error) {
   210  	resp := &tfplugin6.PlanResourceChange_Response{}
   211  	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
   212  
   213  	priorStateVal, err := decodeDynamicValue6(req.PriorState, ty)
   214  	if err != nil {
   215  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   216  		return resp, nil
   217  	}
   218  
   219  	proposedStateVal, err := decodeDynamicValue6(req.ProposedNewState, ty)
   220  	if err != nil {
   221  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   222  		return resp, nil
   223  	}
   224  
   225  	configVal, err := decodeDynamicValue6(req.Config, ty)
   226  	if err != nil {
   227  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   228  		return resp, nil
   229  	}
   230  
   231  	metaTy := p.schema.ProviderMeta.Block.ImpliedType()
   232  	metaVal, err := decodeDynamicValue6(req.ProviderMeta, metaTy)
   233  	if err != nil {
   234  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   235  		return resp, nil
   236  	}
   237  
   238  	planResp := p.provider.PlanResourceChange(providers.PlanResourceChangeRequest{
   239  		TypeName:         req.TypeName,
   240  		PriorState:       priorStateVal,
   241  		ProposedNewState: proposedStateVal,
   242  		Config:           configVal,
   243  		PriorPrivate:     req.PriorPrivate,
   244  		ProviderMeta:     metaVal,
   245  	})
   246  	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, planResp.Diagnostics)
   247  	if planResp.Diagnostics.HasErrors() {
   248  		return resp, nil
   249  	}
   250  
   251  	resp.PlannedPrivate = planResp.PlannedPrivate
   252  
   253  	resp.PlannedState, err = encodeDynamicValue6(planResp.PlannedState, ty)
   254  	if err != nil {
   255  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   256  		return resp, nil
   257  	}
   258  
   259  	for _, path := range planResp.RequiresReplace {
   260  		resp.RequiresReplace = append(resp.RequiresReplace, convert.PathToAttributePath(path))
   261  	}
   262  
   263  	return resp, nil
   264  }
   265  
   266  func (p *provider6) ApplyResourceChange(_ context.Context, req *tfplugin6.ApplyResourceChange_Request) (*tfplugin6.ApplyResourceChange_Response, error) {
   267  	resp := &tfplugin6.ApplyResourceChange_Response{}
   268  	ty := p.schema.ResourceTypes[req.TypeName].Block.ImpliedType()
   269  
   270  	priorStateVal, err := decodeDynamicValue6(req.PriorState, ty)
   271  	if err != nil {
   272  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   273  		return resp, nil
   274  	}
   275  
   276  	plannedStateVal, err := decodeDynamicValue6(req.PlannedState, ty)
   277  	if err != nil {
   278  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   279  		return resp, nil
   280  	}
   281  
   282  	configVal, err := decodeDynamicValue6(req.Config, ty)
   283  	if err != nil {
   284  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   285  		return resp, nil
   286  	}
   287  
   288  	metaTy := p.schema.ProviderMeta.Block.ImpliedType()
   289  	metaVal, err := decodeDynamicValue6(req.ProviderMeta, metaTy)
   290  	if err != nil {
   291  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   292  		return resp, nil
   293  	}
   294  
   295  	applyResp := p.provider.ApplyResourceChange(providers.ApplyResourceChangeRequest{
   296  		TypeName:       req.TypeName,
   297  		PriorState:     priorStateVal,
   298  		PlannedState:   plannedStateVal,
   299  		Config:         configVal,
   300  		PlannedPrivate: req.PlannedPrivate,
   301  		ProviderMeta:   metaVal,
   302  	})
   303  
   304  	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, applyResp.Diagnostics)
   305  	if applyResp.Diagnostics.HasErrors() {
   306  		return resp, nil
   307  	}
   308  	resp.Private = applyResp.Private
   309  
   310  	resp.NewState, err = encodeDynamicValue6(applyResp.NewState, ty)
   311  	if err != nil {
   312  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   313  		return resp, nil
   314  	}
   315  
   316  	return resp, nil
   317  }
   318  
   319  func (p *provider6) ImportResourceState(_ context.Context, req *tfplugin6.ImportResourceState_Request) (*tfplugin6.ImportResourceState_Response, error) {
   320  	resp := &tfplugin6.ImportResourceState_Response{}
   321  
   322  	importResp := p.provider.ImportResourceState(providers.ImportResourceStateRequest{
   323  		TypeName: req.TypeName,
   324  		ID:       req.Id,
   325  	})
   326  	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, importResp.Diagnostics)
   327  
   328  	for _, res := range importResp.ImportedResources {
   329  		ty := p.schema.ResourceTypes[res.TypeName].Block.ImpliedType()
   330  		state, err := encodeDynamicValue6(res.State, ty)
   331  		if err != nil {
   332  			resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   333  			continue
   334  		}
   335  
   336  		resp.ImportedResources = append(resp.ImportedResources, &tfplugin6.ImportResourceState_ImportedResource{
   337  			TypeName: res.TypeName,
   338  			State:    state,
   339  			Private:  res.Private,
   340  		})
   341  	}
   342  
   343  	return resp, nil
   344  }
   345  
   346  func (p *provider6) ReadDataSource(_ context.Context, req *tfplugin6.ReadDataSource_Request) (*tfplugin6.ReadDataSource_Response, error) {
   347  	resp := &tfplugin6.ReadDataSource_Response{}
   348  	ty := p.schema.DataSources[req.TypeName].Block.ImpliedType()
   349  
   350  	configVal, err := decodeDynamicValue6(req.Config, ty)
   351  	if err != nil {
   352  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   353  		return resp, nil
   354  	}
   355  
   356  	metaTy := p.schema.ProviderMeta.Block.ImpliedType()
   357  	metaVal, err := decodeDynamicValue6(req.ProviderMeta, metaTy)
   358  	if err != nil {
   359  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   360  		return resp, nil
   361  	}
   362  
   363  	readResp := p.provider.ReadDataSource(providers.ReadDataSourceRequest{
   364  		TypeName:     req.TypeName,
   365  		Config:       configVal,
   366  		ProviderMeta: metaVal,
   367  	})
   368  	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, readResp.Diagnostics)
   369  	if readResp.Diagnostics.HasErrors() {
   370  		return resp, nil
   371  	}
   372  
   373  	resp.State, err = encodeDynamicValue6(readResp.State, ty)
   374  	if err != nil {
   375  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
   376  		return resp, nil
   377  	}
   378  
   379  	return resp, nil
   380  }
   381  
   382  func (p *provider6) StopProvider(context.Context, *tfplugin6.StopProvider_Request) (*tfplugin6.StopProvider_Response, error) {
   383  	resp := &tfplugin6.StopProvider_Response{}
   384  	err := p.provider.Stop()
   385  	if err != nil {
   386  		resp.Error = err.Error()
   387  	}
   388  	return resp, nil
   389  }
   390  
   391  // decode a DynamicValue from either the JSON or MsgPack encoding.
   392  func decodeDynamicValue6(v *tfplugin6.DynamicValue, ty cty.Type) (cty.Value, error) {
   393  	// always return a valid value
   394  	var err error
   395  	res := cty.NullVal(ty)
   396  	if v == nil {
   397  		return res, nil
   398  	}
   399  
   400  	switch {
   401  	case len(v.Msgpack) > 0:
   402  		res, err = msgpack.Unmarshal(v.Msgpack, ty)
   403  	case len(v.Json) > 0:
   404  		res, err = ctyjson.Unmarshal(v.Json, ty)
   405  	}
   406  	return res, err
   407  }
   408  
   409  // encode a cty.Value into a DynamicValue msgpack payload.
   410  func encodeDynamicValue6(v cty.Value, ty cty.Type) (*tfplugin6.DynamicValue, error) {
   411  	mp, err := msgpack.Marshal(v, ty)
   412  	return &tfplugin6.DynamicValue{
   413  		Msgpack: mp,
   414  	}, err
   415  }