func waitPts(ctx *VmContext) { conn, err := utils.UnixSocketConnect(ctx.TtySockName) if err != nil { glog.Error("Cannot connect to tty socket ", err.Error()) ctx.Hub <- &InitFailedEvent{ Reason: "Cannot connect to tty socket " + err.Error(), } return } glog.V(1).Info("tty socket connected") go waitTtyMessage(ctx, conn.(*net.UnixConn)) for { res, err := readTtyMessage(conn.(*net.UnixConn)) if err != nil { glog.V(1).Info("tty socket closed, quit the reading goroutine ", err.Error()) ctx.Hub <- &Interrupted{Reason: "tty socket failed " + err.Error()} close(ctx.ptys.channel) return } if len(res.Message) == 0 { glog.V(1).Infof("session %d closed by peer, close pty", res.Session) if ctx.vmHyperstartAPIVersion > 4242 { ctx.ptys.Close(ctx, res.Session) } else if ta, ok := ctx.ptys.ttys[res.Session]; ok { ta.closed = true } else { ctx.ptys.addEmptyPty(false, false, true, res.Session, 0) } } else if ta, ok := ctx.ptys.ttys[res.Session]; ok { if ta.closed { var code uint8 = 255 if len(res.Message) == 1 { code = uint8(res.Message[0]) } glog.V(1).Infof("session %d, exit code %d", res.Session, code) ctx.ptys.Close4242(ctx, res.Session, code) } else { for _, tty := range ta.attachments { if tty.Stdout != nil && res.Session == ta.stdioSeq { _, err := tty.Stdout.Write(res.Message) if err != nil { glog.V(1).Infof("fail to write session %d, close pty attachment", res.Session) ctx.ptys.Detach(ta, tty) } } if tty.Stderr != nil && res.Session == ta.stderrSeq { _, err := tty.Stderr.Write(res.Message) if err != nil { glog.V(1).Infof("fail to write session %d, close pty attachment", res.Session) ctx.ptys.Detach(ta, tty) } } } } } } }
func waitConsoleOutput(ctx *VmContext) { conn, err := utils.UnixSocketConnect(ctx.ConsoleSockName) if err != nil { glog.Error("failed to connected to ", ctx.ConsoleSockName, " ", err.Error()) return } glog.V(1).Info("connected to ", ctx.ConsoleSockName) tc, err := telnet.NewConn(conn) if err != nil { glog.Error("fail to init telnet connection to ", ctx.ConsoleSockName, ": ", err.Error()) return } glog.V(1).Infof("connected %s as telnet mode.", ctx.ConsoleSockName) cout := make(chan string, 128) go TtyLiner(tc, cout) for { line, ok := <-cout if ok { glog.V(1).Info("[console] ", line) } else { glog.Info("console output end") break } } }
func waitInitReady(ctx *VmContext) { conn, err := utils.UnixSocketConnect(ctx.HyperSockName) if err != nil { glog.Error("Cannot connect to hyper socket ", err.Error()) ctx.Hub <- &InitFailedEvent{ Reason: "Cannot connect to hyper socket " + err.Error(), } return } glog.Info("Wating for init messages...") msg, err := ReadVmMessage(conn.(*net.UnixConn)) if err != nil { glog.Error("read init message failed... ", err.Error()) ctx.Hub <- &InitFailedEvent{ Reason: "read init message failed... " + err.Error(), } conn.Close() } else if msg.Code == INIT_READY { glog.Info("Get init ready message") ctx.Hub <- &InitConnectedEvent{conn: conn.(*net.UnixConn)} go waitCmdToInit(ctx, conn.(*net.UnixConn)) } else { glog.Warningf("Get init message %d", msg.Code) ctx.Hub <- &InitFailedEvent{ Reason: fmt.Sprintf("Get init message %d", msg.Code), } conn.Close() } }
func runvRequest(root, name string, code uint32, msg interface{}) (net.Conn, error) { conn, err := utils.UnixSocketConnect(filepath.Join(root, name, "runv.sock")) if err != nil { return nil, err } cmd, err := json.Marshal(msg) if err != nil { conn.Close() return nil, err } m := &hypervisor.DecodedMessage{ Code: code, Message: cmd, } data := hypervisor.NewVmMessage(m) w, err := conn.Write(data[:]) if w != len(data) { err = fmt.Errorf("Not full write") // TODO } if err != nil { conn.Close() return nil, err } return conn, nil }
func connectToInit(ctx *VmContext) { conn, err := utils.UnixSocketConnect(ctx.HyperSockName) if err != nil { glog.Error("Cannot re-connect to hyper socket ", err.Error()) ctx.Hub <- &InitFailedEvent{ Reason: "Cannot re-connect to hyper socket " + err.Error(), } return } go waitCmdToInit(ctx, conn.(*net.UnixConn)) }
func waitPts(ctx *VmContext) { conn, err := utils.UnixSocketConnect(ctx.TtySockName) if err != nil { glog.Error("Cannot connect to tty socket ", err.Error()) ctx.Hub <- &InitFailedEvent{ Reason: "Cannot connect to tty socket " + err.Error(), } return } glog.V(1).Info("tty socket connected") go waitTtyMessage(ctx, conn.(*net.UnixConn)) for { res, err := readTtyMessage(conn.(*net.UnixConn)) if err != nil { glog.V(1).Info("tty socket closed, quit the reading goroutine ", err.Error()) ctx.Hub <- &Interrupted{Reason: "tty socket failed " + err.Error()} close(ctx.ptys.channel) return } if ta, ok := ctx.ptys.ttys[res.session]; ok { if len(res.message) == 0 { glog.V(1).Infof("session %d closed by peer, close pty", res.session) ta.closed = true } else if ta.closed { var code uint8 = 255 if len(res.message) == 1 { code = uint8(res.message[0]) } glog.V(1).Infof("session %d, exit code", res.session, code) ctx.ptys.Close(ctx, res.session, code) } else { for _, tty := range ta.attachments { if tty.Stdout != nil && tty.liner == nil { _, err = tty.Stdout.Write(res.message) } else if tty.Stdout != nil { m := tty.liner.Transform(res.message) if len(m) > 0 { _, err = tty.Stdout.Write(m) } } if err != nil { glog.V(1).Infof("fail to write session %d, close pty attachment", res.session) ctx.ptys.Detach(ctx, res.session, tty) } } } } } }
func waitConsoleOutput(ctx *VmContext) { conn, err := utils.UnixSocketConnect(ctx.ConsoleSockName) if err != nil { glog.Error("failed to connected to ", ctx.ConsoleSockName, " ", err.Error()) return } glog.V(1).Info("connected to ", ctx.ConsoleSockName) tc, err := telnet.NewConn(conn) if err != nil { glog.Error("fail to init telnet connection to ", ctx.ConsoleSockName, ": ", err.Error()) return } glog.V(1).Infof("connected %s as telnet mode.", ctx.ConsoleSockName) cout := make(chan string, 128) go TtyLiner(tc, cout) const ignoreLines = 128 for consoleLines := 0; consoleLines < ignoreLines; consoleLines++ { line, ok := <-cout if ok { ctx.Log(EXTRA, "[CNL] %s", line) } else { ctx.Log(INFO, "console output end") return } } if !ctx.LogLevel(EXTRA) { ctx.Log(DEBUG, "[CNL] omit the first %d line of console logs", ignoreLines) } for { line, ok := <-cout if ok { ctx.Log(DEBUG, "[CNL] %s", line) } else { ctx.Log(INFO, "console output end") return } } }
func waitInitReady(ctx *VmContext) { conn, err := utils.UnixSocketConnect(ctx.HyperSockName) if err != nil { glog.Error("Cannot connect to hyper socket ", err.Error()) ctx.Hub <- &InitFailedEvent{ Reason: "Cannot connect to hyper socket " + err.Error(), } return } if ctx.Boot.BootFromTemplate { glog.Info("boot from template") ctx.PauseState = PauseStatePaused ctx.Hub <- &InitConnectedEvent{conn: conn.(*net.UnixConn)} go waitCmdToInit(ctx, conn.(*net.UnixConn)) // TODO call getVMHyperstartAPIVersion(ctx) after unpaused return } glog.Info("Wating for init messages...") msg, err := ReadVmMessage(conn.(*net.UnixConn)) if err != nil { glog.Error("read init message failed... ", err.Error()) ctx.Hub <- &InitFailedEvent{ Reason: "read init message failed... " + err.Error(), } conn.Close() } else if msg.Code == hyperstartapi.INIT_READY { glog.Info("Get init ready message") ctx.Hub <- &InitConnectedEvent{conn: conn.(*net.UnixConn)} go waitCmdToInit(ctx, conn.(*net.UnixConn)) if !ctx.Boot.BootToBeTemplate { getVMHyperstartAPIVersion(ctx) } } else { glog.Warningf("Get init message %d", msg.Code) ctx.Hub <- &InitFailedEvent{ Reason: fmt.Sprintf("Get init message %d", msg.Code), } conn.Close() } }
func qmpInitializer(ctx *hypervisor.VmContext) { qc := qemuContext(ctx) conn, err := utils.UnixSocketConnect(qc.qmpSockName) if err != nil { glog.Error("failed to connected to ", qc.qmpSockName, " ", err.Error()) qc.qmp <- qmpFail(err.Error(), nil) return } glog.V(1).Info("connected to ", qc.qmpSockName) var msg map[string]interface{} decoder := json.NewDecoder(conn) defer func() { if err != nil { conn.Close() } }() glog.Info("begin qmp init...") err = decoder.Decode(&msg) if err != nil { glog.Error("get qmp welcome failed: ", err.Error()) qc.qmp <- qmpFail(err.Error(), nil) return } glog.Info("got qmp welcome, now sending command qmp_capabilities") cmd, err := json.Marshal(QmpCommand{Execute: "qmp_capabilities"}) if err != nil { glog.Error("qmp_capabilities marshal failed ", err.Error()) qc.qmp <- qmpFail(err.Error(), nil) return } _, err = conn.Write(cmd) if err != nil { glog.Error("qmp_capabilities send failed ", err.Error()) qc.qmp <- qmpFail(err.Error(), nil) return } glog.Info("waiting for response") rsp := &QmpResponse{} err = decoder.Decode(rsp) if err != nil { glog.Error("response receive failed ", err.Error()) qc.qmp <- qmpFail(err.Error(), nil) return } glog.Info("got for response") if rsp.msg.MessageType() == QMP_RESULT { glog.Info("QMP connection initialized") qc.qmp <- &QmpInit{ conn: conn.(*net.UnixConn), decoder: decoder, } return } qc.qmp <- qmpFail("handshake failed", nil) }