通过websocket 实现与容器的交互

来源:互联网 发布:平板电脑网络转换器 编辑:程序博客网 时间:2024/06/07 08:45
<!doctype html><html>  <head>    <title>WEB 控制台</title>    <style>body, #terminal {position: absolute; height: 100%; width: 100%; margin: 0px;}</style>  </head>  <input type="hidden" name="t_id" id="t_id" value="<?=$ns?>" />  <input type="hidden" name="s_id" id="s_id" value="<?=$pn?>" />  <input type="hidden" name="c_id" id="c_id" value="<?=$di?>" />  <input type="hidden" name="md5" id="md5" value="<?=$cs?>" />  <input type="hidden" name="wss" id="wss" value="ws://dockerconsole.intra.ffan.com/ws?nodename=<?=$ip?>" />  <body>    <div id="terminal"></div>    <script src="/dist/js/gotty/hterm.js"></script>    <script src="/dist/js/gotty/gotty.js"></script>  </body></html>
upstream 10209202202 {    server 10.209.202.202:10001;}upstream 1020920237 {    server 10.209.202.37:10001;}upstream 10209204167 {    server 10.209.204.167:10001;}upstream 10209204199 {    server 10.209.204.199:10001;}

# For more information on configuration, see:#   * Official English Documentation: http://nginx.org/en/docs/#   * Official Russian Documentation: http://nginx.org/ru/docs/user nginx;worker_processes auto;error_log /var/log/nginx/error.log;# pid /run/nginx.pid;events {    worker_connections 1024;}http {    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '                      '$status $body_bytes_sent "$http_referer" '                      '"$http_user_agent" "$http_x_forwarded_for"';    access_log  /var/log/nginx/access.log  main;    sendfile            on;    tcp_nopush          on;    tcp_nodelay         on;    keepalive_timeout   65;    types_hash_max_size 2048;    include             /etc/nginx/mime.types;    default_type        application/octet-stream;    # Load modular configuration files from the /etc/nginx/conf.d directory.    # See http://nginx.org/en/docs/ngx_core_module.html#include    # for more information.    include /etc/nginx/conf.d/*.conf;    map $http_upgrade $connection_upgrade {        default upgrade;        ''      close;    }        server {        listen       11000;        root         /usr/share/nginx/html;        # Load configuration files for the default server block.        include /etc/nginx/default.d/*.conf;        location / {           proxy_http_version 1.1;           proxy_set_header Upgrade $http_upgrade;           proxy_set_header Connection $connection_upgrade;           set $dynamic $arg_nodename;           set $args '';           proxy_pass http://$dynamic;        }        error_page 404 /404.html;            location = /40x.html {        }        error_page 500 502 503 504 /50x.html;            location = /50x.html {        }    }}

package mainimport ("flag""fmt""os""os/signal""syscall"app "./console")func main() {var address *string = flag.String("Address", "", "server listen address")var port *string = flag.String("Port", "10001", "server listen port")var sessionKey *string = flag.String("SessionKey", "_auth_user_id", "user serssion key")flag.Parse()options := app.DefaultOptionsoptions.Address = *addressoptions.Port = *portoptions.SessionKey = *sessionKeyapp, err := app.New(nil, &options)registerSignals(app)err = app.Run()if err != nil {exit(err, 4)}}func exit(err error, code int) {if err != nil {fmt.Println(err)}os.Exit(code)}func registerSignals(app *app.App) {sigChan := make(chan os.Signal, 1)signal.Notify(sigChan,syscall.SIGINT,syscall.SIGTERM,)go func() {for {s := <-sigChanswitch s {case syscall.SIGINT, syscall.SIGTERM:if app.Exit() {fmt.Println("Send ^C to force exit.")} else {os.Exit(5)}}}}()}

package appimport ("crypto/md5""encoding/hex""encoding/json""log""net/http""os/exec""sync""text/template""github.com/braintree/manners""github.com/gorilla/websocket""github.com/kr/pty""github.com/yudai/umutex")type App struct {command []stringoptions *Optionsupgrader *websocket.UpgradertitleTemplate *template.TemplateonceMutex *umutex.UnblockingMutex}type Options struct {Address         string                 `hcl:"address"`Port            string                 `hcl:"port"`PermitWrite     bool                   `hcl:"permit_write"`IndexFile       string                 `hcl:"index_file"`TitleFormat     string                 `hcl:"title_format"`EnableReconnect bool                   `hcl:"enable_reconnect"`ReconnectTime   int                    `hcl:"reconnect_time"`PermitArguments bool                   `hcl:"permit_arguments"`CloseSignal     int                    `hcl:"close_signal"`Preferences     HtermPrefernces        `hcl:"preferences"`RawPreferences  map[string]interface{} `hcl:"preferences"`SessionKey      string                 `hcl:"session_key"`}var Version = "0.0.1"var DefaultOptions = Options{Address:         "",Port:            "10001",PermitWrite:     true,IndexFile:       "",TitleFormat:     "DTTY Command",EnableReconnect: true,ReconnectTime:   10,CloseSignal:     1, // syscall.SIGHUPPreferences:     HtermPrefernces{},SessionKey:      "_auth_user_id",}type InitMessage struct {T_id string `json:t_id`S_id string `json:s_id`C_id string `json:c_id`Md5  string `json:md5`}func checkSameOrigin(r *http.Request) bool {return true}func New(command []string, options *Options) (*App, error) {titleTemplate, _ := template.New("title").Parse(options.TitleFormat)return &App{command: command,options: options,upgrader: &websocket.Upgrader{ReadBufferSize:  1024,WriteBufferSize: 1024,CheckOrigin:     checkSameOrigin,},titleTemplate: titleTemplate,onceMutex:     umutex.New(),}, nil}func (app *App) Run() error {wsHandler := http.HandlerFunc(app.handleWS)siteHandler := wrapHeaders(http.Handler(http.NewServeMux()))wsMux := http.NewServeMux()wsMux.Handle("/", siteHandler)wsMux.Handle("/ws", wsHandler)siteHandler = (http.Handler(wsMux))siteHandler = wrapLogger(siteHandler)s := manners.NewWithServer(&http.Server{Addr:    app.options.Address + ":" + app.options.Port,Handler: siteHandler,})log.Printf("Start server on port " + app.options.Port)log.Fatal(s.ListenAndServe())log.Printf("Exiting...")return nil}func (app *App) handleWS(w http.ResponseWriter, r *http.Request) {log.Printf("New client connected: %s", r.RemoteAddr)if r.Method != "GET" {http.Error(w, "Method not allowed", 405)return}conn, err := app.upgrader.Upgrade(w, r, nil)if err != nil {log.Print("Failed to upgrade connection: " + err.Error())return}//defer conn.Close()_, stream, err := conn.ReadMessage()if err != nil {log.Print("Failed to authenticate websocket connection " + err.Error())conn.Close()return}message := string(stream)log.Print("message=", message)var init InitMessageerr = json.Unmarshal(stream, &init)//todo authif init.C_id == "" {log.Print("Parameter is error:" + init.C_id)conn.WriteMessage(websocket.TextMessage, []byte("Parameter is error !"))conn.Close()return}key := init.T_id + "_" + init.S_id + "_" + init.C_id + "_yunpingtai"md5 := md5Func(key)log.Print(key + ":" + md5)if md5 != init.Md5 {log.Print("Auth is not allowed !")conn.WriteMessage(websocket.TextMessage, []byte("Auth is not allowed!"))conn.Close()return}cmd := exec.Command("docker", "exec", "-ti", init.C_id, "/bin/bash")ptyIo, err := pty.Start(cmd)if err != nil {log.Print("Failed to execute command")return}log.Printf("Command is running for client %s with PID %d ", r.RemoteAddr, cmd.Process.Pid)context := &clientContext{app:        app,request:    r,connection: conn,command:    cmd,pty:        ptyIo,writeMutex: &sync.Mutex{},}context.goHandleClient()}func (app *App) Exit() (firstCall bool) {manners.Close()return true}func wrapLogger(handler http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {rw := &responseWrapper{w, 200}handler.ServeHTTP(rw, r)log.Printf("%s %d %s %s", r.RemoteAddr, rw.status, r.Method, r.URL.Path)})}func wrapHeaders(handler http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {w.Header().Set("Server", "GoTTY/"+Version)handler.ServeHTTP(w, r)})}func md5Func(str string) string {h := md5.New()h.Write([]byte(str))cipherStr := h.Sum(nil)return hex.EncodeToString(cipherStr)}


原创粉丝点击