mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-30 10:47:14 -06:00
183 lines
5.1 KiB
Go
183 lines
5.1 KiB
Go
package terraform
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/terraform/config"
|
|
)
|
|
|
|
// ResourceProvider is an interface that must be implemented by any
|
|
// resource provider: the thing that creates and manages the resources in
|
|
// a Terraform configuration.
|
|
type ResourceProvider interface {
|
|
// Validate is called once at the beginning with the raw configuration
|
|
// (no interpolation done) and can return a list of warnings and/or
|
|
// errors.
|
|
//
|
|
// This is called once with the provider configuration only. It may not
|
|
// be called at all if no provider configuration is given.
|
|
//
|
|
// This should not assume that any values of the configurations are valid.
|
|
// The primary use case of this call is to check that required keys are
|
|
// set.
|
|
Validate(*ResourceConfig) ([]string, []error)
|
|
|
|
// ValidateResource is called once at the beginning with the raw
|
|
// configuration (no interpolation done) and can return a list of warnings
|
|
// and/or errors.
|
|
//
|
|
// This is called once per resource.
|
|
//
|
|
// This should not assume any of the values in the resource configuration
|
|
// are valid since it is possible they have to be interpolated still.
|
|
// The primary use case of this call is to check that the required keys
|
|
// are set and that the general structure is correct.
|
|
ValidateResource(string, *ResourceConfig) ([]string, []error)
|
|
|
|
// Configure configures the provider itself with the configuration
|
|
// given. This is useful for setting things like access keys.
|
|
//
|
|
// This won't be called at all if no provider configuration is given.
|
|
//
|
|
// Configure returns an error if it occurred.
|
|
Configure(*ResourceConfig) error
|
|
|
|
// Resources returns all the available resource types that this provider
|
|
// knows how to manage.
|
|
Resources() []ResourceType
|
|
|
|
// Apply applies a diff to a specific resource and returns the new
|
|
// resource state along with an error.
|
|
//
|
|
// If the resource state given has an empty ID, then a new resource
|
|
// is expected to be created.
|
|
Apply(
|
|
*ResourceState,
|
|
*ResourceDiff) (*ResourceState, error)
|
|
|
|
// Diff diffs a resource versus a desired state and returns
|
|
// a diff.
|
|
Diff(
|
|
*ResourceState,
|
|
*ResourceConfig) (*ResourceDiff, error)
|
|
|
|
// Refresh refreshes a resource and updates all of its attributes
|
|
// with the latest information.
|
|
Refresh(*ResourceState) (*ResourceState, error)
|
|
}
|
|
|
|
// ResourceConfig holds the configuration given for a resource. This is
|
|
// done instead of a raw `map[string]interface{}` type so that rich
|
|
// methods can be added to it to make dealing with it easier.
|
|
type ResourceConfig struct {
|
|
ComputedKeys []string
|
|
Raw map[string]interface{}
|
|
Config map[string]interface{}
|
|
}
|
|
|
|
// ResourceType is a type of resource that a resource provider can manage.
|
|
type ResourceType struct {
|
|
Name string
|
|
}
|
|
|
|
// ResourceProviderFactory is a function type that creates a new instance
|
|
// of a resource provider.
|
|
type ResourceProviderFactory func() (ResourceProvider, error)
|
|
|
|
// NewResourceConfig creates a new ResourceConfig from a config.RawConfig.
|
|
func NewResourceConfig(c *config.RawConfig) *ResourceConfig {
|
|
return &ResourceConfig{
|
|
ComputedKeys: c.UnknownKeys(),
|
|
Raw: c.Raw,
|
|
Config: c.Config(),
|
|
}
|
|
}
|
|
|
|
// CheckSet checks that the given list of configuration keys is
|
|
// properly set. If not, errors are returned for each unset key.
|
|
//
|
|
// This is useful to be called in the Validate method of a ResourceProvider.
|
|
func (c *ResourceConfig) CheckSet(keys []string) []error {
|
|
var errs []error
|
|
|
|
for _, k := range keys {
|
|
if !c.IsSet(k) {
|
|
errs = append(errs, fmt.Errorf("%s must be set", k))
|
|
}
|
|
}
|
|
|
|
return errs
|
|
}
|
|
|
|
// Get looks up a configuration value by key and returns the value.
|
|
//
|
|
// The second return value is true if the get was successful. Get will
|
|
// not succeed if the value is being computed.
|
|
func (c *ResourceConfig) Get(k string) (interface{}, bool) {
|
|
parts := strings.Split(k, ".")
|
|
|
|
var current interface{} = c.Raw
|
|
for _, part := range parts {
|
|
if current == nil {
|
|
return nil, false
|
|
}
|
|
|
|
cv := reflect.ValueOf(current)
|
|
switch cv.Kind() {
|
|
case reflect.Map:
|
|
v := cv.MapIndex(reflect.ValueOf(part))
|
|
if !v.IsValid() {
|
|
return nil, false
|
|
}
|
|
current = v.Interface()
|
|
case reflect.Slice:
|
|
i, err := strconv.ParseInt(part, 0, 0)
|
|
if err != nil {
|
|
return nil, false
|
|
}
|
|
current = cv.Index(int(i)).Interface()
|
|
default:
|
|
panic(fmt.Sprintf("Unknown kind: %s", cv.Kind()))
|
|
}
|
|
}
|
|
|
|
return current, true
|
|
}
|
|
|
|
// IsSet checks if the key in the configuration is set. A key is set if
|
|
// it has a value or the value is being computed (is unknown currently).
|
|
//
|
|
// This function should be used rather than checking the keys of the
|
|
// raw configuration itself, since a key may be omitted from the raw
|
|
// configuration if it is being computed.
|
|
func (c *ResourceConfig) IsSet(k string) bool {
|
|
if c == nil {
|
|
return false
|
|
}
|
|
|
|
for _, ck := range c.ComputedKeys {
|
|
if ck == k {
|
|
return true
|
|
}
|
|
}
|
|
|
|
if _, ok := c.Get(k); ok {
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func ProviderSatisfies(p ResourceProvider, n string) bool {
|
|
for _, rt := range p.Resources() {
|
|
if rt.Name == n {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|