mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-25 16:31:10 -06:00
183833affc
In order to parse provider, resource and data source configuration from HCL2 config files, we need to know the relevant configuration schema. This new method allows Terraform Core to request these from a provider. This is a breaking change to this interface, so all of its implementers in this package are updated too. This includes concrete implementations of the new method in helper/schema that use the schema conversion code added in an earlier commit to produce a configschema.Block automatically. Plugins compiled against prior versions of helper/schema will not have support for this method, and so calls to them will fail. Callers of this new method will therefore need to sniff for support using the SchemaAvailable field added to both ResourceType and DataSource. This careful handling will need to persist until next time we increment the plugin protocol version, at which point we can make the breaking change of requiring this information to be available.
618 lines
14 KiB
Go
618 lines
14 KiB
Go
package plugin
|
|
|
|
import (
|
|
"net/rpc"
|
|
|
|
"github.com/hashicorp/go-plugin"
|
|
"github.com/hashicorp/terraform/terraform"
|
|
)
|
|
|
|
// ResourceProviderPlugin is the plugin.Plugin implementation.
|
|
type ResourceProviderPlugin struct {
|
|
F func() terraform.ResourceProvider
|
|
}
|
|
|
|
func (p *ResourceProviderPlugin) Server(b *plugin.MuxBroker) (interface{}, error) {
|
|
return &ResourceProviderServer{Broker: b, Provider: p.F()}, nil
|
|
}
|
|
|
|
func (p *ResourceProviderPlugin) Client(
|
|
b *plugin.MuxBroker, c *rpc.Client) (interface{}, error) {
|
|
return &ResourceProvider{Broker: b, Client: c}, nil
|
|
}
|
|
|
|
// ResourceProvider is an implementation of terraform.ResourceProvider
|
|
// that communicates over RPC.
|
|
type ResourceProvider struct {
|
|
Broker *plugin.MuxBroker
|
|
Client *rpc.Client
|
|
}
|
|
|
|
func (p *ResourceProvider) Stop() error {
|
|
var resp ResourceProviderStopResponse
|
|
err := p.Client.Call("Plugin.Stop", new(interface{}), &resp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if resp.Error != nil {
|
|
err = resp.Error
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func (p *ResourceProvider) GetSchema(req *terraform.ProviderSchemaRequest) (*terraform.ProviderSchema, error) {
|
|
var result ResourceProviderGetSchemaResponse
|
|
args := &ResourceProviderGetSchemaArgs{
|
|
Req: req,
|
|
}
|
|
|
|
err := p.Client.Call("Plugin.GetSchema", args, &result)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if result.Error != nil {
|
|
err = result.Error
|
|
}
|
|
|
|
return result.Schema, err
|
|
}
|
|
|
|
func (p *ResourceProvider) Input(
|
|
input terraform.UIInput,
|
|
c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) {
|
|
id := p.Broker.NextId()
|
|
go p.Broker.AcceptAndServe(id, &UIInputServer{
|
|
UIInput: input,
|
|
})
|
|
|
|
var resp ResourceProviderInputResponse
|
|
args := ResourceProviderInputArgs{
|
|
InputId: id,
|
|
Config: c,
|
|
}
|
|
|
|
err := p.Client.Call("Plugin.Input", &args, &resp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.Error != nil {
|
|
err = resp.Error
|
|
return nil, err
|
|
}
|
|
|
|
return resp.Config, nil
|
|
}
|
|
|
|
func (p *ResourceProvider) Validate(c *terraform.ResourceConfig) ([]string, []error) {
|
|
var resp ResourceProviderValidateResponse
|
|
args := ResourceProviderValidateArgs{
|
|
Config: c,
|
|
}
|
|
|
|
err := p.Client.Call("Plugin.Validate", &args, &resp)
|
|
if err != nil {
|
|
return nil, []error{err}
|
|
}
|
|
|
|
var errs []error
|
|
if len(resp.Errors) > 0 {
|
|
errs = make([]error, len(resp.Errors))
|
|
for i, err := range resp.Errors {
|
|
errs[i] = err
|
|
}
|
|
}
|
|
|
|
return resp.Warnings, errs
|
|
}
|
|
|
|
func (p *ResourceProvider) ValidateResource(
|
|
t string, c *terraform.ResourceConfig) ([]string, []error) {
|
|
var resp ResourceProviderValidateResourceResponse
|
|
args := ResourceProviderValidateResourceArgs{
|
|
Config: c,
|
|
Type: t,
|
|
}
|
|
|
|
err := p.Client.Call("Plugin.ValidateResource", &args, &resp)
|
|
if err != nil {
|
|
return nil, []error{err}
|
|
}
|
|
|
|
var errs []error
|
|
if len(resp.Errors) > 0 {
|
|
errs = make([]error, len(resp.Errors))
|
|
for i, err := range resp.Errors {
|
|
errs[i] = err
|
|
}
|
|
}
|
|
|
|
return resp.Warnings, errs
|
|
}
|
|
|
|
func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error {
|
|
var resp ResourceProviderConfigureResponse
|
|
err := p.Client.Call("Plugin.Configure", c, &resp)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if resp.Error != nil {
|
|
err = resp.Error
|
|
}
|
|
|
|
return err
|
|
}
|
|
|
|
func (p *ResourceProvider) Apply(
|
|
info *terraform.InstanceInfo,
|
|
s *terraform.InstanceState,
|
|
d *terraform.InstanceDiff) (*terraform.InstanceState, error) {
|
|
var resp ResourceProviderApplyResponse
|
|
args := &ResourceProviderApplyArgs{
|
|
Info: info,
|
|
State: s,
|
|
Diff: d,
|
|
}
|
|
|
|
err := p.Client.Call("Plugin.Apply", args, &resp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.Error != nil {
|
|
err = resp.Error
|
|
}
|
|
|
|
return resp.State, err
|
|
}
|
|
|
|
func (p *ResourceProvider) Diff(
|
|
info *terraform.InstanceInfo,
|
|
s *terraform.InstanceState,
|
|
c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
|
|
var resp ResourceProviderDiffResponse
|
|
args := &ResourceProviderDiffArgs{
|
|
Info: info,
|
|
State: s,
|
|
Config: c,
|
|
}
|
|
err := p.Client.Call("Plugin.Diff", args, &resp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.Error != nil {
|
|
err = resp.Error
|
|
}
|
|
|
|
return resp.Diff, err
|
|
}
|
|
|
|
func (p *ResourceProvider) ValidateDataSource(
|
|
t string, c *terraform.ResourceConfig) ([]string, []error) {
|
|
var resp ResourceProviderValidateResourceResponse
|
|
args := ResourceProviderValidateResourceArgs{
|
|
Config: c,
|
|
Type: t,
|
|
}
|
|
|
|
err := p.Client.Call("Plugin.ValidateDataSource", &args, &resp)
|
|
if err != nil {
|
|
return nil, []error{err}
|
|
}
|
|
|
|
var errs []error
|
|
if len(resp.Errors) > 0 {
|
|
errs = make([]error, len(resp.Errors))
|
|
for i, err := range resp.Errors {
|
|
errs[i] = err
|
|
}
|
|
}
|
|
|
|
return resp.Warnings, errs
|
|
}
|
|
|
|
func (p *ResourceProvider) Refresh(
|
|
info *terraform.InstanceInfo,
|
|
s *terraform.InstanceState) (*terraform.InstanceState, error) {
|
|
var resp ResourceProviderRefreshResponse
|
|
args := &ResourceProviderRefreshArgs{
|
|
Info: info,
|
|
State: s,
|
|
}
|
|
|
|
err := p.Client.Call("Plugin.Refresh", args, &resp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.Error != nil {
|
|
err = resp.Error
|
|
}
|
|
|
|
return resp.State, err
|
|
}
|
|
|
|
func (p *ResourceProvider) ImportState(
|
|
info *terraform.InstanceInfo,
|
|
id string) ([]*terraform.InstanceState, error) {
|
|
var resp ResourceProviderImportStateResponse
|
|
args := &ResourceProviderImportStateArgs{
|
|
Info: info,
|
|
Id: id,
|
|
}
|
|
|
|
err := p.Client.Call("Plugin.ImportState", args, &resp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.Error != nil {
|
|
err = resp.Error
|
|
}
|
|
|
|
return resp.State, err
|
|
}
|
|
|
|
func (p *ResourceProvider) Resources() []terraform.ResourceType {
|
|
var result []terraform.ResourceType
|
|
|
|
err := p.Client.Call("Plugin.Resources", new(interface{}), &result)
|
|
if err != nil {
|
|
// TODO: panic, log, what?
|
|
return nil
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (p *ResourceProvider) ReadDataDiff(
|
|
info *terraform.InstanceInfo,
|
|
c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) {
|
|
var resp ResourceProviderReadDataDiffResponse
|
|
args := &ResourceProviderReadDataDiffArgs{
|
|
Info: info,
|
|
Config: c,
|
|
}
|
|
|
|
err := p.Client.Call("Plugin.ReadDataDiff", args, &resp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.Error != nil {
|
|
err = resp.Error
|
|
}
|
|
|
|
return resp.Diff, err
|
|
}
|
|
|
|
func (p *ResourceProvider) ReadDataApply(
|
|
info *terraform.InstanceInfo,
|
|
d *terraform.InstanceDiff) (*terraform.InstanceState, error) {
|
|
var resp ResourceProviderReadDataApplyResponse
|
|
args := &ResourceProviderReadDataApplyArgs{
|
|
Info: info,
|
|
Diff: d,
|
|
}
|
|
|
|
err := p.Client.Call("Plugin.ReadDataApply", args, &resp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.Error != nil {
|
|
err = resp.Error
|
|
}
|
|
|
|
return resp.State, err
|
|
}
|
|
|
|
func (p *ResourceProvider) DataSources() []terraform.DataSource {
|
|
var result []terraform.DataSource
|
|
|
|
err := p.Client.Call("Plugin.DataSources", new(interface{}), &result)
|
|
if err != nil {
|
|
// TODO: panic, log, what?
|
|
return nil
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (p *ResourceProvider) Close() error {
|
|
return p.Client.Close()
|
|
}
|
|
|
|
// ResourceProviderServer is a net/rpc compatible structure for serving
|
|
// a ResourceProvider. This should not be used directly.
|
|
type ResourceProviderServer struct {
|
|
Broker *plugin.MuxBroker
|
|
Provider terraform.ResourceProvider
|
|
}
|
|
|
|
type ResourceProviderStopResponse struct {
|
|
Error *plugin.BasicError
|
|
}
|
|
|
|
type ResourceProviderGetSchemaArgs struct {
|
|
Req *terraform.ProviderSchemaRequest
|
|
}
|
|
|
|
type ResourceProviderGetSchemaResponse struct {
|
|
Schema *terraform.ProviderSchema
|
|
Error *plugin.BasicError
|
|
}
|
|
|
|
type ResourceProviderConfigureResponse struct {
|
|
Error *plugin.BasicError
|
|
}
|
|
|
|
type ResourceProviderInputArgs struct {
|
|
InputId uint32
|
|
Config *terraform.ResourceConfig
|
|
}
|
|
|
|
type ResourceProviderInputResponse struct {
|
|
Config *terraform.ResourceConfig
|
|
Error *plugin.BasicError
|
|
}
|
|
|
|
type ResourceProviderApplyArgs struct {
|
|
Info *terraform.InstanceInfo
|
|
State *terraform.InstanceState
|
|
Diff *terraform.InstanceDiff
|
|
}
|
|
|
|
type ResourceProviderApplyResponse struct {
|
|
State *terraform.InstanceState
|
|
Error *plugin.BasicError
|
|
}
|
|
|
|
type ResourceProviderDiffArgs struct {
|
|
Info *terraform.InstanceInfo
|
|
State *terraform.InstanceState
|
|
Config *terraform.ResourceConfig
|
|
}
|
|
|
|
type ResourceProviderDiffResponse struct {
|
|
Diff *terraform.InstanceDiff
|
|
Error *plugin.BasicError
|
|
}
|
|
|
|
type ResourceProviderRefreshArgs struct {
|
|
Info *terraform.InstanceInfo
|
|
State *terraform.InstanceState
|
|
}
|
|
|
|
type ResourceProviderRefreshResponse struct {
|
|
State *terraform.InstanceState
|
|
Error *plugin.BasicError
|
|
}
|
|
|
|
type ResourceProviderImportStateArgs struct {
|
|
Info *terraform.InstanceInfo
|
|
Id string
|
|
}
|
|
|
|
type ResourceProviderImportStateResponse struct {
|
|
State []*terraform.InstanceState
|
|
Error *plugin.BasicError
|
|
}
|
|
|
|
type ResourceProviderReadDataApplyArgs struct {
|
|
Info *terraform.InstanceInfo
|
|
Diff *terraform.InstanceDiff
|
|
}
|
|
|
|
type ResourceProviderReadDataApplyResponse struct {
|
|
State *terraform.InstanceState
|
|
Error *plugin.BasicError
|
|
}
|
|
|
|
type ResourceProviderReadDataDiffArgs struct {
|
|
Info *terraform.InstanceInfo
|
|
Config *terraform.ResourceConfig
|
|
}
|
|
|
|
type ResourceProviderReadDataDiffResponse struct {
|
|
Diff *terraform.InstanceDiff
|
|
Error *plugin.BasicError
|
|
}
|
|
|
|
type ResourceProviderValidateArgs struct {
|
|
Config *terraform.ResourceConfig
|
|
}
|
|
|
|
type ResourceProviderValidateResponse struct {
|
|
Warnings []string
|
|
Errors []*plugin.BasicError
|
|
}
|
|
|
|
type ResourceProviderValidateResourceArgs struct {
|
|
Config *terraform.ResourceConfig
|
|
Type string
|
|
}
|
|
|
|
type ResourceProviderValidateResourceResponse struct {
|
|
Warnings []string
|
|
Errors []*plugin.BasicError
|
|
}
|
|
|
|
func (s *ResourceProviderServer) Stop(
|
|
_ interface{},
|
|
reply *ResourceProviderStopResponse) error {
|
|
err := s.Provider.Stop()
|
|
*reply = ResourceProviderStopResponse{
|
|
Error: plugin.NewBasicError(err),
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProviderServer) GetSchema(
|
|
args *ResourceProviderGetSchemaArgs,
|
|
result *ResourceProviderGetSchemaResponse,
|
|
) error {
|
|
schema, err := s.Provider.GetSchema(args.Req)
|
|
result.Schema = schema
|
|
if err != nil {
|
|
result.Error = plugin.NewBasicError(err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProviderServer) Input(
|
|
args *ResourceProviderInputArgs,
|
|
reply *ResourceProviderInputResponse) error {
|
|
conn, err := s.Broker.Dial(args.InputId)
|
|
if err != nil {
|
|
*reply = ResourceProviderInputResponse{
|
|
Error: plugin.NewBasicError(err),
|
|
}
|
|
return nil
|
|
}
|
|
client := rpc.NewClient(conn)
|
|
defer client.Close()
|
|
|
|
input := &UIInput{Client: client}
|
|
|
|
config, err := s.Provider.Input(input, args.Config)
|
|
*reply = ResourceProviderInputResponse{
|
|
Config: config,
|
|
Error: plugin.NewBasicError(err),
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProviderServer) Validate(
|
|
args *ResourceProviderValidateArgs,
|
|
reply *ResourceProviderValidateResponse) error {
|
|
warns, errs := s.Provider.Validate(args.Config)
|
|
berrs := make([]*plugin.BasicError, len(errs))
|
|
for i, err := range errs {
|
|
berrs[i] = plugin.NewBasicError(err)
|
|
}
|
|
*reply = ResourceProviderValidateResponse{
|
|
Warnings: warns,
|
|
Errors: berrs,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProviderServer) ValidateResource(
|
|
args *ResourceProviderValidateResourceArgs,
|
|
reply *ResourceProviderValidateResourceResponse) error {
|
|
warns, errs := s.Provider.ValidateResource(args.Type, args.Config)
|
|
berrs := make([]*plugin.BasicError, len(errs))
|
|
for i, err := range errs {
|
|
berrs[i] = plugin.NewBasicError(err)
|
|
}
|
|
*reply = ResourceProviderValidateResourceResponse{
|
|
Warnings: warns,
|
|
Errors: berrs,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProviderServer) Configure(
|
|
config *terraform.ResourceConfig,
|
|
reply *ResourceProviderConfigureResponse) error {
|
|
err := s.Provider.Configure(config)
|
|
*reply = ResourceProviderConfigureResponse{
|
|
Error: plugin.NewBasicError(err),
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProviderServer) Apply(
|
|
args *ResourceProviderApplyArgs,
|
|
result *ResourceProviderApplyResponse) error {
|
|
state, err := s.Provider.Apply(args.Info, args.State, args.Diff)
|
|
*result = ResourceProviderApplyResponse{
|
|
State: state,
|
|
Error: plugin.NewBasicError(err),
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProviderServer) Diff(
|
|
args *ResourceProviderDiffArgs,
|
|
result *ResourceProviderDiffResponse) error {
|
|
diff, err := s.Provider.Diff(args.Info, args.State, args.Config)
|
|
*result = ResourceProviderDiffResponse{
|
|
Diff: diff,
|
|
Error: plugin.NewBasicError(err),
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProviderServer) Refresh(
|
|
args *ResourceProviderRefreshArgs,
|
|
result *ResourceProviderRefreshResponse) error {
|
|
newState, err := s.Provider.Refresh(args.Info, args.State)
|
|
*result = ResourceProviderRefreshResponse{
|
|
State: newState,
|
|
Error: plugin.NewBasicError(err),
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProviderServer) ImportState(
|
|
args *ResourceProviderImportStateArgs,
|
|
result *ResourceProviderImportStateResponse) error {
|
|
states, err := s.Provider.ImportState(args.Info, args.Id)
|
|
*result = ResourceProviderImportStateResponse{
|
|
State: states,
|
|
Error: plugin.NewBasicError(err),
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProviderServer) Resources(
|
|
nothing interface{},
|
|
result *[]terraform.ResourceType) error {
|
|
*result = s.Provider.Resources()
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProviderServer) ValidateDataSource(
|
|
args *ResourceProviderValidateResourceArgs,
|
|
reply *ResourceProviderValidateResourceResponse) error {
|
|
warns, errs := s.Provider.ValidateDataSource(args.Type, args.Config)
|
|
berrs := make([]*plugin.BasicError, len(errs))
|
|
for i, err := range errs {
|
|
berrs[i] = plugin.NewBasicError(err)
|
|
}
|
|
*reply = ResourceProviderValidateResourceResponse{
|
|
Warnings: warns,
|
|
Errors: berrs,
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProviderServer) ReadDataDiff(
|
|
args *ResourceProviderReadDataDiffArgs,
|
|
result *ResourceProviderReadDataDiffResponse) error {
|
|
diff, err := s.Provider.ReadDataDiff(args.Info, args.Config)
|
|
*result = ResourceProviderReadDataDiffResponse{
|
|
Diff: diff,
|
|
Error: plugin.NewBasicError(err),
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProviderServer) ReadDataApply(
|
|
args *ResourceProviderReadDataApplyArgs,
|
|
result *ResourceProviderReadDataApplyResponse) error {
|
|
newState, err := s.Provider.ReadDataApply(args.Info, args.Diff)
|
|
*result = ResourceProviderReadDataApplyResponse{
|
|
State: newState,
|
|
Error: plugin.NewBasicError(err),
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *ResourceProviderServer) DataSources(
|
|
nothing interface{},
|
|
result *[]terraform.DataSource) error {
|
|
*result = s.Provider.DataSources()
|
|
return nil
|
|
}
|