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 }