Exemplo n.º 1
0
func testPlanFile(t *testing.T, plan *terraform.Plan) string {
	path := testTempFile(t)

	f, err := os.Create(path)
	if err != nil {
		t.Fatalf("err: %s", err)
	}
	defer f.Close()

	if err := terraform.WritePlan(plan, f); err != nil {
		t.Fatalf("err: %s", err)
	}

	return path
}
Exemplo n.º 2
0
func (c *PlanCommand) Run(args []string) int {
	var destroy, refresh, detailed bool
	var outPath string
	var moduleDepth int

	args = c.Meta.process(args, true)

	cmdFlags := c.Meta.flagSet("plan")
	cmdFlags.BoolVar(&destroy, "destroy", false, "destroy")
	cmdFlags.BoolVar(&refresh, "refresh", true, "refresh")
	c.addModuleDepthFlag(cmdFlags, &moduleDepth)
	cmdFlags.StringVar(&outPath, "out", "", "path")
	cmdFlags.IntVar(
		&c.Meta.parallelism, "parallelism", DefaultParallelism, "parallelism")
	cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
	cmdFlags.BoolVar(&detailed, "detailed-exitcode", false, "detailed-exitcode")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	var path string
	args = cmdFlags.Args()
	if len(args) > 1 {
		c.Ui.Error(
			"The plan command expects at most one argument with the path\n" +
				"to a Terraform configuration.\n")
		cmdFlags.Usage()
		return 1
	} else if len(args) == 1 {
		path = args[0]
	} else {
		var err error
		path, err = os.Getwd()
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error getting pwd: %s", err))
		}
	}

	countHook := new(CountHook)
	c.Meta.extraHooks = []terraform.Hook{countHook}

	// This is going to keep track of shadow errors
	var shadowErr error

	ctx, planned, err := c.Context(contextOpts{
		Destroy:     destroy,
		Path:        path,
		StatePath:   c.Meta.statePath,
		Parallelism: c.Meta.parallelism,
	})
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}
	if planned {
		c.Ui.Output(c.Colorize().Color(
			"[reset][bold][yellow]" +
				"The plan command received a saved plan file as input. This command\n" +
				"will output the saved plan. This will not modify the already-existing\n" +
				"plan. If you wish to generate a new plan, please pass in a configuration\n" +
				"directory as an argument.\n\n"))

		// Disable refreshing no matter what since we only want to show the plan
		refresh = false
	}

	err = terraform.SetDebugInfo(DefaultDataDir)
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	if err := ctx.Input(c.InputMode()); err != nil {
		c.Ui.Error(fmt.Sprintf("Error configuring: %s", err))
		return 1
	}

	// Record any shadow errors for later
	if err := ctx.ShadowError(); err != nil {
		shadowErr = multierror.Append(shadowErr, multierror.Prefix(
			err, "input operation:"))
	}

	if !validateContext(ctx, c.Ui) {
		return 1
	}

	if refresh {
		c.Ui.Output("Refreshing Terraform state in-memory prior to plan...")
		c.Ui.Output("The refreshed state will be used to calculate this plan, but")
		c.Ui.Output("will not be persisted to local or remote state storage.\n")
		_, err := ctx.Refresh()
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err))
			return 1
		}
		c.Ui.Output("")
	}

	plan, err := ctx.Plan()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error running plan: %s", err))
		return 1
	}

	if outPath != "" {
		log.Printf("[INFO] Writing plan output to: %s", outPath)
		f, err := os.Create(outPath)
		if err == nil {
			defer f.Close()
			err = terraform.WritePlan(plan, f)
		}
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error writing plan file: %s", err))
			return 1
		}
	}

	if plan.Diff.Empty() {
		c.Ui.Output(
			"No changes. Infrastructure is up-to-date. This means that Terraform\n" +
				"could not detect any differences between your configuration and\n" +
				"the real physical resources that exist. As a result, Terraform\n" +
				"doesn't need to do anything.")
		return 0
	}

	if outPath == "" {
		c.Ui.Output(strings.TrimSpace(planHeaderNoOutput) + "\n")
	} else {
		c.Ui.Output(fmt.Sprintf(
			strings.TrimSpace(planHeaderYesOutput)+"\n",
			outPath))
	}

	c.Ui.Output(FormatPlan(&FormatPlanOpts{
		Plan:        plan,
		Color:       c.Colorize(),
		ModuleDepth: moduleDepth,
	}))

	c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
		"[reset][bold]Plan:[reset] "+
			"%d to add, %d to change, %d to destroy.",
		countHook.ToAdd+countHook.ToRemoveAndAdd,
		countHook.ToChange,
		countHook.ToRemove+countHook.ToRemoveAndAdd)))

	// Record any shadow errors for later
	if err := ctx.ShadowError(); err != nil {
		shadowErr = multierror.Append(shadowErr, multierror.Prefix(
			err, "plan operation:"))
	}

	// If we have an error in the shadow graph, let the user know.
	c.outputShadowError(shadowErr, true)

	if detailed {
		return 2
	}
	return 0
}
Exemplo n.º 3
0
func (c *PlanCommand) Run(args []string) int {
	var destroy, refresh, detailed bool
	var outPath string
	var moduleDepth int

	args = c.Meta.process(args, true)

	cmdFlags := c.Meta.flagSet("plan")
	cmdFlags.BoolVar(&destroy, "destroy", false, "destroy")
	cmdFlags.BoolVar(&refresh, "refresh", true, "refresh")
	c.addModuleDepthFlag(cmdFlags, &moduleDepth)
	cmdFlags.StringVar(&outPath, "out", "", "path")
	cmdFlags.IntVar(
		&c.Meta.parallelism, "parallelism", DefaultParallelism, "parallelism")
	cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
	cmdFlags.BoolVar(&detailed, "detailed-exitcode", false, "detailed-exitcode")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	var path string
	args = cmdFlags.Args()
	if len(args) > 1 {
		c.Ui.Error(
			"The plan command expects at most one argument with the path\n" +
				"to a Terraform configuration.\n")
		cmdFlags.Usage()
		return 1
	} else if len(args) == 1 {
		path = args[0]
	} else {
		var err error
		path, err = os.Getwd()
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error getting pwd: %s", err))
		}
	}

	countHook := new(CountHook)
	c.Meta.extraHooks = []terraform.Hook{countHook}

	ctx, _, err := c.Context(contextOpts{
		Destroy:     destroy,
		Path:        path,
		StatePath:   c.Meta.statePath,
		Parallelism: c.Meta.parallelism,
	})
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}

	if err := ctx.Input(c.InputMode()); err != nil {
		c.Ui.Error(fmt.Sprintf("Error configuring: %s", err))
		return 1
	}

	if !validateContext(ctx, c.Ui) {
		return 1
	}

	if refresh {
		c.Ui.Output("Refreshing Terraform state in-memory prior to plan...")
		c.Ui.Output("The refreshed state will be used to calculate this plan, but")
		c.Ui.Output("will not be persisted to local or remote state storage.\n")
		_, err := ctx.Refresh()
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err))
			return 1
		}
		c.Ui.Output("")
	}

	plan, err := ctx.Plan()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error running plan: %s", err))
		return 1
	}

	if outPath != "" {
		log.Printf("[INFO] Writing plan output to: %s", outPath)
		f, err := os.Create(outPath)
		if err == nil {
			defer f.Close()
			err = terraform.WritePlan(plan, f)
		}
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error writing plan file: %s", err))
			return 1
		}
	}

	if plan.Diff.Empty() {
		c.Ui.Output(
			"No changes. Infrastructure is up-to-date. This means that Terraform\n" +
				"could not detect any differences between your configuration and\n" +
				"the real physical resources that exist. As a result, Terraform\n" +
				"doesn't need to do anything.")
		return 0
	}

	if outPath == "" {
		c.Ui.Output(strings.TrimSpace(planHeaderNoOutput) + "\n")
	} else {
		c.Ui.Output(fmt.Sprintf(
			strings.TrimSpace(planHeaderYesOutput)+"\n",
			outPath))
	}

	c.Ui.Output(FormatPlan(&FormatPlanOpts{
		Plan:        plan,
		Color:       c.Colorize(),
		ModuleDepth: moduleDepth,
	}))

	c.Ui.Output(c.Colorize().Color(fmt.Sprintf(
		"[reset][bold]Plan:[reset] "+
			"%d to add, %d to change, %d to destroy.",
		countHook.ToAdd+countHook.ToRemoveAndAdd,
		countHook.ToChange,
		countHook.ToRemove+countHook.ToRemoveAndAdd)))

	if detailed {
		return 2
	}
	return 0
}
Exemplo n.º 4
0
func (c *PlanCommand) Run(args []string) int {
	var destroy, refresh bool
	var outPath, statePath, backupPath string

	args = c.Meta.process(args, true)

	cmdFlags := c.Meta.flagSet("plan")
	cmdFlags.BoolVar(&destroy, "destroy", false, "destroy")
	cmdFlags.BoolVar(&refresh, "refresh", true, "refresh")
	cmdFlags.StringVar(&outPath, "out", "", "path")
	cmdFlags.StringVar(&statePath, "state", DefaultStateFilename, "path")
	cmdFlags.StringVar(&backupPath, "backup", "", "path")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	var path string
	args = cmdFlags.Args()
	if len(args) > 1 {
		c.Ui.Error(
			"The plan command expects at most one argument with the path\n" +
				"to a Terraform configuration.\n")
		cmdFlags.Usage()
		return 1
	} else if len(args) == 1 {
		path = args[0]
	} else {
		var err error
		path, err = os.Getwd()
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error getting pwd: %s", err))
		}
	}

	// If the default state path doesn't exist, ignore it.
	if statePath != "" {
		if _, err := os.Stat(statePath); err != nil {
			if os.IsNotExist(err) && statePath == DefaultStateFilename {
				statePath = ""
			}
		}
	}

	// If we don't specify a backup path, default to state out with
	// the extension
	if backupPath == "" {
		backupPath = statePath + DefaultBackupExtention
	}

	ctx, _, err := c.Context(path, statePath)
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}
	if !validateContext(ctx, c.Ui) {
		return 1
	}

	if refresh {
		// Create a backup of the state before updating
		if backupPath != "-" && c.state != nil {
			log.Printf("[INFO] Writing backup state to: %s", backupPath)
			f, err := os.Create(backupPath)
			if err == nil {
				err = terraform.WriteState(c.state, f)
				f.Close()
			}
			if err != nil {
				c.Ui.Error(fmt.Sprintf("Error writing backup state file: %s", err))
				return 1
			}
		}

		c.Ui.Output("Refreshing Terraform state prior to plan...\n")
		if _, err := ctx.Refresh(); err != nil {
			c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err))
			return 1
		}
		c.Ui.Output("")
	}

	plan, err := ctx.Plan(&terraform.PlanOpts{Destroy: destroy})
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error running plan: %s", err))
		return 1
	}

	if plan.Diff.Empty() {
		c.Ui.Output(
			"No changes. Infrastructure is up-to-date. This means that Terraform\n" +
				"could not detect any differences between your configuration and\n" +
				"the real physical resources that exist. As a result, Terraform\n" +
				"doesn't need to do anything.")
		return 0
	}

	if outPath != "" {
		log.Printf("[INFO] Writing plan output to: %s", outPath)
		f, err := os.Create(outPath)
		if err == nil {
			defer f.Close()
			err = terraform.WritePlan(plan, f)
		}
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error writing plan file: %s", err))
			return 1
		}
	}

	if outPath == "" {
		c.Ui.Output(strings.TrimSpace(planHeaderNoOutput) + "\n")
	} else {
		c.Ui.Output(fmt.Sprintf(
			strings.TrimSpace(planHeaderYesOutput)+"\n",
			outPath))
	}

	c.Ui.Output(FormatPlan(plan, c.Colorize()))

	return 0
}
Exemplo n.º 5
0
func (c *PlanCommand) Run(args []string) int {
	var destroy, refresh bool
	var outPath string
	var moduleDepth int

	args = c.Meta.process(args, true)

	cmdFlags := c.Meta.flagSet("plan")
	cmdFlags.BoolVar(&destroy, "destroy", false, "destroy")
	cmdFlags.BoolVar(&refresh, "refresh", true, "refresh")
	cmdFlags.IntVar(&moduleDepth, "module-depth", 0, "module-depth")
	cmdFlags.StringVar(&outPath, "out", "", "path")
	cmdFlags.StringVar(&c.Meta.statePath, "state", DefaultStateFilename, "path")
	cmdFlags.StringVar(&c.Meta.backupPath, "backup", "", "path")
	cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
	if err := cmdFlags.Parse(args); err != nil {
		return 1
	}

	var path string
	args = cmdFlags.Args()
	if len(args) > 1 {
		c.Ui.Error(
			"The plan command expects at most one argument with the path\n" +
				"to a Terraform configuration.\n")
		cmdFlags.Usage()
		return 1
	} else if len(args) == 1 {
		path = args[0]
	} else {
		var err error
		path, err = os.Getwd()
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error getting pwd: %s", err))
		}
	}

	ctx, _, err := c.Context(contextOpts{
		Path:      path,
		StatePath: c.Meta.statePath,
	})
	if err != nil {
		c.Ui.Error(err.Error())
		return 1
	}
	if !validateContext(ctx, c.Ui) {
		return 1
	}
	if err := ctx.Input(c.InputMode()); err != nil {
		c.Ui.Error(fmt.Sprintf("Error configuring: %s", err))
		return 1
	}

	if refresh {
		c.Ui.Output("Refreshing Terraform state prior to plan...\n")
		state, err := ctx.Refresh()
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error refreshing state: %s", err))
			return 1
		}
		c.Ui.Output("")

		if state != nil {
			log.Printf("[INFO] Writing state output to: %s", c.Meta.StateOutPath())
			if err := c.Meta.PersistState(state); err != nil {
				c.Ui.Error(fmt.Sprintf("Error writing state file: %s", err))
				return 1
			}
		}
	}

	plan, err := ctx.Plan(&terraform.PlanOpts{Destroy: destroy})
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Error running plan: %s", err))
		return 1
	}

	if plan.Diff.Empty() {
		c.Ui.Output(
			"No changes. Infrastructure is up-to-date. This means that Terraform\n" +
				"could not detect any differences between your configuration and\n" +
				"the real physical resources that exist. As a result, Terraform\n" +
				"doesn't need to do anything.")
		return 0
	}

	if outPath != "" {
		log.Printf("[INFO] Writing plan output to: %s", outPath)
		f, err := os.Create(outPath)
		if err == nil {
			defer f.Close()
			err = terraform.WritePlan(plan, f)
		}
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error writing plan file: %s", err))
			return 1
		}
	}

	if outPath == "" {
		c.Ui.Output(strings.TrimSpace(planHeaderNoOutput) + "\n")
	} else {
		c.Ui.Output(fmt.Sprintf(
			strings.TrimSpace(planHeaderYesOutput)+"\n",
			outPath))
	}

	c.Ui.Output(FormatPlan(&FormatPlanOpts{
		Plan:        plan,
		Color:       c.Colorize(),
		ModuleDepth: moduleDepth,
	}))

	return 0
}