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 := &copyingReader{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  }