github.com/eliastor/durgaform@v0.0.0-20220816172711-d0ab2d17673e/internal/grpcwrap/provisioner.go (about)

     1  package grpcwrap
     2  
     3  import (
     4  	"context"
     5  	"log"
     6  	"strings"
     7  	"unicode/utf8"
     8  
     9  	"github.com/eliastor/durgaform/internal/communicator/shared"
    10  	"github.com/eliastor/durgaform/internal/configs/configschema"
    11  	"github.com/eliastor/durgaform/internal/plugin/convert"
    12  	"github.com/eliastor/durgaform/internal/provisioners"
    13  	"github.com/eliastor/durgaform/internal/tfplugin5"
    14  )
    15  
    16  // New wraps a provisioners.Interface to implement a grpc ProviderServer.
    17  // This is useful for creating a test binary out of an internal provider
    18  // implementation.
    19  func Provisioner(p provisioners.Interface) tfplugin5.ProvisionerServer {
    20  	return &provisioner{
    21  		provisioner: p,
    22  		schema:      p.GetSchema().Provisioner,
    23  	}
    24  }
    25  
    26  type provisioner struct {
    27  	provisioner provisioners.Interface
    28  	schema      *configschema.Block
    29  }
    30  
    31  func (p *provisioner) GetSchema(_ context.Context, req *tfplugin5.GetProvisionerSchema_Request) (*tfplugin5.GetProvisionerSchema_Response, error) {
    32  	resp := &tfplugin5.GetProvisionerSchema_Response{}
    33  
    34  	resp.Provisioner = &tfplugin5.Schema{
    35  		Block: &tfplugin5.Schema_Block{},
    36  	}
    37  
    38  	if p.schema != nil {
    39  		resp.Provisioner.Block = convert.ConfigSchemaToProto(p.schema)
    40  	}
    41  
    42  	return resp, nil
    43  }
    44  
    45  func (p *provisioner) ValidateProvisionerConfig(_ context.Context, req *tfplugin5.ValidateProvisionerConfig_Request) (*tfplugin5.ValidateProvisionerConfig_Response, error) {
    46  	resp := &tfplugin5.ValidateProvisionerConfig_Response{}
    47  	ty := p.schema.ImpliedType()
    48  
    49  	configVal, err := decodeDynamicValue(req.Config, ty)
    50  	if err != nil {
    51  		resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
    52  		return resp, nil
    53  	}
    54  
    55  	validateResp := p.provisioner.ValidateProvisionerConfig(provisioners.ValidateProvisionerConfigRequest{
    56  		Config: configVal,
    57  	})
    58  
    59  	resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, validateResp.Diagnostics)
    60  	return resp, nil
    61  }
    62  
    63  func (p *provisioner) ProvisionResource(req *tfplugin5.ProvisionResource_Request, srv tfplugin5.Provisioner_ProvisionResourceServer) error {
    64  	// We send back a diagnostics over the stream if there was a
    65  	// provisioner-side problem.
    66  	srvResp := &tfplugin5.ProvisionResource_Response{}
    67  
    68  	ty := p.schema.ImpliedType()
    69  	configVal, err := decodeDynamicValue(req.Config, ty)
    70  	if err != nil {
    71  		srvResp.Diagnostics = convert.AppendProtoDiag(srvResp.Diagnostics, err)
    72  		srv.Send(srvResp)
    73  		return nil
    74  	}
    75  
    76  	connVal, err := decodeDynamicValue(req.Connection, shared.ConnectionBlockSupersetSchema.ImpliedType())
    77  	if err != nil {
    78  		srvResp.Diagnostics = convert.AppendProtoDiag(srvResp.Diagnostics, err)
    79  		srv.Send(srvResp)
    80  		return nil
    81  	}
    82  
    83  	resp := p.provisioner.ProvisionResource(provisioners.ProvisionResourceRequest{
    84  		Config:     configVal,
    85  		Connection: connVal,
    86  		UIOutput:   uiOutput{srv},
    87  	})
    88  
    89  	srvResp.Diagnostics = convert.AppendProtoDiag(srvResp.Diagnostics, resp.Diagnostics)
    90  	srv.Send(srvResp)
    91  	return nil
    92  }
    93  
    94  func (p *provisioner) Stop(context.Context, *tfplugin5.Stop_Request) (*tfplugin5.Stop_Response, error) {
    95  	resp := &tfplugin5.Stop_Response{}
    96  	err := p.provisioner.Stop()
    97  	if err != nil {
    98  		resp.Error = err.Error()
    99  	}
   100  	return resp, nil
   101  }
   102  
   103  // uiOutput implements the durgaform.UIOutput interface to adapt the grpc
   104  // stream to the legacy Provisioner.Apply method.
   105  type uiOutput struct {
   106  	srv tfplugin5.Provisioner_ProvisionResourceServer
   107  }
   108  
   109  func (o uiOutput) Output(s string) {
   110  	err := o.srv.Send(&tfplugin5.ProvisionResource_Response{
   111  		Output: strings.ToValidUTF8(s, string(utf8.RuneError)),
   112  	})
   113  	if err != nil {
   114  		log.Printf("[ERROR] %s", err)
   115  	}
   116  }