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