github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/cloud/cloudplan/saved_plan.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  package cloudplan
     4  
     5  import (
     6  	"encoding/json"
     7  	"errors"
     8  	"io"
     9  	"os"
    10  	"strings"
    11  )
    12  
    13  var ErrInvalidRemotePlanFormat = errors.New("invalid remote plan format, must be 1")
    14  var ErrInvalidRunID = errors.New("invalid run ID")
    15  var ErrInvalidHostname = errors.New("invalid hostname")
    16  
    17  type SavedPlanBookmark struct {
    18  	RemotePlanFormat int    `json:"remote_plan_format"`
    19  	RunID            string `json:"run_id"`
    20  	Hostname         string `json:"hostname"`
    21  }
    22  
    23  func NewSavedPlanBookmark(runID, hostname string) SavedPlanBookmark {
    24  	return SavedPlanBookmark{
    25  		RemotePlanFormat: 1,
    26  		RunID:            runID,
    27  		Hostname:         hostname,
    28  	}
    29  }
    30  
    31  func LoadSavedPlanBookmark(filepath string) (SavedPlanBookmark, error) {
    32  	bookmark := SavedPlanBookmark{}
    33  
    34  	file, err := os.Open(filepath)
    35  	if err != nil {
    36  		return bookmark, err
    37  	}
    38  	defer file.Close()
    39  
    40  	data, err := io.ReadAll(file)
    41  	if err != nil {
    42  		return bookmark, err
    43  	}
    44  
    45  	err = json.Unmarshal(data, &bookmark)
    46  	if err != nil {
    47  		return bookmark, err
    48  	}
    49  
    50  	// Note that these error cases are somewhat ambiguous, but they *likely*
    51  	// mean we're not looking at a saved plan bookmark at all. Since we're not
    52  	// certain about the format at this point, it doesn't quite make sense to
    53  	// emit a "known file type but bad" error struct the way we do over in the
    54  	// planfile and statefile packages.
    55  	if bookmark.RemotePlanFormat != 1 {
    56  		return bookmark, ErrInvalidRemotePlanFormat
    57  	} else if bookmark.Hostname == "" {
    58  		return bookmark, ErrInvalidHostname
    59  	} else if bookmark.RunID == "" || !strings.HasPrefix(bookmark.RunID, "run-") {
    60  		return bookmark, ErrInvalidRunID
    61  	}
    62  
    63  	return bookmark, err
    64  }
    65  
    66  func (s *SavedPlanBookmark) Save(filepath string) error {
    67  	data, _ := json.Marshal(s)
    68  
    69  	err := os.WriteFile(filepath, data, 0644)
    70  	if err != nil {
    71  		return err
    72  	}
    73  
    74  	return nil
    75  }