github.com/Cloud-Foundations/Dominator@v0.3.4/hypervisor/manager/qemuMonitor.go (about) 1 package manager 2 3 import ( 4 "encoding/json" 5 "io" 6 "net" 7 8 proto "github.com/Cloud-Foundations/Dominator/proto/hypervisor" 9 ) 10 11 type copyingReader struct { 12 copyChannel chan<- byte 13 r io.Reader 14 } 15 16 type monitorMessageType struct { 17 Data json.RawMessage `json:data",omitempty"` 18 Event string `json:event",omitempty"` 19 Timestamp monitorTimestampType `json:timestamp",omitempty"` 20 } 21 22 type monitorTimestampType struct { 23 Microseconds int64 `json:microseconds",omitempty"` 24 Seconds int64 `json:seconds",omitempty"` 25 } 26 27 type shutdownDataType struct { 28 Guest bool `json:guest",omitempty"` 29 Reason string `json:reason",omitempty"` 30 } 31 32 func (r *copyingReader) Read(p []byte) (int, error) { 33 nRead, err := r.r.Read(p) 34 for index := 0; index < nRead; index++ { 35 select { 36 case r.copyChannel <- p[index]: 37 default: 38 } 39 } 40 return nRead, err 41 } 42 43 func (vm *vmInfoType) processMonitorResponses(monitorSock net.Conn, 44 commandOutput chan<- byte) { 45 reader := ©ingReader{commandOutput, monitorSock} 46 decoder := json.NewDecoder(reader) 47 var guestShutdown, hostQuit bool 48 for { 49 var message monitorMessageType 50 if err := decoder.Decode(&message); err != nil { 51 if err == io.EOF { 52 if !guestShutdown && !hostQuit { 53 vm.logger.Debugln(0, "EOF on monitor socket") 54 } 55 break 56 } 57 vm.logger.Printf("error reading monitor message: %s\n", err) 58 } 59 if message.Event != "SHUTDOWN" { 60 continue 61 } 62 var shutdownData shutdownDataType 63 if err := json.Unmarshal(message.Data, &shutdownData); err != nil { 64 vm.logger.Printf("error unmarshaling shutdown event data: %s\n", 65 err) 66 continue 67 } 68 vm.logger.Debugf(0, "VM shutdown, guest: %v, reason: %s\n", 69 shutdownData.Guest, shutdownData.Reason) 70 if shutdownData.Guest && shutdownData.Reason == "guest-shutdown" { 71 guestShutdown = true 72 } else if shutdownData.Reason == "host-qmp-quit" { 73 hostQuit = true // Not currently used but may be useful later. 74 } 75 } 76 close(commandOutput) 77 vm.mutex.Lock() 78 defer vm.mutex.Unlock() 79 close(vm.commandInput) 80 vm.commandInput = nil 81 vm.commandOutput = nil 82 switch vm.State { 83 case proto.StateStarting: 84 select { 85 case vm.stoppedNotifier <- struct{}{}: 86 default: 87 } 88 return 89 case proto.StateRunning, proto.StateDebugging: 90 if !vm.manager.shuttingDown && guestShutdown { 91 if vm.DestroyOnPowerdown && !vm.DestroyProtection { 92 vm.delete() 93 vm.logger.Debugln(0, "VM destroyed due to guest powerdown") 94 } else { 95 vm.setState(proto.StateStopped) 96 vm.logger.Debugln(0, "VM stopped due to guest powerdown") 97 } 98 } else { 99 vm.setState(proto.StateCrashed) 100 } 101 select { 102 case vm.stoppedNotifier <- struct{}{}: 103 default: 104 } 105 return 106 case proto.StateFailedToStart: 107 return 108 case proto.StateStopping: 109 vm.setState(proto.StateStopped) 110 select { 111 case vm.stoppedNotifier <- struct{}{}: 112 default: 113 } 114 case proto.StateStopped: 115 return 116 case proto.StateDestroying: 117 vm.delete() 118 return 119 case proto.StateMigrating: 120 return 121 case proto.StateExporting: 122 return 123 case proto.StateCrashed: 124 vm.logger.Println("monitor socket closed on already crashed VM") 125 return 126 default: 127 vm.logger.Println("unknown state: " + vm.State.String()) 128 } 129 }