/* 周期性的检查到MongoDB的连接 如果检查失败,则尝试重新连接 */ func TouchMongoDB(show_check_info bool) { c := time.Tick(10 * time.Second) for _ = range c { if MgoSession != nil && MgoDatabase != nil { err := MgoSession.Ping() if err != nil { // 当MongoDB无法连接时,关闭Session if MgoSession != nil && MgoDatabase == nil { utils.Println("MongoDB connection lost, clear resources and close session.") MgoDatabase.Logout() MgoSession.LogoutAll() MgoSession.Close() MgoDatabase = nil MgoSession = nil } SetMgoFailed() utils.Println("Check connection: MongoDB has gone, try to reconnect.") InitMongoDB(MgoURL, MgoTimeout) } else { SetMgoOK() if show_check_info == true { utils.Println("Check MongoDB connection... OK") } } } else { SetMgoFailed() utils.Println("Check connection: MongoDB has gone, try to reconnect.") InitMongoDB(MgoURL, MgoTimeout) } } }
func GetConn(host, port string) (*libvirt.VirConnection, error) { var conn *libvirt.VirConnection var err error var ok bool global_conn.lock.RLock() if conn, ok = global_conn.conn_map[host]; ok { if ok, err = conn.IsAlive(); ok { global_conn.lock.RUnlock() return conn, nil } } global_conn.lock.RUnlock() address := host + ":" + port new_conn, err := libvirt.NewVirConnection("qemu+tcp://" + address + "/system") if err != nil { return &new_conn, err } if v, ok := event_map[address]; !ok { if v == false { utils.Println("register event...") var Callback libvirt.DomainEventCallback Callback = EventCallback test := func() {} //dom := libvirt.VirDomain{} dom, _ := new_conn.LookupDomainByName("i-2-161-VM") ret := new_conn.DomainEventRegister(dom, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, &Callback, test) utils.Println("LIFECYCLE ret:", ret) //ret = new_conn.DomainEventRegister(dom, libvirt.VIR_DOMAIN_EVENT_ID_REBOOT, &Callback, test) //utils.Println("ret:", ret) //ret = new_conn.DomainEventRegister(dom, libvirt.VIR_DOMAIN_EVENT_ID_BLOCK_JOB, &Callback, test) //utils.Println("ret:", ret) go func() { for { ret := libvirt.EventRunDefaultImpl() utils.Println("EventRunDefaultImpl ret:", ret) } }() event_map[address] = true } } global_conn.lock.Lock() global_conn.conn_map[host] = &new_conn global_conn.lock.Unlock() return &new_conn, nil }
func (this *Client) Close() { err := this.GetClient().Close() if err != nil { utils.Println(err) } this.InternalClient = nil this.Connected = false if this.Debug { utils.Println("Connection closed.") } }
// POSIX信号发生时的回调 func SignalCallback() { for s := range SignalChan { sig := s.String() utils.Println("Got Signal: ", sig) if s == syscall.SIGINT { utils.Println("RConsole server exit...") os.Exit(0) } } }
func (this *Client) ReadInstruction() *inst.Instruction { if this.Debug { utils.Println("Read instruction") } instruction, err := inst.LoadInstruction(this.BufReceive()) if this.Debug { utils.Println(instruction.String()) } if err != nil { utils.Println("Read instruction failed:", err) } else { return instruction } return nil }
func (this *Client) Send(data []byte) error { if this.Debug { utils.Printf("Sending data: %s\n", string(data)) } client := this.GetClient() if client == nil { return fmt.Errorf("maybe not connected\n") } n, err := client.Write(data) if err != nil { utils.Println("Send data failed:", err) this.Close() return err } if n != len(data) { utils.Println("Write() has blocked, send: %d, all: %d", n, len(data)) this.Close() return fmt.Errorf("Write() has blocked, send: %d, all: %d", n, len(data)) } return nil }
func (this *HostController) Post() { var resp_message ResponseMessage var libvirt_host LibvirtHost var insert_id string err := this.ParseForm(&libvirt_host) if err != nil { err_msg := fmt.Sprintf("parseform failed: %s", err) utils.Println(err_msg) resp_message.Code = 1 resp_message.Message = err_msg this.Ctx.Output.Status = 500 goto end } err = this.Valid(libvirt_host) if err != nil { err_msg := fmt.Sprintf("validation failed: %s", err) utils.Println(err_msg) resp_message.Code = 2 resp_message.Message = err_msg this.Ctx.Output.Status = 500 goto end } libvirt_host.UUID = utils.MakeRandomID() insert_id = libvirt_host.UUID err = mongo.InsertOne("libvirt_host", libvirt_host) if resp_message.Code == 0 { resp_message.Code = 0 resp_message.Message = insert_id } end: this.Data["json"] = resp_message this.ServeJson() }
func (this *Client) GetClient() net.Conn { if this.InternalClient == nil { address := net.JoinHostPort(this.Host, this.Port) conn, err := net.DialTimeout("tcp", address, this.Timeout) if err != nil { utils.Println(err) return nil } this.InternalClient = conn this.BufReader = bufio.NewReader(conn) this.BufWriter = bufio.NewWriter(conn) if this.Debug { utils.Printf("Client connected with gucad server (%s %s %s)\n", this.Host, this.Port, this.Timeout) } return this.InternalClient } return this.InternalClient }
func (this *ConnectionManagerController) CreateConnection() { var resp_message ResponseMessage var found_protocol bool var decode_failed bool var decode_failed_reason string var insert_failed bool var insert_failed_reason string var insert_id string var valid_failed bool var valid_failed_reason string conn_type := this.Ctx.Input.Param(":conn_type") found_protocol = client.ValidProtocol(conn_type) if found_protocol { if conn_type == "vnc" { args, err := this.DecodeVNCArgs() if err != nil { decode_failed = true decode_failed_reason = fmt.Sprintf("decode vnc args failed: %s", err) } else { err = this.Valid(args) if err != nil { valid_failed = true valid_failed_reason = fmt.Sprintf("valid error: %s", err) } else { args.UUID = utils.MakeRandomID() insert_id = args.UUID err = mongo.InsertOne("connection", *args) if err != nil { insert_failed = true insert_failed_reason = fmt.Sprintf("save vnc args failed: %s, args: %s", err, *args) } } } } if conn_type == "rdp" { args, err := this.DecodeRDPArgs() if err != nil { decode_failed = true decode_failed_reason = fmt.Sprintf("decode rdp args failed: %s", err) } else { err = this.Valid(args) if err != nil { valid_failed = true valid_failed_reason = fmt.Sprintf("valid error: %s", err) } else { args.UUID = utils.MakeRandomID() insert_id = args.UUID err = mongo.InsertOne("connection", *args) if err != nil { insert_failed = true insert_failed_reason = fmt.Sprintf("save rdp args failed: %s, args: %s", err, *args) } } } } if conn_type == "ssh" { args, err := this.DecodeSSHArgs() if err != nil { decode_failed = true decode_failed_reason = fmt.Sprintf("decode ssh args failed: %s", err) } else { err = this.Valid(args) if err != nil { valid_failed = true valid_failed_reason = fmt.Sprintf("valid error: %s", err) } else { args.UUID = utils.MakeRandomID() insert_id = args.UUID err = mongo.InsertOne("connection", *args) if err != nil { insert_failed = true insert_failed_reason = fmt.Sprintf("save ssh args failed: %s, args: %s", err, *args) } } } } if conn_type == "telnet" { args, err := this.DecodeTELNETArgs() if err != nil { decode_failed = true decode_failed_reason = fmt.Sprintf("decode telnet args failed: %s", err) } else { err = this.Valid(args) if err != nil { valid_failed = true valid_failed_reason = fmt.Sprintf("valid error: %s", err) } else { args.UUID = utils.MakeRandomID() insert_id = args.UUID err = mongo.InsertOne("connection", *args) if err != nil { insert_failed = true insert_failed_reason = fmt.Sprintf("save telnet args failed: %s, args: %s", err, *args) } } } } if conn_type == "spice" { args, err := this.DecodeSPICEArgs() if err != nil { decode_failed = true decode_failed_reason = fmt.Sprintf("decode spice args failed: %s", err) } else { err = this.Valid(args) if err != nil { valid_failed = true valid_failed_reason = fmt.Sprintf("valid error: %s", err) } else { args.UUID = utils.MakeRandomID() insert_id = args.UUID err = mongo.InsertOne("connection", *args) if err != nil { insert_failed = true insert_failed_reason = fmt.Sprintf("save spice args failed: %s, args: %s", err, *args) } } } } if conn_type == "libvirt" { args, err := this.DecodeLIBVIRTArgs() if err != nil { decode_failed = true decode_failed_reason = fmt.Sprintf("decode libvirt args failed: %s", err) } else { err = this.Valid(args) if err != nil { valid_failed = true valid_failed_reason = fmt.Sprintf("valid error: %s", err) } else { args.UUID = utils.MakeRandomID() insert_id = args.UUID err = mongo.InsertOne("connection", *args) if err != nil { insert_failed = true insert_failed_reason = fmt.Sprintf("save libvirt args failed: %s, args: %s", err, *args) } } } } if decode_failed { utils.Println(decode_failed_reason) resp_message.Code = 1 resp_message.Message = decode_failed_reason this.Ctx.Output.Status = 500 } if insert_failed { utils.Println(insert_failed_reason) resp_message.Code = 2 resp_message.Message = insert_failed_reason this.Ctx.Output.Status = 500 } if valid_failed { utils.Println(valid_failed_reason) resp_message.Code = 3 resp_message.Message = valid_failed_reason this.Ctx.Output.Status = 500 } } else { resp_message.Code = 4 resp_message.Message = "wrong protocol type" this.Ctx.Output.Status = 400 } if resp_message.Code == 0 { resp_message.Code = 0 resp_message.Message = insert_id } this.Data["json"] = resp_message this.ServeJson() }
func EventCallback(c *libvirt.VirConnection, d *libvirt.VirDomain, event interface{}, f func()) int { utils.Println("got event:", c, d, event, f) return 0 }
func (this *Client) HandShake(protocol, width, height, dpi string, audio []string, video []string, KWArgs map[string]string) bool { var found_protocol bool for index := range PROTOCOLS { if protocol == PROTOCOLS[index] { found_protocol = true break } } if !found_protocol { utils.Printf("Invalid protocol: %s\n", protocol) return false } // 1. Send "select" instruction utils.Println("Send 'select' instruction") err := this.SendInstruction(inst.NewInstruction("select", protocol)) if err != nil { utils.Println("Send 'select' failed:", err) return false } // 2. Receive "args" instruction instruction := this.ReadInstruction() utils.Printf("Expecting 'args' instruction, received: %s\n", instruction.String()) if instruction == nil { utils.Println("Cannot establish Handshake. Connection Lost!") return false } if instruction.OpCode != "args" { utils.Printf("Cannot establish Handshake. Expected opcode 'args', received '%s' instead.\n", instruction.OpCode) return false } // 3. Respond with size, audio & video support utils.Printf("Send 'size' instruction (%s %s %s)\n", width, height, dpi) size_instruction := inst.NewInstruction("size", width, height, dpi) err = this.SendInstruction(size_instruction) if err != nil { utils.Println("Send 'size' failed:", err) return false } utils.Printf("Send 'audio' instruction (%s)\n", audio) err = this.SendInstruction(inst.NewInstruction("audio", audio...)) if err != nil { utils.Println("Send 'audio' failed:", err) return false } utils.Printf("Send 'video' instruction (%s)\n", video) err = this.SendInstruction(inst.NewInstruction("video", video...)) if err != nil { utils.Println("Send 'video' failed:", err) return false } var connect_args []string for idx := range instruction.Args { arg := strings.Replace(instruction.Args[idx], "-", "_", -1) if v, ok := KWArgs[arg]; ok { connect_args = append(connect_args, v) } else { connect_args = append(connect_args, "") } } // 4. Send connect arguments utils.Printf("Send 'connect' instruction (%s)\n", connect_args) err = this.SendInstruction(inst.NewInstruction("connect", connect_args...)) if err != nil { utils.Println("Send 'connect' failed:", err) return false } return true }
func (this *Client) SendInstruction(instruction *inst.Instruction) error { if this.Debug { utils.Println("Sending instruction:", instruction.String()) } return this.Send([]byte(instruction.Encode())) }
/* 判断命令行参数和配置文件 如果配置文件不存在,则会使用命令行的参数 否则直接使用配置文件中的参数 */ func Init() { if *ServerProfile == true { Config.ServerProfile = true } if !Exist(*ConfigFile) { if *LogFile == "" { *LogFile = "/var/log/rconsole.log" } Config.LogFile = *LogFile if *ProfileAddress == "" { *ProfileAddress = "0.0.0.0:9998" } Config.ProfileAddress = *ProfileAddress if *ListenAddress == "" { *ListenAddress = "0.0.0.0:9999" } Config.ListenAddress = *ListenAddress if *MongoURL == "" { *MongoURL = "mongo://127.0.0.1/rconsole" } Config.MongoURL = *MongoURL if *MongoTimeout == 0 { *MongoTimeout = 1 } Config.MongoTimeout = *MongoTimeout if *ShowCheckConn == true { *ShowCheckConn = true } Config.ShowCheckConn = *ShowCheckConn if *ServerDebug == true { *ServerDebug = true } Config.ServerDebug = *ServerDebug } else { data, err := ioutil.ReadFile(*ConfigFile) if err != nil { utils.Println(err) return } err = json.Unmarshal(data, &Config) if err != nil { utils.Println(err) } if *LogFile != "" { Config.LogFile = *LogFile } if *ProfileAddress != "" { Config.ProfileAddress = *ProfileAddress } if *ListenAddress != "" { Config.ListenAddress = *ListenAddress } if *MongoURL != "" { Config.MongoURL = *MongoURL } if *MongoTimeout != 0 { Config.MongoTimeout = *MongoTimeout } if *ShowCheckConn != false { Config.ShowCheckConn = *ShowCheckConn } if *ServerDebug != false { Config.ServerDebug = *ServerDebug } } }
func main() { ret := libvirt.EventRegisterDefaultImpl() utils.Println("EventRegisterDefaultImpl ret:", ret) runtime.GOMAXPROCS(runtime.NumCPU()) defer func() { if err := recover(); err != nil { utils.Println("Server Error: ", err.(string)) } }() // 解析命令行参数 flag.Parse() // 自定义初始化 Init() // 设置guacd客户端连接时的调试信息 client.ClientDebug = Config.ServerDebug // 初始化guacd服务连接池 client.Pool.Init(Config.GuacdServer) utils.Println("Try connect to:", Config.MongoURL) // 初始化MongoDB的连接 timeout := time.Duration(Config.MongoTimeout) * time.Second err := mongo.InitMongoDB(Config.MongoURL, timeout) if err != nil { utils.Println(err) os.Exit(1) } // 启动独立的线程测试MongoDB连接 go mongo.TouchMongoDB(Config.ShowCheckConn) utils.Println("Connect to MongoDB OK") // 捕捉信号并设置回调函数 SignalChan = make(chan os.Signal, 1) signal.Notify(SignalChan, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGPIPE, syscall.SIGALRM, syscall.SIGPIPE) go SignalCallback() // 启动性能调试接口 if Config.ServerProfile == true { go func() { http.ListenAndServe(Config.ProfileAddress, nil) }() } utils.Printf("http profile server Running on %s\n", Config.ProfileAddress) addr_splited := strings.Split(Config.ListenAddress, ":") if len(addr_splited) < 2 { utils.Println("the format of listen address is invalid!") os.Exit(1) } beego.HttpAddr = addr_splited[0] beego.HttpPort, err = strconv.Atoi(addr_splited[1]) beego.SetStaticPath("/static", "./static") beego.Router("/connect", &controllers.MainController{}) beego.Router("/ws", &wscontrollers.WebSocketController{}) beego.Router("/ws/spice", &spicecontrollers.SpiceController{}) beego.Router("/ws/libvirt", &libvirtcontrollers.LibvirtController{}) beego.Router("/api/conn/list", &managercontrollers.ConnectionManagerController{}, "get:ListConnection") beego.Router("/api/conn/create/:conn_type([a-z]+)", &managercontrollers.ConnectionManagerController{}, "post:CreateConnection") beego.Router("/api/conn/update/:conn_type([a-z]+)", &managercontrollers.ConnectionManagerController{}, "put:UpdateConnection") beego.Router("/api/conn/delete", &managercontrollers.ConnectionManagerController{}, "delete:DeleteConnection") beego.Router("/api/libvirt/host", &libvirtcontrollers.HostController{}) beego.Run() }
func (this *SpiceController) Get() { ws, err := upgrader.Upgrade(this.Ctx.ResponseWriter, this.Ctx.Request, nil) if err != nil { utils.Println("websocket upgrade failed:", err) return } defer func() { utils.Println("websocket client disconnected:", ws.RemoteAddr()) ws.Close() }() Type := this.GetString("type") if Type != "spice" { utils.Printf("invalid protocol: %s\n", Type) return } spice_args, err := GetSPICEArgs(this.Ctx) if err != nil { utils.Println("get args for SPICE failed:", err) return } if spice_args == nil { utils.Println("empty args for SPICE") return } hostname := spice_args["hostname"] port := spice_args["port"] spice_conn, err := net.DialTimeout("tcp", hostname+":"+port, 3*time.Second) if err != nil { utils.Println("Can not connect to spice server:", err) return } writer_buf := make([]byte, 4096) go func() { for { n, err := spice_conn.Read(writer_buf) if err != nil { utils.Println("Error read from spice server:", err) return } err = ws.WriteMessage(websocket.BinaryMessage, writer_buf[:n]) if err != nil { utils.Println("websocket write failed:", err) return } } }() // TODO: use ws.NextReader to reuse memory allocation for { _, data, err := ws.ReadMessage() if err != nil { utils.Println("websocket readmessage failed:", err) return } spice_conn.Write(data) } }
func (this *LibvirtController) Get() { var console_host string var console_port string ws, err := upgrader.Upgrade(this.Ctx.ResponseWriter, this.Ctx.Request, nil) if err != nil { utils.Println("websocket upgrade failed:", err) return } defer func() { utils.Println("websocket client disconnected:", ws.RemoteAddr()) ws.Close() }() libvirt_args, err := GetLIBVIRTArgs(this.Ctx) if err != nil { utils.Println(err) return } if libvirt_args == nil { utils.Println("empty args for LIBVIRT") return } libvirt_host := libvirt_args["hostname"] libvirt_port := libvirt_args["port"] vm_name := libvirt_args["vm"] graphics, err := libvirt.GetDomainGraphics(libvirt_host, libvirt_port, vm_name) if err != nil { utils.Println(err) return } if graphics.Listen.Address == "0.0.0.0" { console_host = libvirt_host } else { console_host = graphics.Listen.Address } console_port = graphics.Port console_conn, err := net.DialTimeout("tcp", console_host+":"+console_port, 3*time.Second) if err != nil { utils.Println("Can not connect to console host:", err) return } writer_buf := make([]byte, 4096) go func() { for { n, err := console_conn.Read(writer_buf) if err != nil { utils.Println("Error read from console host:", err) return } err = ws.WriteMessage(websocket.BinaryMessage, writer_buf[:n]) if err != nil { utils.Println("websocket write failed:", err) return } } }() // TODO: use ws.NextReader to reuse memory allocation for { _, data, err := ws.ReadMessage() if err != nil { utils.Println("websocket readmessage failed:", err) return } console_conn.Write(data) } }