github.com/opentofu/opentofu@v1.7.1/internal/builtin/providers/tf/provider.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package tf
     7  
     8  import (
     9  	"fmt"
    10  	"log"
    11  	"strings"
    12  
    13  	"github.com/opentofu/opentofu/internal/addrs"
    14  	"github.com/opentofu/opentofu/internal/encryption"
    15  	"github.com/opentofu/opentofu/internal/providers"
    16  )
    17  
    18  // Provider is an implementation of providers.Interface
    19  type Provider struct{}
    20  
    21  // NewProvider returns a new tofu provider
    22  func NewProvider() providers.Interface {
    23  	return &Provider{}
    24  }
    25  
    26  // GetSchema returns the complete schema for the provider.
    27  func (p *Provider) GetProviderSchema() providers.GetProviderSchemaResponse {
    28  	return providers.GetProviderSchemaResponse{
    29  		DataSources: map[string]providers.Schema{
    30  			"terraform_remote_state": dataSourceRemoteStateGetSchema(),
    31  		},
    32  		ResourceTypes: map[string]providers.Schema{
    33  			"terraform_data": dataStoreResourceSchema(),
    34  		},
    35  	}
    36  }
    37  
    38  // ValidateProviderConfig is used to validate the configuration values.
    39  func (p *Provider) ValidateProviderConfig(req providers.ValidateProviderConfigRequest) providers.ValidateProviderConfigResponse {
    40  	// At this moment there is nothing to configure for the tofu provider,
    41  	// so we will happily return without taking any action
    42  	var res providers.ValidateProviderConfigResponse
    43  	res.PreparedConfig = req.Config
    44  	return res
    45  }
    46  
    47  // ValidateDataResourceConfig is used to validate the data source configuration values.
    48  func (p *Provider) ValidateDataResourceConfig(req providers.ValidateDataResourceConfigRequest) providers.ValidateDataResourceConfigResponse {
    49  	// FIXME: move the backend configuration validate call that's currently
    50  	// inside the read method  into here so that we can catch provider configuration
    51  	// errors in tofu validate as well as during tofu plan.
    52  	var res providers.ValidateDataResourceConfigResponse
    53  
    54  	// This should not happen
    55  	if req.TypeName != "terraform_remote_state" {
    56  		res.Diagnostics.Append(fmt.Errorf("Error: unsupported data source %s", req.TypeName))
    57  		return res
    58  	}
    59  
    60  	diags := dataSourceRemoteStateValidate(req.Config)
    61  	res.Diagnostics = diags
    62  
    63  	return res
    64  }
    65  
    66  // Configure configures and initializes the provider.
    67  func (p *Provider) ConfigureProvider(providers.ConfigureProviderRequest) providers.ConfigureProviderResponse {
    68  	// At this moment there is nothing to configure for the terraform provider,
    69  	// so we will happily return without taking any action
    70  	var res providers.ConfigureProviderResponse
    71  	return res
    72  }
    73  
    74  // ReadDataSource returns the data source's current state.
    75  func (p *Provider) ReadDataSource(req providers.ReadDataSourceRequest) providers.ReadDataSourceResponse {
    76  	panic("Should not be called directly, special case for terraform_remote_state")
    77  }
    78  
    79  func (p *Provider) ReadDataSourceEncrypted(req providers.ReadDataSourceRequest, path addrs.AbsResourceInstance, enc encryption.Encryption) providers.ReadDataSourceResponse {
    80  	// call function
    81  	var res providers.ReadDataSourceResponse
    82  
    83  	// This should not happen
    84  	if req.TypeName != "terraform_remote_state" {
    85  		res.Diagnostics.Append(fmt.Errorf("Error: unsupported data source %s", req.TypeName))
    86  		return res
    87  	}
    88  
    89  	// These string manipulations are kind of funky
    90  	key := path.String()
    91  
    92  	// data.terraform_remote_state.foo[4] -> foo[4]
    93  	// module.submod[1].data.terraform_remote_state.bar -> module.submod[1].bar
    94  	key = strings.Replace(key, "data.terraform_remote_state.", "", 1)
    95  
    96  	// module.submod[1].bar -> submod[1].bar
    97  	key = strings.TrimPrefix(key, "module.")
    98  
    99  	log.Printf("[DEBUG] accessing remote state at %s", key)
   100  
   101  	newState, diags := dataSourceRemoteStateRead(req.Config, enc.RemoteState(key))
   102  
   103  	if diags.HasErrors() {
   104  		diags = diags.Append(fmt.Errorf("%s: Unable to read remote state", path.String()))
   105  	}
   106  
   107  	res.State = newState
   108  	res.Diagnostics = diags
   109  
   110  	return res
   111  }
   112  
   113  // Stop is called when the provider should halt any in-flight actions.
   114  func (p *Provider) Stop() error {
   115  	log.Println("[DEBUG] terraform provider cannot Stop")
   116  	return nil
   117  }
   118  
   119  // All the Resource-specific functions are below.
   120  // The terraform provider supplies a single data source, `terraform_remote_state`
   121  // and no resources.
   122  
   123  // UpgradeResourceState is called when the state loader encounters an
   124  // instance state whose schema version is less than the one reported by the
   125  // currently-used version of the corresponding provider, and the upgraded
   126  // result is used for any further processing.
   127  func (p *Provider) UpgradeResourceState(req providers.UpgradeResourceStateRequest) providers.UpgradeResourceStateResponse {
   128  	return upgradeDataStoreResourceState(req)
   129  }
   130  
   131  // ReadResource refreshes a resource and returns its current state.
   132  func (p *Provider) ReadResource(req providers.ReadResourceRequest) providers.ReadResourceResponse {
   133  	return readDataStoreResourceState(req)
   134  }
   135  
   136  // PlanResourceChange takes the current state and proposed state of a
   137  // resource, and returns the planned final state.
   138  func (p *Provider) PlanResourceChange(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
   139  	return planDataStoreResourceChange(req)
   140  }
   141  
   142  // ApplyResourceChange takes the planned state for a resource, which may
   143  // yet contain unknown computed values, and applies the changes returning
   144  // the final state.
   145  func (p *Provider) ApplyResourceChange(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
   146  	return applyDataStoreResourceChange(req)
   147  }
   148  
   149  // ImportResourceState requests that the given resource be imported.
   150  func (p *Provider) ImportResourceState(req providers.ImportResourceStateRequest) providers.ImportResourceStateResponse {
   151  	if req.TypeName == "terraform_data" {
   152  		return importDataStore(req)
   153  	}
   154  
   155  	panic("unimplemented - terraform_remote_state has no resources")
   156  }
   157  
   158  // ValidateResourceConfig is used to to validate the resource configuration values.
   159  func (p *Provider) ValidateResourceConfig(req providers.ValidateResourceConfigRequest) providers.ValidateResourceConfigResponse {
   160  	return validateDataStoreResourceConfig(req)
   161  }
   162  
   163  func (p *Provider) GetFunctions() providers.GetFunctionsResponse {
   164  	panic("unimplemented - terraform provider has no functions")
   165  }
   166  
   167  func (p *Provider) CallFunction(r providers.CallFunctionRequest) providers.CallFunctionResponse {
   168  	panic("unimplemented - terraform provider has no functions")
   169  }
   170  
   171  // Close is a noop for this provider, since it's run in-process.
   172  func (p *Provider) Close() error {
   173  	return nil
   174  }