github.com/adrian-bl/terraform@v0.7.0-rc2.0.20160705220747-de0a34fc3517/terraform/semantics.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/go-multierror"
     7  	"github.com/hashicorp/terraform/config"
     8  	"github.com/hashicorp/terraform/dag"
     9  )
    10  
    11  // GraphSemanticChecker is the interface that semantic checks across
    12  // the entire Terraform graph implement.
    13  //
    14  // The graph should NOT be modified by the semantic checker.
    15  type GraphSemanticChecker interface {
    16  	Check(*dag.Graph) error
    17  }
    18  
    19  // UnorderedSemanticCheckRunner is an implementation of GraphSemanticChecker
    20  // that runs a list of SemanticCheckers against the vertices of the graph
    21  // in no specified order.
    22  type UnorderedSemanticCheckRunner struct {
    23  	Checks []SemanticChecker
    24  }
    25  
    26  func (sc *UnorderedSemanticCheckRunner) Check(g *dag.Graph) error {
    27  	var err error
    28  	for _, v := range g.Vertices() {
    29  		for _, check := range sc.Checks {
    30  			if e := check.Check(g, v); e != nil {
    31  				err = multierror.Append(err, e)
    32  			}
    33  		}
    34  	}
    35  
    36  	return err
    37  }
    38  
    39  // SemanticChecker is the interface that semantic checks across the
    40  // Terraform graph implement. Errors are accumulated. Even after an error
    41  // is returned, child vertices in the graph will still be visited.
    42  //
    43  // The graph should NOT be modified by the semantic checker.
    44  //
    45  // The order in which vertices are visited is left unspecified, so the
    46  // semantic checks should not rely on that.
    47  type SemanticChecker interface {
    48  	Check(*dag.Graph, dag.Vertex) error
    49  }
    50  
    51  // SemanticCheckModulesExist is an implementation of SemanticChecker that
    52  // verifies that all the modules that are referenced in the graph exist.
    53  type SemanticCheckModulesExist struct{}
    54  
    55  // TODO: test
    56  func (*SemanticCheckModulesExist) Check(g *dag.Graph, v dag.Vertex) error {
    57  	mn, ok := v.(*GraphNodeConfigModule)
    58  	if !ok {
    59  		return nil
    60  	}
    61  
    62  	if mn.Tree == nil {
    63  		return fmt.Errorf(
    64  			"module '%s' not found", mn.Module.Name)
    65  	}
    66  
    67  	return nil
    68  }
    69  
    70  // smcUserVariables does all the semantic checks to verify that the
    71  // variables given satisfy the configuration itself.
    72  func smcUserVariables(c *config.Config, vs map[string]string) []error {
    73  	var errs []error
    74  
    75  	cvs := make(map[string]*config.Variable)
    76  	for _, v := range c.Variables {
    77  		cvs[v.Name] = v
    78  	}
    79  
    80  	// Check that all required variables are present
    81  	required := make(map[string]struct{})
    82  	for _, v := range c.Variables {
    83  		if v.Required() {
    84  			required[v.Name] = struct{}{}
    85  		}
    86  	}
    87  	for k, _ := range vs {
    88  		delete(required, k)
    89  	}
    90  	if len(required) > 0 {
    91  		for k, _ := range required {
    92  			errs = append(errs, fmt.Errorf(
    93  				"Required variable not set: %s", k))
    94  		}
    95  	}
    96  
    97  	// Check that types match up
    98  	for k, _ := range vs {
    99  		v, ok := cvs[k]
   100  		if !ok {
   101  			continue
   102  		}
   103  
   104  		if v.Type() != config.VariableTypeString {
   105  			errs = append(errs, fmt.Errorf(
   106  				"%s: cannot assign string value to map type",
   107  				k))
   108  		}
   109  	}
   110  
   111  	// TODO(mitchellh): variables that are unknown
   112  
   113  	return errs
   114  }