github.com/trawler/terraform@v0.10.8-0.20171106022149-4b1c7a1d9b48/command/meta_new.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"os"
     7  	"path/filepath"
     8  	"strconv"
     9  
    10  	"github.com/hashicorp/errwrap"
    11  	"github.com/hashicorp/terraform/config"
    12  	"github.com/hashicorp/terraform/config/module"
    13  	"github.com/hashicorp/terraform/terraform"
    14  )
    15  
    16  // NOTE: Temporary file until this branch is cleaned up.
    17  
    18  // Input returns whether or not input asking is enabled.
    19  func (m *Meta) Input() bool {
    20  	if test || !m.input {
    21  		return false
    22  	}
    23  
    24  	if envVar := os.Getenv(InputModeEnvVar); envVar != "" {
    25  		if v, err := strconv.ParseBool(envVar); err == nil && !v {
    26  			return false
    27  		}
    28  	}
    29  
    30  	return true
    31  }
    32  
    33  // Module loads the module tree for the given root path.
    34  //
    35  // It expects the modules to already be downloaded. This will never
    36  // download any modules.
    37  func (m *Meta) Module(path string) (*module.Tree, error) {
    38  	mod, err := module.NewTreeModule("", path)
    39  	if err != nil {
    40  		// Check for the error where we have no config files
    41  		if errwrap.ContainsType(err, new(config.ErrNoConfigsFound)) {
    42  			return nil, nil
    43  		}
    44  
    45  		return nil, err
    46  	}
    47  
    48  	err = mod.Load(m.moduleStorage(m.DataDir(), module.GetModeNone))
    49  	if err != nil {
    50  		return nil, errwrap.Wrapf("Error loading modules: {{err}}", err)
    51  	}
    52  
    53  	return mod, nil
    54  }
    55  
    56  // Config loads the root config for the path specified. Path may be a directory
    57  // or file. The absence of configuration is not an error and returns a nil Config.
    58  func (m *Meta) Config(path string) (*config.Config, error) {
    59  	// If no explicit path was given then it is okay for there to be
    60  	// no backend configuration found.
    61  	emptyOk := path == ""
    62  
    63  	// If we had no path set, it is an error. We can't initialize unset
    64  	if path == "" {
    65  		path = "."
    66  	}
    67  
    68  	// Expand the path
    69  	if !filepath.IsAbs(path) {
    70  		var err error
    71  		path, err = filepath.Abs(path)
    72  		if err != nil {
    73  			return nil, fmt.Errorf(
    74  				"Error expanding path to backend config %q: %s", path, err)
    75  		}
    76  	}
    77  
    78  	log.Printf("[DEBUG] command: loading backend config file: %s", path)
    79  
    80  	// We first need to determine if we're loading a file or a directory.
    81  	fi, err := os.Stat(path)
    82  	if err != nil {
    83  		if os.IsNotExist(err) && emptyOk {
    84  			log.Printf(
    85  				"[INFO] command: backend config not found, returning nil: %s",
    86  				path)
    87  			return nil, nil
    88  		}
    89  
    90  		return nil, err
    91  	}
    92  
    93  	var f func(string) (*config.Config, error) = config.LoadFile
    94  	if fi.IsDir() {
    95  		f = config.LoadDir
    96  	}
    97  
    98  	// Load the configuration
    99  	c, err := f(path)
   100  	if err != nil {
   101  		// Check for the error where we have no config files and return nil
   102  		// as the configuration type.
   103  		if errwrap.ContainsType(err, new(config.ErrNoConfigsFound)) {
   104  			log.Printf(
   105  				"[INFO] command: backend config not found, returning nil: %s",
   106  				path)
   107  			return nil, nil
   108  		}
   109  
   110  		return nil, err
   111  	}
   112  
   113  	return c, nil
   114  }
   115  
   116  // Plan returns the plan for the given path.
   117  //
   118  // This only has an effect if the path itself looks like a plan.
   119  // If error is nil and the plan is nil, then the path didn't look like
   120  // a plan.
   121  //
   122  // Error will be non-nil if path looks like a plan and loading the plan
   123  // failed.
   124  func (m *Meta) Plan(path string) (*terraform.Plan, error) {
   125  	// Open the path no matter if its a directory or file
   126  	f, err := os.Open(path)
   127  	defer f.Close()
   128  	if err != nil {
   129  		return nil, fmt.Errorf(
   130  			"Failed to load Terraform configuration or plan: %s", err)
   131  	}
   132  
   133  	// Stat it so we can check if its a directory
   134  	fi, err := f.Stat()
   135  	if err != nil {
   136  		return nil, fmt.Errorf(
   137  			"Failed to load Terraform configuration or plan: %s", err)
   138  	}
   139  
   140  	// If this path is a directory, then it can't be a plan. Not an error.
   141  	if fi.IsDir() {
   142  		return nil, nil
   143  	}
   144  
   145  	// Read the plan
   146  	p, err := terraform.ReadPlan(f)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  
   151  	// We do a validation here that seems odd but if any plan is given,
   152  	// we must not have set any extra variables. The plan itself contains
   153  	// the variables and those aren't overwritten.
   154  	if len(m.variables) > 0 {
   155  		return nil, fmt.Errorf(
   156  			"You can't set variables with the '-var' or '-var-file' flag\n" +
   157  				"when you're applying a plan file. The variables used when\n" +
   158  				"the plan was created will be used. If you wish to use different\n" +
   159  				"variable values, create a new plan file.")
   160  	}
   161  
   162  	return p, nil
   163  }