1package planfile
2
3import (
4	"archive/zip"
5	"fmt"
6	"os"
7	"time"
8
9	"github.com/hashicorp/terraform/internal/configs/configload"
10	"github.com/hashicorp/terraform/internal/plans"
11	"github.com/hashicorp/terraform/internal/states/statefile"
12)
13
14// Create creates a new plan file with the given filename, overwriting any
15// file that might already exist there.
16//
17// A plan file contains both a snapshot of the configuration and of the latest
18// state file in addition to the plan itself, so that Terraform can detect
19// if the world has changed since the plan was created and thus refuse to
20// apply it.
21func Create(filename string, configSnap *configload.Snapshot, prevStateFile, stateFile *statefile.File, plan *plans.Plan) error {
22	f, err := os.Create(filename)
23	if err != nil {
24		return err
25	}
26	defer f.Close()
27
28	zw := zip.NewWriter(f)
29	defer zw.Close()
30
31	// tfplan file
32	{
33		w, err := zw.CreateHeader(&zip.FileHeader{
34			Name:     tfplanFilename,
35			Method:   zip.Deflate,
36			Modified: time.Now(),
37		})
38		if err != nil {
39			return fmt.Errorf("failed to create tfplan file: %s", err)
40		}
41		err = writeTfplan(plan, w)
42		if err != nil {
43			return fmt.Errorf("failed to write plan: %s", err)
44		}
45	}
46
47	// tfstate file
48	{
49		w, err := zw.CreateHeader(&zip.FileHeader{
50			Name:     tfstateFilename,
51			Method:   zip.Deflate,
52			Modified: time.Now(),
53		})
54		if err != nil {
55			return fmt.Errorf("failed to create embedded tfstate file: %s", err)
56		}
57		err = statefile.Write(stateFile, w)
58		if err != nil {
59			return fmt.Errorf("failed to write state snapshot: %s", err)
60		}
61	}
62
63	// tfstate-prev file
64	{
65		w, err := zw.CreateHeader(&zip.FileHeader{
66			Name:     tfstatePreviousFilename,
67			Method:   zip.Deflate,
68			Modified: time.Now(),
69		})
70		if err != nil {
71			return fmt.Errorf("failed to create embedded tfstate-prev file: %s", err)
72		}
73		err = statefile.Write(prevStateFile, w)
74		if err != nil {
75			return fmt.Errorf("failed to write previous state snapshot: %s", err)
76		}
77	}
78
79	// tfconfig directory
80	{
81		err := writeConfigSnapshot(configSnap, zw)
82		if err != nil {
83			return fmt.Errorf("failed to write config snapshot: %s", err)
84		}
85	}
86
87	return nil
88}
89