diff --git a/model/gateway/instance.go b/model/gateway/instance.go index 8bbc91a2..f8b6aba5 100644 --- a/model/gateway/instance.go +++ b/model/gateway/instance.go @@ -16,11 +16,13 @@ type Instance struct { Name string `json:"name,omitempty" elastic_mapping:"name:{type:keyword,fields:{text: {type: text}}}"` Endpoint string `json:"endpoint,omitempty" elastic_mapping:"endpoint: { type: keyword }"` Version map[string]interface{} `json:"version,omitempty" elastic_mapping:"version: { type: object }"` - BasicAuth struct { - Username string `json:"username,omitempty" config:"username" elastic_mapping:"username:{type:keyword}"` - Password string `json:"password,omitempty" config:"password" elastic_mapping:"password:{type:keyword}"` - } `config:"basic_auth" json:"basic_auth,omitempty" elastic_mapping:"basic_auth:{type:object}"` + BasicAuth BasicAuth `config:"basic_auth" json:"basic_auth,omitempty" elastic_mapping:"basic_auth:{type:object}"` Owner string `json:"owner,omitempty" config:"owner" elastic_mapping:"owner:{type:keyword}"` Tags [] string `json:"tags,omitempty"` Description string `json:"description,omitempty" config:"description" elastic_mapping:"description:{type:keyword}"` } + +type BasicAuth struct { + Username string `json:"username,omitempty" config:"username" elastic_mapping:"username:{type:keyword}"` + Password string `json:"password,omitempty" config:"password" elastic_mapping:"password:{type:keyword}"` +} \ No newline at end of file diff --git a/plugin/api/gateway/api.go b/plugin/api/gateway/api.go index 7f7aa716..7624624b 100644 --- a/plugin/api/gateway/api.go +++ b/plugin/api/gateway/api.go @@ -21,4 +21,6 @@ func init() { api.HandleAPIMethod(api.DELETE, "/gateway/instance/:instance_id", gateway.deleteInstance) api.HandleAPIMethod(api.GET, "/gateway/instance/_search", gateway.searchInstance) api.HandleAPIMethod(api.POST, "/gateway/instance/status", gateway.getInstanceStatus) + + api.HandleAPIMethod(api.POST, "/gateway/instance/:instance_id/_proxy", gateway.proxy) } diff --git a/plugin/api/gateway/helper.go b/plugin/api/gateway/helper.go index e345364e..cf0ee734 100644 --- a/plugin/api/gateway/helper.go +++ b/plugin/api/gateway/helper.go @@ -4,6 +4,16 @@ package gateway +import ( + "bytes" + "crypto/tls" + "github.com/segmentio/encoding/json" + "infini.sh/console/model/gateway" + "infini.sh/framework/lib/fasthttp" + "io" + "time" +) + //import ( // "fmt" // "infini.sh/console/model/gateway" @@ -88,3 +98,65 @@ package gateway // return resultMap //} +type ProxyRequest struct { + Endpoint string + Path string + Method string + BasicAuth gateway.BasicAuth + Body interface{} +} + +type ProxyResponse struct { + Body []byte + StatusCode int +} + +func doGatewayRequest(req *ProxyRequest) (*ProxyResponse, error){ + var ( + freq = fasthttp.AcquireRequest() + fres = fasthttp.AcquireResponse() + ) + defer func() { + fasthttp.ReleaseRequest(freq) + fasthttp.ReleaseResponse(fres) + }() + freq.SetRequestURI(req.Endpoint+ req.Path) + freq.Header.SetMethod(req.Method) + if req.BasicAuth.Username != ""{ + freq.SetBasicAuth(req.BasicAuth.Username, req.BasicAuth.Password) + } + if req.Body != nil { + switch req.Body.(type) { + case []byte: + freq.SetBody(req.Body.([]byte)) + case string: + freq.SetBody([]byte(req.Body.(string))) + case io.Reader: + freq.SetBodyStream(req.Body.(io.Reader), -1) + default: + rw := &bytes.Buffer{} + enc := json.NewEncoder(rw) + err := enc.Encode(req.Body) + if err != nil { + return nil, err + } + freq.SetBody(rw.Bytes()) + } + } + + client := &fasthttp.Client{ + MaxConnsPerHost: 1000, + TLSConfig: &tls.Config{InsecureSkipVerify: true}, + ReadTimeout: time.Second * 5, + } + err := client.Do(freq, fres) + if err != nil { + return nil, err + } + + return &ProxyResponse{ + Body: fres.Body(), + StatusCode: fres.StatusCode(), + }, nil + +} diff --git a/plugin/api/gateway/instance.go b/plugin/api/gateway/instance.go index a479c34d..71611f3f 100644 --- a/plugin/api/gateway/instance.go +++ b/plugin/api/gateway/instance.go @@ -5,7 +5,6 @@ package gateway import ( - "crypto/tls" "fmt" log "github.com/cihub/seelog" "github.com/segmentio/encoding/json" @@ -13,11 +12,9 @@ import ( httprouter "infini.sh/framework/core/api/router" "infini.sh/framework/core/orm" "infini.sh/framework/core/util" - "infini.sh/framework/lib/fasthttp" "net/http" "strconv" "strings" - "time" ) func (h *GatewayAPI) createInstance(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { @@ -217,7 +214,10 @@ func (h *GatewayAPI) getInstanceStatus(w http.ResponseWriter, req *http.Request, password = "" } gid, _ := instance.GetValue("id") - connRes, err := h.doConnect(endpoint.(string), username.(string), password.(string)) + connRes, err := h.doConnect(endpoint.(string), gateway.BasicAuth{ + Username: username.(string), + Password: password.(string), + }) if err != nil { log.Error(err) } @@ -225,6 +225,43 @@ func (h *GatewayAPI) getInstanceStatus(w http.ResponseWriter, req *http.Request, } h.WriteJSON(w, result, http.StatusOK) } +func (h *GatewayAPI) proxy(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { + var ( + method = h.Get(req, "method", "GET") + path = h.Get(req, "path", "") + ) + instanceID := ps.MustGetParameter("instance_id") + + obj := gateway.Instance{} + obj.ID = instanceID + + exists, err := orm.Get(&obj) + if err != nil { + h.WriteError(w, err.Error(), http.StatusInternalServerError) + log.Error(err) + return + } + if !exists { + h.WriteJSON(w, util.MapStr{ + "error": "gateway instance not found", + }, http.StatusNotFound) + return + } + res, err := doGatewayRequest(&ProxyRequest{ + Method: method, + Endpoint: obj.Endpoint, + Path: path, + Body: req.Body, + BasicAuth: obj.BasicAuth, + }) + if err != nil { + h.WriteError(w, err.Error(), http.StatusInternalServerError) + log.Error(err) + return + } + h.WriteHeader(w, res.StatusCode) + h.Write(w, res.Body) +} type GatewayConnectResponse struct { ID string `json:"id"` @@ -238,32 +275,17 @@ type GatewayConnectResponse struct { } `json:"version"` } -func (h *GatewayAPI) doConnect(endpoint, username, password string) (*GatewayConnectResponse, error) { - var ( - freq = fasthttp.AcquireRequest() - fres = fasthttp.AcquireResponse() - ) - defer func() { - fasthttp.ReleaseRequest(freq) - fasthttp.ReleaseResponse(fres) - }() - - freq.SetRequestURI(fmt.Sprintf("%s/_framework/api/_info", endpoint)) - freq.Header.SetMethod("GET") - if username != ""{ - freq.SetBasicAuth(username, password) - } - - client := &fasthttp.Client{ - MaxConnsPerHost: 1000, - TLSConfig: &tls.Config{InsecureSkipVerify: true}, - ReadTimeout: time.Second * 5, - } - err := client.Do(freq, fres) +func (h *GatewayAPI) doConnect(endpoint string, basicAuth gateway.BasicAuth) (*GatewayConnectResponse, error) { + res, err := doGatewayRequest(&ProxyRequest{ + Method: http.MethodGet, + Endpoint: endpoint, + Path: "/_framework/api/_info", + BasicAuth: basicAuth, + }) if err != nil { return nil, err } - b := fres.Body() + b := res.Body gres := &GatewayConnectResponse{} err = json.Unmarshal(b, gres) return gres, err @@ -273,17 +295,14 @@ func (h *GatewayAPI) doConnect(endpoint, username, password string) (*GatewayCon func (h *GatewayAPI) tryConnect(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { var reqBody = struct { Endpoint string `json:"endpoint"` - BasicAuth struct { - Username string `json:"username"` - Password string `json:"password"` - } + BasicAuth gateway.BasicAuth }{} err := h.DecodeJSON(req, &reqBody) if err != nil { h.WriteError(w, err.Error(), http.StatusInternalServerError) return } - connectRes, err := h.doConnect(reqBody.Endpoint, reqBody.BasicAuth.Username, reqBody.BasicAuth.Password) + connectRes, err := h.doConnect(reqBody.Endpoint, reqBody.BasicAuth) if err != nil { h.WriteError(w, err.Error(), http.StatusInternalServerError) return