github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/pluginmanager/state.go (about) 1 package pluginmanager 2 3 import ( 4 "encoding/json" 5 "log" 6 "os" 7 "syscall" 8 9 "github.com/hashicorp/go-plugin" 10 filehelpers "github.com/turbot/go-kit/files" 11 "github.com/turbot/steampipe/pkg/filepaths" 12 pb "github.com/turbot/steampipe/pkg/pluginmanager_service/grpc/proto" 13 "github.com/turbot/steampipe/pkg/utils" 14 ) 15 16 const PluginManagerStructVersion = 20220411 17 18 type State struct { 19 Protocol plugin.Protocol `json:"protocol"` 20 ProtocolVersion int `json:"protocol_version"` 21 Addr *pb.SimpleAddr `json:"addr"` 22 Pid int `json:"pid"` 23 // path to the steampipe executable 24 Executable string `json:"executable"` 25 // is the plugin manager running 26 Running bool `json:"-"` 27 StructVersion int64 `json:"struct_version"` 28 } 29 30 func NewState(executable string, reattach *plugin.ReattachConfig) *State { 31 return &State{ 32 Executable: executable, 33 Protocol: reattach.Protocol, 34 ProtocolVersion: reattach.ProtocolVersion, 35 Addr: pb.NewSimpleAddr(reattach.Addr), 36 Pid: reattach.Pid, 37 StructVersion: PluginManagerStructVersion, 38 } 39 } 40 41 func LoadState() (*State, error) { 42 // always return empty state 43 s := new(State) 44 if !filehelpers.FileExists(filepaths.PluginManagerStateFilePath()) { 45 log.Printf("[TRACE] plugin manager state file not found") 46 return s, nil 47 } 48 49 fileContent, err := os.ReadFile(filepaths.PluginManagerStateFilePath()) 50 if err != nil { 51 return s, err 52 } 53 err = json.Unmarshal(fileContent, s) 54 if err != nil { 55 log.Printf("[TRACE] failed to unmarshall plugin manager state file at %s with error %s\n", filepaths.PluginManagerStateFilePath(), err.Error()) 56 log.Printf("[TRACE] deleting invalid plugin manager state file\n") 57 s.delete() 58 return s, nil 59 } 60 61 // check is the manager is running - this deletes that state file if it is not running, 62 // and set the 'Running' property on the state if it is 63 pluginManagerRunning, err := s.verifyRunning() 64 if err != nil { 65 return s, err 66 } 67 // save the running status on the state struct 68 s.Running = pluginManagerRunning 69 70 // return error (which may be nil) 71 return s, err 72 } 73 74 func (s *State) Save() error { 75 // set struct version 76 s.StructVersion = PluginManagerStructVersion 77 78 content, err := json.MarshalIndent(s, "", " ") 79 if err != nil { 80 return err 81 } 82 return os.WriteFile(filepaths.PluginManagerStateFilePath(), content, 0644) 83 } 84 85 func (s *State) reattachConfig() *plugin.ReattachConfig { 86 return &plugin.ReattachConfig{ 87 Protocol: s.Protocol, 88 ProtocolVersion: s.ProtocolVersion, 89 Addr: *s.Addr, 90 Pid: s.Pid, 91 } 92 } 93 94 // check whether the plugin manager is running 95 func (s *State) verifyRunning() (bool, error) { 96 pidExists, err := utils.PidExists(s.Pid) 97 if err != nil { 98 return false, err 99 } 100 return pidExists, nil 101 } 102 103 // kill the plugin manager process and delete the state 104 func (s *State) kill() error { 105 // the state file contains the Pid of the daemon process - find and kill the process 106 process, err := utils.FindProcess(s.Pid) 107 if err != nil { 108 return err 109 } 110 if process == nil { 111 log.Printf("[TRACE] tried to kill plugin_manager, but couldn't find process (%d)", s.Pid) 112 return nil 113 } 114 // kill the plugin manager process by sending a SIGTERM (to give it a chance to clean up its children) 115 err = process.SendSignal(syscall.SIGTERM) 116 if err != nil { 117 log.Println("[TRACE] tried to kill plugin_manager, but couldn't send signal to process", err) 118 return err 119 } 120 // delete the state file as we have shutdown the plugin manager 121 s.delete() 122 return nil 123 } 124 125 func (s *State) delete() { 126 _ = os.Remove(filepaths.PluginManagerStateFilePath()) 127 }