summaryrefslogtreecommitdiff
path: root/vendor/github.com/hashicorp/terraform/terraform/eval_validate.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform/eval_validate.go')
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/eval_validate.go227
1 files changed, 227 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_validate.go b/vendor/github.com/hashicorp/terraform/terraform/eval_validate.go
new file mode 100644
index 00000000..478aa640
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/terraform/eval_validate.go
@@ -0,0 +1,227 @@
+package terraform
+
+import (
+ "fmt"
+
+ "github.com/hashicorp/terraform/config"
+ "github.com/mitchellh/mapstructure"
+)
+
+// EvalValidateError is the error structure returned if there were
+// validation errors.
+type EvalValidateError struct {
+ Warnings []string
+ Errors []error
+}
+
+func (e *EvalValidateError) Error() string {
+ return fmt.Sprintf("Warnings: %s. Errors: %s", e.Warnings, e.Errors)
+}
+
+// EvalValidateCount is an EvalNode implementation that validates
+// the count of a resource.
+type EvalValidateCount struct {
+ Resource *config.Resource
+}
+
+// TODO: test
+func (n *EvalValidateCount) Eval(ctx EvalContext) (interface{}, error) {
+ var count int
+ var errs []error
+ var err error
+ if _, err := ctx.Interpolate(n.Resource.RawCount, nil); err != nil {
+ errs = append(errs, fmt.Errorf(
+ "Failed to interpolate count: %s", err))
+ goto RETURN
+ }
+
+ count, err = n.Resource.Count()
+ if err != nil {
+ // If we can't get the count during validation, then
+ // just replace it with the number 1.
+ c := n.Resource.RawCount.Config()
+ c[n.Resource.RawCount.Key] = "1"
+ count = 1
+ }
+ err = nil
+
+ if count < 0 {
+ errs = append(errs, fmt.Errorf(
+ "Count is less than zero: %d", count))
+ }
+
+RETURN:
+ if len(errs) != 0 {
+ err = &EvalValidateError{
+ Errors: errs,
+ }
+ }
+ return nil, err
+}
+
+// EvalValidateProvider is an EvalNode implementation that validates
+// the configuration of a resource.
+type EvalValidateProvider struct {
+ Provider *ResourceProvider
+ Config **ResourceConfig
+}
+
+func (n *EvalValidateProvider) Eval(ctx EvalContext) (interface{}, error) {
+ provider := *n.Provider
+ config := *n.Config
+
+ warns, errs := provider.Validate(config)
+ if len(warns) == 0 && len(errs) == 0 {
+ return nil, nil
+ }
+
+ return nil, &EvalValidateError{
+ Warnings: warns,
+ Errors: errs,
+ }
+}
+
+// EvalValidateProvisioner is an EvalNode implementation that validates
+// the configuration of a resource.
+type EvalValidateProvisioner struct {
+ Provisioner *ResourceProvisioner
+ Config **ResourceConfig
+ ConnConfig **ResourceConfig
+}
+
+func (n *EvalValidateProvisioner) Eval(ctx EvalContext) (interface{}, error) {
+ provisioner := *n.Provisioner
+ config := *n.Config
+ var warns []string
+ var errs []error
+
+ {
+ // Validate the provisioner's own config first
+ w, e := provisioner.Validate(config)
+ warns = append(warns, w...)
+ errs = append(errs, e...)
+ }
+
+ {
+ // Now validate the connection config, which might either be from
+ // the provisioner block itself or inherited from the resource's
+ // shared connection info.
+ w, e := n.validateConnConfig(*n.ConnConfig)
+ warns = append(warns, w...)
+ errs = append(errs, e...)
+ }
+
+ if len(warns) == 0 && len(errs) == 0 {
+ return nil, nil
+ }
+
+ return nil, &EvalValidateError{
+ Warnings: warns,
+ Errors: errs,
+ }
+}
+
+func (n *EvalValidateProvisioner) validateConnConfig(connConfig *ResourceConfig) (warns []string, errs []error) {
+ // We can't comprehensively validate the connection config since its
+ // final structure is decided by the communicator and we can't instantiate
+ // that until we have a complete instance state. However, we *can* catch
+ // configuration keys that are not valid for *any* communicator, catching
+ // typos early rather than waiting until we actually try to run one of
+ // the resource's provisioners.
+
+ type connConfigSuperset struct {
+ // All attribute types are interface{} here because at this point we
+ // may still have unresolved interpolation expressions, which will
+ // appear as strings regardless of the final goal type.
+
+ Type interface{} `mapstructure:"type"`
+ User interface{} `mapstructure:"user"`
+ Password interface{} `mapstructure:"password"`
+ Host interface{} `mapstructure:"host"`
+ Port interface{} `mapstructure:"port"`
+ Timeout interface{} `mapstructure:"timeout"`
+ ScriptPath interface{} `mapstructure:"script_path"`
+
+ // For type=ssh only (enforced in ssh communicator)
+ PrivateKey interface{} `mapstructure:"private_key"`
+ Agent interface{} `mapstructure:"agent"`
+ BastionHost interface{} `mapstructure:"bastion_host"`
+ BastionPort interface{} `mapstructure:"bastion_port"`
+ BastionUser interface{} `mapstructure:"bastion_user"`
+ BastionPassword interface{} `mapstructure:"bastion_password"`
+ BastionPrivateKey interface{} `mapstructure:"bastion_private_key"`
+
+ // For type=winrm only (enforced in winrm communicator)
+ HTTPS interface{} `mapstructure:"https"`
+ Insecure interface{} `mapstructure:"insecure"`
+ CACert interface{} `mapstructure:"cacert"`
+ }
+
+ var metadata mapstructure.Metadata
+ decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
+ Metadata: &metadata,
+ Result: &connConfigSuperset{}, // result is disregarded; we only care about unused keys
+ })
+ if err != nil {
+ // should never happen
+ errs = append(errs, err)
+ return
+ }
+
+ if err := decoder.Decode(connConfig.Config); err != nil {
+ errs = append(errs, err)
+ return
+ }
+
+ for _, attrName := range metadata.Unused {
+ errs = append(errs, fmt.Errorf("unknown 'connection' argument %q", attrName))
+ }
+ return
+}
+
+// EvalValidateResource is an EvalNode implementation that validates
+// the configuration of a resource.
+type EvalValidateResource struct {
+ Provider *ResourceProvider
+ Config **ResourceConfig
+ ResourceName string
+ ResourceType string
+ ResourceMode config.ResourceMode
+
+ // IgnoreWarnings means that warnings will not be passed through. This allows
+ // "just-in-time" passes of validation to continue execution through warnings.
+ IgnoreWarnings bool
+}
+
+func (n *EvalValidateResource) Eval(ctx EvalContext) (interface{}, error) {
+ provider := *n.Provider
+ cfg := *n.Config
+ var warns []string
+ var errs []error
+ // Provider entry point varies depending on resource mode, because
+ // managed resources and data resources are two distinct concepts
+ // in the provider abstraction.
+ switch n.ResourceMode {
+ case config.ManagedResourceMode:
+ warns, errs = provider.ValidateResource(n.ResourceType, cfg)
+ case config.DataResourceMode:
+ warns, errs = provider.ValidateDataSource(n.ResourceType, cfg)
+ }
+
+ // If the resource name doesn't match the name regular
+ // expression, show an error.
+ if !config.NameRegexp.Match([]byte(n.ResourceName)) {
+ errs = append(errs, fmt.Errorf(
+ "%s: resource name can only contain letters, numbers, "+
+ "dashes, and underscores.", n.ResourceName))
+ }
+
+ if (len(warns) == 0 || n.IgnoreWarnings) && len(errs) == 0 {
+ return nil, nil
+ }
+
+ return nil, &EvalValidateError{
+ Warnings: warns,
+ Errors: errs,
+ }
+}