From 92a442f2eb49970e6065528adee0732221d65ef4 Mon Sep 17 00:00:00 2001 From: senlin Date: Thu, 7 Mar 2019 13:59:56 -0800 Subject: [PATCH] fix issue #134 1. QSL to support dashed keyname 2. fix full sync API timeout problem after add more k8s clusters 3. support special chars when QSL query is part of http URL, e.g. pod[@containers.$image="k8s.io/test"]{*} --- service/apis/entity_service.go | 1 + service/apis/qsl_service.go | 6 +- service/resources/server_resource.go | 142 ++++++++++++---------- service/resources/server_resource_v1.1.go | 54 +++++--- service/server.go | 6 +- 5 files changed, 119 insertions(+), 90 deletions(-) diff --git a/service/apis/entity_service.go b/service/apis/entity_service.go index 01d3434..8c5ba08 100644 --- a/service/apis/entity_service.go +++ b/service/apis/entity_service.go @@ -194,6 +194,7 @@ func (s EntityService) SyncEntities(meta string, data []map[string]interface{}) } if !found { s.dbclient.DeleteEntity(uid) + log.Debugf("entity %s deleted by sync", rid) } } } diff --git a/service/apis/qsl_service.go b/service/apis/qsl_service.go index 74c2cef..55cd316 100644 --- a/service/apis/qsl_service.go +++ b/service/apis/qsl_service.go @@ -17,10 +17,10 @@ import ( ) // regex to get objtype[filters]{fields} -var blockRegex = `([a-zA-Z0-9]+)\[?(?:(\@[\(\)\"\,\@\$\=\>\<\~\!a-zA-Z0-9\-\.\|\&\:_\^\*]*|\**|\$\$[a-zA-Z0-9\,\=]+))\]?\{([\*|[\,\@\"\=a-zA-Z0-9\-]*)` +var blockRegex = `([a-zA-Z0-9]+)\[?(?:(\@[\(\)\"\,\@\$\=\>\<\~\!a-zA-Z0-9\/\-\.\|\&\:_\^\*]*|\**|\$\$[a-zA-Z0-9\,\=]+))\]?\{([\*|[\,\@\"\=a-zA-Z0-9\-]*)` // regex to get KeyOperatorValue from something like numreplicas>=2 -var filterRegex = `\@([a-zA-Z0-9\(\)\.\$]*)([\!\<\>\=\~]*)(\"?[a-zA-Z0-9\-\.\|\&\:_\$\^]*\"?)` +var filterRegex = `\@([a-zA-Z0-9-_\(\)\.\$]*)([\!\<\>\=\~]*)(\"?[a-zA-Z0-9\-\\\/\.\|\&\:_\$\^]*\"?)` // QSLService service for QSL type QSLService struct { @@ -438,7 +438,7 @@ func parseQuery(qry string) (string, string, string, error) { objType := strings.ToLower(matches[1]) filters := matches[2] fields := strings.ToLower(matches[3]) - return objType, filters, fields, nil + return objType, strings.Replace(filters, "/", "\\/", -1), fields, nil } func (qa *QSLService) getCntFilter(query, objType string) (string, error) { diff --git a/service/resources/server_resource.go b/service/resources/server_resource.go index 4bb9507..a119b22 100644 --- a/service/resources/server_resource.go +++ b/service/resources/server_resource.go @@ -34,9 +34,7 @@ type ServerResource struct { // EntityGetHandler REST API for get Entity func (s ServerResource) EntityGetHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -44,19 +42,18 @@ func (s ServerResource) EntityGetHandler(w http.ResponseWriter, r *http.Request) w.Header().Set("Content-Type", "application/json") vars := mux.Vars(r) uid := vars[util.UID] - start := time.Now() code := http.StatusOK defer func() { metrics.DgraphGetEntityLatencyHistogram.WithLabelValues(fmt.Sprintf("%d", code)).Observe(time.Since(start).Seconds()) }() - obj, err := s.EntitySvc.GetEntity(uid) if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() code = http.StatusInternalServerError - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } // object not found @@ -64,21 +61,19 @@ func (s ServerResource) EntityGetHandler(w http.ResponseWriter, r *http.Request) metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() code = http.StatusNotFound - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"entity with id %s not found\"}", http.StatusNotFound, uid))) + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"entity with id %s not found\"}", code, uid))) return } - obj["status"] = http.StatusOK + obj["status"] = code ret, _ := json.Marshal(obj) w.Write(ret) - metrics.KatlasNumReq2xx.Inc() } // MetaGetHandler REST API for get metadata func (s ServerResource) MetaGetHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -90,6 +85,7 @@ func (s ServerResource) MetaGetHandler(w http.ResponseWriter, r *http.Request) { if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) return } @@ -104,14 +100,13 @@ func (s ServerResource) MetaGetHandler(w http.ResponseWriter, r *http.Request) { } metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() + w.WriteHeader(http.StatusNotFound) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"metadata %s not found\"}", http.StatusNotFound, name))) } // MetaDeleteHandler REST API for delete metadata func (s ServerResource) MetaDeleteHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "application/json") vars := mux.Vars(r) @@ -120,6 +115,7 @@ func (s ServerResource) MetaDeleteHandler(w http.ResponseWriter, r *http.Request if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() + w.WriteHeader(http.StatusConflict) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusConflict, trim(err.Error())))) return } @@ -134,15 +130,12 @@ func (s ServerResource) MetaDeleteHandler(w http.ResponseWriter, r *http.Request } ret, _ := json.Marshal(msg) w.Write(ret) - metrics.KatlasNumReq2xx.Inc() } // EntityDeleteHandler REST API for delete Entity func (s ServerResource) EntityDeleteHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -163,11 +156,12 @@ func (s ServerResource) EntityDeleteHandler(w http.ResponseWriter, r *http.Reque metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() code = http.StatusInternalServerError - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } msg := map[string]interface{}{ - "status": http.StatusOK, + "status": code, "objects": []map[string]interface{}{ { "resourceid": rid, @@ -177,15 +171,12 @@ func (s ServerResource) EntityDeleteHandler(w http.ResponseWriter, r *http.Reque } ret, _ := json.Marshal(msg) w.Write(ret) - metrics.KatlasNumReq2xx.Inc() } // EntityCreateHandler REST API for create Entity func (s ServerResource) EntityCreateHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -194,22 +185,26 @@ func (s ServerResource) EntityCreateHandler(w http.ResponseWriter, r *http.Reque vars := mux.Vars(r) meta := vars[util.Metadata] clusterName := r.Header.Get(util.ClusterName) - + code := http.StatusOK body, err := ioutil.ReadAll(r.Body) if err != nil { log.Error(err) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) + return } payload, err := buildEntityData(clusterName, meta, body, false) if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } - start := time.Now() - code := http.StatusOK defer func() { metrics.DgraphCreateEntityLatencyHistogram.WithLabelValues(fmt.Sprintf("%d", code)).Observe(time.Since(start).Seconds()) }() @@ -218,13 +213,14 @@ func (s ServerResource) EntityCreateHandler(w http.ResponseWriter, r *http.Reque if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() - code = http.StatusInternalServerError log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + code = http.StatusInternalServerError + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } msg := map[string]interface{}{ - "status": http.StatusOK, + "status": code, "objects": []map[string]interface{}{ { "uid": uid, @@ -234,15 +230,12 @@ func (s ServerResource) EntityCreateHandler(w http.ResponseWriter, r *http.Reque } ret, _ := json.Marshal(msg) w.Write(ret) - metrics.KatlasNumReq2xx.Inc() } // EntityUpdateHandler REST API for update Entity func (s ServerResource) EntityUpdateHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -252,10 +245,14 @@ func (s ServerResource) EntityUpdateHandler(w http.ResponseWriter, r *http.Reque vars := mux.Vars(r) meta := vars[util.Metadata] uuid := vars[util.UID] - + code := http.StatusOK body, err := ioutil.ReadAll(r.Body) if err != nil { log.Error(err) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) + return } payload := make(map[string]interface{}, 0) err = json.Unmarshal(body, &payload) @@ -263,12 +260,12 @@ func (s ServerResource) EntityUpdateHandler(w http.ResponseWriter, r *http.Reque metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } - start := time.Now() - code := http.StatusOK defer func() { metrics.DgraphUpdateEntityLatencyHistogram.WithLabelValues(fmt.Sprintf("%d", code)).Observe(time.Since(start).Seconds()) }() @@ -277,13 +274,14 @@ func (s ServerResource) EntityUpdateHandler(w http.ResponseWriter, r *http.Reque if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() - code = http.StatusInternalServerError log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + code = http.StatusInternalServerError + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } msg := map[string]interface{}{ - "status": http.StatusOK, + "status": code, "objects": []map[string]interface{}{ { "uid": uuid, @@ -299,9 +297,6 @@ func (s ServerResource) EntityUpdateHandler(w http.ResponseWriter, r *http.Reque // EntitySyncHandler REST API to sync entities func (s ServerResource) EntitySyncHandler(w http.ResponseWriter, r *http.Request) { - - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -310,37 +305,43 @@ func (s ServerResource) EntitySyncHandler(w http.ResponseWriter, r *http.Request vars := mux.Vars(r) meta := vars[util.Metadata] clusterName := r.Header.Get(util.ClusterName) - body, err := ioutil.ReadAll(r.Body) if err != nil { log.Error(err) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) + return } payload, err := buildEntityData(clusterName, meta, body, true) if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) return } - err = s.EntitySvc.SyncEntities(meta, payload.([]map[string]interface{})) - if err != nil { - metrics.KatlasNumReqErr.Inc() - metrics.KatlasNumReqErr5xx.Inc() - log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) - return - } - w.Write([]byte(fmt.Sprintf("{\"synced\": \"done\", \"type\": \"%s\"}", meta))) - - metrics.KatlasNumReq2xx.Inc() + metrics.KatlasNumReqCount.Inc() + // return status code 202 directly + w.WriteHeader(http.StatusAccepted) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"message\": \"%s sync request accepted\"}", http.StatusAccepted, meta))) + // process by goroutine + go func() { + err = s.EntitySvc.SyncEntities(meta, payload.([]map[string]interface{})) + if err != nil { + metrics.KatlasNumReqErr.Inc() + metrics.KatlasNumReqErr5xx.Inc() + log.Error(err) + return + } + log.Debugf("%s sync completed, total %d synced", meta, len(payload.([]map[string]interface{}))) + metrics.KatlasNumReq2xx.Inc() + }() } // QueryHandler REST API for get Query Response func (s ServerResource) QueryHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -356,13 +357,14 @@ func (s ServerResource) QueryHandler(w http.ResponseWriter, r *http.Request) { obj, err := s.QuerySvc.GetQueryResult(queryMap) if err != nil { - code = http.StatusInternalServerError metrics.KatlasNumReqErr5xx.Inc() metrics.KatlasNumReqErr.Inc() - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + code = http.StatusInternalServerError + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } - obj["status"] = http.StatusOK + obj["status"] = code ret, _ := json.Marshal(obj) w.Write(ret) @@ -371,9 +373,7 @@ func (s ServerResource) QueryHandler(w http.ResponseWriter, r *http.Request) { // MetaCreateHandler REST API for create Metadata func (s ServerResource) MetaCreateHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "application/json") body, err := ioutil.ReadAll(r.Body) @@ -386,6 +386,7 @@ func (s ServerResource) MetaCreateHandler(w http.ResponseWriter, r *http.Request metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) return } @@ -398,6 +399,7 @@ func (s ServerResource) MetaCreateHandler(w http.ResponseWriter, r *http.Request metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() log.Error(err) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) return } @@ -418,6 +420,7 @@ func (s ServerResource) MetaCreateHandler(w http.ResponseWriter, r *http.Request metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() log.Error(err) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) return } @@ -438,9 +441,7 @@ func (s ServerResource) MetaCreateHandler(w http.ResponseWriter, r *http.Request // MetaUpdateHandler REST API for update Metadata func (s ServerResource) MetaUpdateHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "application/json") vars := mux.Vars(r) @@ -448,6 +449,9 @@ func (s ServerResource) MetaUpdateHandler(w http.ResponseWriter, r *http.Request body, err := ioutil.ReadAll(r.Body) if err != nil { log.Error(err) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) + return } var payload interface{} err = json.Unmarshal(body, &payload) @@ -455,6 +459,7 @@ func (s ServerResource) MetaUpdateHandler(w http.ResponseWriter, r *http.Request metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) return } @@ -463,6 +468,7 @@ func (s ServerResource) MetaUpdateHandler(w http.ResponseWriter, r *http.Request metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() log.Error(err) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) return } @@ -484,15 +490,16 @@ func (s ServerResource) MetaUpdateHandler(w http.ResponseWriter, r *http.Request // SchemaUpsertHandler REST API for create Schema func (s ServerResource) SchemaUpsertHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - defer s.MetaSvc.RemoveSchemaCache(db.LruCache) w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "application/json") body, err := ioutil.ReadAll(r.Body) if err != nil { log.Error(err) + w.WriteHeader(http.StatusBadRequest) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) + return } var payload interface{} err = json.Unmarshal(body, &payload) @@ -500,6 +507,7 @@ func (s ServerResource) SchemaUpsertHandler(w http.ResponseWriter, r *http.Reque metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) return } @@ -511,6 +519,7 @@ func (s ServerResource) SchemaUpsertHandler(w http.ResponseWriter, r *http.Reque metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) return } @@ -521,6 +530,7 @@ func (s ServerResource) SchemaUpsertHandler(w http.ResponseWriter, r *http.Reque log.Error(err) metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) return } @@ -538,6 +548,7 @@ func (s ServerResource) SchemaUpsertHandler(w http.ResponseWriter, r *http.Reque metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) + w.WriteHeader(http.StatusBadRequest) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) return } @@ -546,6 +557,7 @@ func (s ServerResource) SchemaUpsertHandler(w http.ResponseWriter, r *http.Reque metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() log.Error(err) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) return } @@ -561,20 +573,18 @@ func (s ServerResource) SchemaUpsertHandler(w http.ResponseWriter, r *http.Reque // SchemaDropHandler remove db schema func (s ServerResource) SchemaDropHandler(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - defer s.MetaSvc.RemoveSchemaCache(db.LruCache) w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "application/json") vars := mux.Vars(r) predicate := vars[util.Name] - err := s.MetaSvc.DropSchema(predicate) if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() log.Error(err) + w.WriteHeader(http.StatusInternalServerError) w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) return } diff --git a/service/resources/server_resource_v1.1.go b/service/resources/server_resource_v1.1.go index 6124da6..b5a0dc9 100644 --- a/service/resources/server_resource_v1.1.go +++ b/service/resources/server_resource_v1.1.go @@ -14,9 +14,7 @@ import ( // EntityGetHandlerV1_1 REST API for get Entity func (s ServerResource) EntityGetHandlerV1_1(w http.ResponseWriter, r *http.Request) { - metrics.KatlasNumReqCount.Inc() - //Set Access-Control-Allow-Origin header now so that it will be present //even if an error is returned (otherwise the error also causes a CORS //exception in the browser/client) @@ -36,7 +34,8 @@ func (s ServerResource) EntityGetHandlerV1_1(w http.ResponseWriter, r *http.Requ metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() code = http.StatusInternalServerError - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } // object not found @@ -44,10 +43,11 @@ func (s ServerResource) EntityGetHandlerV1_1(w http.ResponseWriter, r *http.Requ metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() code = http.StatusNotFound - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"entity with id %s not found\"}", http.StatusNotFound, uid))) + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"entity with id %s not found\"}", code, uid))) return } - obj["status"] = http.StatusOK + obj["status"] = code ret, _ := json.Marshal(obj) w.Write(ret) @@ -88,11 +88,12 @@ func (s ServerResource) EntityDeleteHandlerV1_1(w http.ResponseWriter, r *http.R metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() code = http.StatusInternalServerError - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } msg := map[string]interface{}{ - "status": http.StatusOK, + "status": code, "objects": []map[string]interface{}{ { "uid": uid, @@ -117,26 +118,34 @@ func (s ServerResource) EntityCreateHandlerV1_1(w http.ResponseWriter, r *http.R w.Header().Set("Content-Type", "application/json") clusterName := r.Header.Get(util.ClusterName) metas, ok := r.URL.Query()[util.ObjType] + code := http.StatusOK if !ok || len(metas[0]) < 1 { - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"metadata not found from parameters\"}", http.StatusBadRequest))) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"metadata not found from parameters\"}", code))) return } meta := metas[0] body, err := ioutil.ReadAll(r.Body) if err != nil { log.Error(err) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) + return } payload, err := buildEntityData(clusterName, meta, body, false) if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } start := time.Now() - code := http.StatusOK defer func() { metrics.DgraphCreateEntityLatencyHistogram.WithLabelValues(fmt.Sprintf("%d", code)).Observe(time.Since(start).Seconds()) }() @@ -145,13 +154,14 @@ func (s ServerResource) EntityCreateHandlerV1_1(w http.ResponseWriter, r *http.R if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() - code = http.StatusInternalServerError log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + code = http.StatusInternalServerError + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } msg := map[string]interface{}{ - "status": http.StatusOK, + "status": code, "objects": []map[string]interface{}{ { "uid": uid, @@ -178,10 +188,14 @@ func (s ServerResource) EntityUpdateHandlerV1_1(w http.ResponseWriter, r *http.R vars := mux.Vars(r) uuid := vars[util.UID] - + code := http.StatusOK body, err := ioutil.ReadAll(r.Body) if err != nil { log.Error(err) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"metadata not found from parameters\"}", code))) + return } payload := make(map[string]interface{}, 0) err = json.Unmarshal(body, &payload) @@ -189,12 +203,13 @@ func (s ServerResource) EntityUpdateHandlerV1_1(w http.ResponseWriter, r *http.R metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr4xx.Inc() log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusBadRequest, trim(err.Error())))) + code = http.StatusBadRequest + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } start := time.Now() - code := http.StatusOK defer func() { metrics.DgraphUpdateEntityLatencyHistogram.WithLabelValues(fmt.Sprintf("%d", code)).Observe(time.Since(start).Seconds()) }() @@ -203,13 +218,14 @@ func (s ServerResource) EntityUpdateHandlerV1_1(w http.ResponseWriter, r *http.R if err != nil { metrics.KatlasNumReqErr.Inc() metrics.KatlasNumReqErr5xx.Inc() - code = http.StatusInternalServerError log.Error(err) - w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", http.StatusInternalServerError, trim(err.Error())))) + code = http.StatusInternalServerError + w.WriteHeader(code) + w.Write([]byte(fmt.Sprintf("{\"status\": %v, \"error\": \"%s\"}", code, trim(err.Error())))) return } msg := map[string]interface{}{ - "status": http.StatusOK, + "status": code, "objects": []map[string]interface{}{ { "uid": uuid, diff --git a/service/server.go b/service/server.go index 452cee1..fd180bb 100644 --- a/service/server.go +++ b/service/server.go @@ -44,6 +44,7 @@ func serve() { qslSvc := apis.NewQSLService(dc) res := resources.ServerResource{EntitySvc: entitySvc, QuerySvc: querySvc, MetaSvc: metaSvc, QSLSvc: qslSvc} // Entity APIs v1 + router.HandleFunc("/v1/entity/{metadata}/{uid}", res.EntityGetHandler).Methods("GET") router.HandleFunc("/v1/entity/{metadata}", res.EntityCreateHandler).Methods("POST") router.HandleFunc("/v1/entity/{metadata}/{uid}", res.EntityUpdateHandler).Methods("POST") @@ -51,7 +52,7 @@ func serve() { router.HandleFunc("/v1/sync/{metadata}", res.EntitySyncHandler).Methods("POST") // Query APIs router.HandleFunc("/v1/query", res.QueryHandler).Methods("GET") - router.HandleFunc("/v1/qsl/{query}", res.QSLHandler).Methods("GET") + router.HandleFunc("/v1/qsl/{query:.*}", res.QSLHandler).Methods("GET") //Metadata router.HandleFunc("/v1/metadata/{name}", res.MetaGetHandler).Methods("GET") router.HandleFunc("/v1/metadata/{name}", res.MetaDeleteHandler).Methods("DELETE") @@ -68,7 +69,8 @@ func serve() { router.HandleFunc("/v1.1/sync/{metadata}", res.EntitySyncHandlerV1_1).Methods("POST") // Query APIs v1.1 router.HandleFunc("/v1.1/query", res.QueryHandlerV1_1).Methods("GET") - router.HandleFunc("/v1.1/qsl/{query}", res.QSLHandlerV1_1).Methods("GET") + // add .* to support url that contains special characters like pod[@name="abc/bcd"]{} + router.HandleFunc("/v1.1/qsl/{query:.*}", res.QSLHandlerV1_1).Methods("GET") //Metadata v1.1 router.HandleFunc("/v1.1/metadata/{name}", res.MetaGetHandlerV1_1).Methods("GET") router.HandleFunc("/v1.1/metadata/{name}", res.MetaDeleteHandlerV1_1).Methods("DELETE")