func runvGetTag(conn net.Conn) (tag string, err error) { msg, err := hypervisor.ReadVmMessage(conn.(*net.UnixConn)) if err != nil { fmt.Printf("read runv server data failed: %v\n", err) return "", err } if msg.Code != RUNV_ACK { return "", fmt.Errorf("unexpected respond code") } return string(msg.Message), nil }
// stdin/stdout <-> conn func containerTtySplice(root, container string, conn net.Conn, isContainer bool) (int, error) { tag, err := runvGetTag(conn) if err != nil { return -1, err } fmt.Printf("tag=%s\n", tag) outFd, isTerminalOut := term.GetFdInfo(os.Stdout) newTty(root, container, tag, outFd, isTerminalOut).monitorTtySize() _, err = term.TtySplice(conn) if err != nil { return -1, err } cmd := &ttyTagCmd{Root: root, Container: "", Tag: tag} if isContainer { cmd.Container = container } conn, err = runvRequest(root, container, RUNV_EXITSTATUS, cmd) if err != nil { fmt.Printf("runvRequest failed: %v\n", err) return -1, err } defer conn.Close() msg, err := hypervisor.ReadVmMessage(conn.(*net.UnixConn)) if err != nil { fmt.Printf("read runv server data failed: %v\n", err) return -1, err } if msg.Code != RUNV_EXITSTATUS { return -1, fmt.Errorf("unexpected respond code") } return int(msg.Message[0]), nil }
func HandleRunvRequest(context *nsContext, info *hypervisor.ContainerInfo, conn net.Conn) { defer context.wg.Done() defer conn.Close() msg, err := hypervisor.ReadVmMessage(conn.(*net.UnixConn)) if err != nil { fmt.Printf("read runv client data failed: %v\n", err) return } switch msg.Code { case RUNV_INITCONTAINER: { initCmd := &initContainerCmd{} err = json.Unmarshal(msg.Message, initCmd) if err != nil { fmt.Printf("parse runv init container command failed: %v\n", err) return } startVContainer(context, initCmd.Root, initCmd.Name) } case RUNV_EXECCMD: { tag, _ := runvAllocAndRespondTag(conn) fmt.Printf("client exec cmd request %s\n", msg.Message[:]) tty := &hypervisor.TtyIO{ ClientTag: tag, Stdin: conn, Stdout: conn, Callback: make(chan *types.VmResponse, 1), } context.Lock() context.ttyList[tag] = tty context.Unlock() err = context.vm.Exec(tty, info.Id, string(msg.Message[:])) if err != nil { fmt.Printf("read runv client data failed: %v\n", err) } } case RUNV_EXITSTATUS: { var code uint8 = 255 tagCmd := &ttyTagCmd{} err = json.Unmarshal(msg.Message, &tagCmd) if err != nil { fmt.Printf("parse exit status failed: %v\n", err) return } fmt.Printf("client get exit status: tag %v\n", tagCmd) context.Lock() if tty, ok := context.ttyList[tagCmd.Tag]; ok { code = uint8(tty.ExitCode) delete(context.ttyList, tagCmd.Tag) } context.Unlock() m := &hypervisor.DecodedMessage{ Code: RUNV_EXITSTATUS, Message: []byte{code}, } data := hypervisor.NewVmMessage(m) conn.Write(data) /* Get exit code of Container, it's time to let container go */ if tagCmd.Container != "" { cleanupVSocket(context, tagCmd.Root, tagCmd.Container) } } case RUNV_WINSIZE: { var winSize ttyWinSize json.Unmarshal(msg.Message, &winSize) //fmt.Printf("client exec winsize request %v\n", winSize) context.vm.Tty(winSize.Tag, winSize.Height, winSize.Width) } case RUNV_KILLCONTAINER: { killCmd := &killContainerCmd{} err = json.Unmarshal(msg.Message, killCmd) if err != nil { fmt.Printf("parse runv kill container command failed: %v\n", err) return } context.vm.KillContainer(info.Id, killCmd.Signal) } default: fmt.Printf("unknown cient request\n") } }
func startVContainer(context *nsContext, root, container string) { stateDir := filepath.Join(root, container) err := createVSocket(context, root, container) if err != nil { fmt.Printf("create runv Socket err: %v\n", err) return } sock, ok := context.sockets[container] if !ok { fmt.Printf("can not find runv Socket, container %v\n", container) return } conn, err := sock.Accept() if err != nil { fmt.Printf("accept on runv Socket err: %v\n", err) return } // get config from sock msg, err := hypervisor.ReadVmMessage(conn.(*net.UnixConn)) if err != nil || msg.Code != RUNV_STARTCONTAINER { fmt.Printf("read runv client data failed: %v\n", err) return } config := &startConfig{} err = json.Unmarshal(msg.Message, config) if err != nil || config.Root != root || config.Name != container { fmt.Printf("parse runv start config failed: %v\n", err) return } // start pure pod err = startRunvPod(context, config) if err != nil { fmt.Printf("Start Pod failed: %s\n", err.Error()) return } defer cleanupRunvPod(context, container) // save the state state := &specs.State{ Version: config.LinuxSpec.Spec.Version, ID: container, Pid: -1, BundlePath: config.BundlePath, } stateData, err := json.MarshalIndent(state, "", "\t") if err != nil { fmt.Printf("%s\n", err.Error()) return } stateFile := filepath.Join(stateDir, "state.json") err = ioutil.WriteFile(stateFile, stateData, 0644) if err != nil { fmt.Printf("%s\n", err.Error()) return } userContainer := pod.ConvertOCF2UserContainer(&config.LinuxSpec, &config.LinuxRuntimeSpec) info, err := prepareInfo(config, userContainer, context.vmId) if err != nil { fmt.Printf("%s\n", err.Error()) return } defer func() { rootDir := filepath.Join(hypervisor.BaseDir, context.vmId, hypervisor.ShareDirTag, info.Id, "rootfs") utils.Umount(rootDir) os.RemoveAll(filepath.Join(hypervisor.BaseDir, context.vmId, hypervisor.ShareDirTag, info.Id)) }() tag, _ := runvAllocAndRespondTag(conn) tty := &hypervisor.TtyIO{ ClientTag: tag, Stdin: conn, Stdout: conn, Callback: make(chan *types.VmResponse, 1), } context.Lock() context.ttyList[tag] = tty context.Unlock() err = context.vm.Attach(tty, info.Id, nil) if err != nil { fmt.Printf("StartPod fail: fail to set up tty connection.\n") return } err = execPrestartHooks(&config.LinuxRuntimeSpec.RuntimeSpec, state) if err != nil { fmt.Printf("execute Prestart hooks failed, %s\n", err.Error()) return } context.podStatus.AddContainer(info.Id, context.podId, "", []string{}, types.S_POD_CREATED) context.vm.NewContainer(userContainer, info) ListenAndHandleRunvRequests(context, info, sock) err = execPoststartHooks(&config.LinuxRuntimeSpec.RuntimeSpec, state) if err != nil { fmt.Printf("execute Poststart hooks failed %s\n", err.Error()) } err = tty.WaitForFinish() if err != nil { fmt.Printf("get exit code failed %s\n", err.Error()) } err = execPoststopHooks(&config.LinuxRuntimeSpec.RuntimeSpec, state) if err != nil { fmt.Printf("execute Poststop hooks failed %s\n", err.Error()) return } }