You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@trafficcontrol.apache.org by GitBox <gi...@apache.org> on 2018/06/05 18:52:05 UTC

[GitHub] elsloo closed pull request #2301: Add TO Go cachegroups/id/queue_update

elsloo closed pull request #2301: Add TO Go cachegroups/id/queue_update
URL: https://github.com/apache/incubator-trafficcontrol/pull/2301
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/lib/go-tc/v13/cachegroups.go b/lib/go-tc/v13/cachegroups.go
index ee203fcd5..d3b759936 100644
--- a/lib/go-tc/v13/cachegroups.go
+++ b/lib/go-tc/v13/cachegroups.go
@@ -19,7 +19,10 @@ package v13
  * under the License.
  */
 
-import tc "github.com/apache/incubator-trafficcontrol/lib/go-tc"
+import (
+	"github.com/apache/incubator-trafficcontrol/lib/go-tc"
+	"github.com/apache/incubator-trafficcontrol/lib/go-util"
+)
 
 // CacheGroupResponse ...
 type CacheGroupsResponse struct {
@@ -60,3 +63,9 @@ type CacheGroupNullable struct {
 type CachegroupTrimmedName struct {
 	Name string `json:"name"`
 }
+
+type CachegroupQueueUpdatesRequest struct {
+	Action string           `json:"action"`
+	CDN    *tc.CDNName      `json:"cdn"`
+	CDNID  *util.JSONIntStr `json:"cdnId"`
+}
diff --git a/lib/go-util/num.go b/lib/go-util/num.go
index fdb79b259..8f5532a5e 100644
--- a/lib/go-util/num.go
+++ b/lib/go-util/num.go
@@ -19,6 +19,11 @@ package util
  * under the License.
  */
 
+import (
+	"errors"
+	"strconv"
+)
+
 const MSPerNS = int64(1000000)
 
 // ToNumeric returns a float for any numeric type, and false if the interface does not hold a numeric type.
@@ -54,3 +59,23 @@ func ToNumeric(v interface{}) (float64, bool) {
 		return 0.0, false
 	}
 }
+
+// JSONIntStr unmarshals JSON strings or numbers into an int.
+// This is designed to handle backwards-compatibility for old Perl endpoints which accept both. Please do not use this for new endpoints or new APIs, APIs should be well-typed.
+type JSONIntStr int64
+
+func (i *JSONIntStr) UnmarshalJSON(d []byte) error {
+	if len(d) == 0 {
+		return errors.New("empty object")
+	}
+	if d[0] == '"' {
+		d = d[1 : len(d)-1] // strip JSON quotes
+	}
+	err := error(nil)
+	di, err := strconv.ParseInt(string(d), 10, 64)
+	if err != nil {
+		return errors.New("not an integer")
+	}
+	*i = JSONIntStr(di)
+	return nil
+}
diff --git a/traffic_ops/traffic_ops_golang/cachegroup/queueupdate.go b/traffic_ops/traffic_ops_golang/cachegroup/queueupdate.go
new file mode 100644
index 000000000..8256eb43f
--- /dev/null
+++ b/traffic_ops/traffic_ops_golang/cachegroup/queueupdate.go
@@ -0,0 +1,150 @@
+package cachegroup
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import (
+	"database/sql"
+	"encoding/json"
+	"errors"
+	"net/http"
+	"strconv"
+
+	"github.com/apache/incubator-trafficcontrol/lib/go-tc"
+	tcv13 "github.com/apache/incubator-trafficcontrol/lib/go-tc/v13"
+	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/api"
+	"github.com/apache/incubator-trafficcontrol/traffic_ops/traffic_ops_golang/auth"
+)
+
+func QueueUpdates(db *sql.DB) http.HandlerFunc {
+	return func(w http.ResponseWriter, r *http.Request) {
+		user, err := auth.GetCurrentUser(r.Context())
+		if err != nil {
+			api.HandleErr(w, r, http.StatusInternalServerError, nil, errors.New("getting user: "+err.Error()))
+			return
+		}
+		params, intParams, userErr, sysErr, errCode := api.AllParams(r, []string{"id"})
+		if userErr != nil || sysErr != nil {
+			api.HandleErr(w, r, errCode, userErr, sysErr)
+			return
+		}
+		reqObj := tcv13.CachegroupQueueUpdatesRequest{}
+		if err := json.NewDecoder(r.Body).Decode(&reqObj); err != nil {
+			api.HandleErr(w, r, http.StatusBadRequest, errors.New("malformed JSON: "+err.Error()), nil)
+			return
+		}
+		if reqObj.Action != "queue" && reqObj.Action != "dequeue" {
+			api.HandleErr(w, r, http.StatusBadRequest, errors.New("action must be 'queue' or 'dequeue'"), nil)
+			return
+		}
+		if reqObj.CDN == nil && reqObj.CDNID == nil {
+			api.HandleErr(w, r, http.StatusBadRequest, errors.New("cdn does not exist"), nil)
+			return
+		}
+		if reqObj.CDN == nil || *reqObj.CDN == "" {
+			cdn, ok, err := getCDNNameFromID(db, int64(*reqObj.CDNID))
+			if err != nil {
+				api.HandleErr(w, r, http.StatusInternalServerError, nil, errors.New("getting CDN name from ID '"+strconv.Itoa(int(*reqObj.CDNID))+"': "+err.Error()))
+				return
+			}
+			if !ok {
+				api.HandleErr(w, r, http.StatusBadRequest, errors.New("cdn "+strconv.Itoa(int(*reqObj.CDNID))+" does not exist"), nil)
+				return
+			}
+			reqObj.CDN = &cdn
+		}
+		cgID := int64(intParams["id"])
+		cgName, ok, err := getCGNameFromID(db, cgID)
+		if err != nil {
+			api.HandleErr(w, r, http.StatusInternalServerError, nil, errors.New("getting cachegroup name from ID '"+params["id"]+"': "+err.Error()))
+			return
+		}
+		if !ok {
+			api.HandleErr(w, r, http.StatusBadRequest, errors.New("cachegroup "+params["id"]+" does not exist"), nil)
+			return
+		}
+		queue := reqObj.Action == "queue"
+		updatedCaches, err := queueUpdates(db, cgID, *reqObj.CDN, queue)
+		if err != nil {
+			api.HandleErr(w, r, http.StatusInternalServerError, nil, errors.New("queueing updates: "+err.Error()))
+			return
+		}
+		api.WriteResp(w, r, QueueUpdatesResp{
+			CacheGroupName: cgName,
+			Action:         reqObj.Action,
+			ServerNames:    updatedCaches,
+			CDN:            *reqObj.CDN,
+			CacheGroupID:   cgID,
+		})
+		api.CreateChangeLogRaw(api.ApiChange, "Server updates "+reqObj.Action+"d for "+string(cgName), *user, db)
+	}
+}
+
+type QueueUpdatesResp struct {
+	CacheGroupName tc.CacheGroupName `json:"cachegroupName"`
+	Action         string            `json:"action"`
+	ServerNames    []tc.CacheName    `json:"serverNames"`
+	CDN            tc.CDNName        `json:"cdn"`
+	CacheGroupID   int64             `json:"cachegroupID"`
+}
+
+func getCDNNameFromID(db *sql.DB, id int64) (tc.CDNName, bool, error) {
+	name := ""
+	if err := db.QueryRow(`SELECT name FROM cdn WHERE id = $1`, id).Scan(&name); err != nil {
+		if err == sql.ErrNoRows {
+			return "", false, nil
+		}
+		return "", false, errors.New("querying CDN ID: " + err.Error())
+	}
+	return tc.CDNName(name), true, nil
+}
+
+func getCGNameFromID(db *sql.DB, id int64) (tc.CacheGroupName, bool, error) {
+	name := ""
+	if err := db.QueryRow(`SELECT name FROM cachegroup WHERE id = $1`, id).Scan(&name); err != nil {
+		if err == sql.ErrNoRows {
+			return "", false, nil
+		}
+		return "", false, errors.New("querying cachegroup ID: " + err.Error())
+	}
+	return tc.CacheGroupName(name), true, nil
+}
+
+func queueUpdates(db *sql.DB, cgID int64, cdn tc.CDNName, queue bool) ([]tc.CacheName, error) {
+	q := `
+UPDATE server SET upd_pending = $1
+WHERE server.cachegroup = $2
+AND server.cdn_id = (select id from cdn where name = $3)
+RETURNING server.host_name
+`
+	rows, err := db.Query(q, queue, cgID, cdn)
+	if err != nil {
+		return nil, errors.New("querying queue updates: " + err.Error())
+	}
+	defer rows.Close()
+	names := []tc.CacheName{}
+	for rows.Next() {
+		name := ""
+		if err := rows.Scan(&name); err != nil {
+			return nil, errors.New("scanning queue updates: " + err.Error())
+		}
+		names = append(names, tc.CacheName(name))
+	}
+	return names, nil
+}
diff --git a/traffic_ops/traffic_ops_golang/routes.go b/traffic_ops/traffic_ops_golang/routes.go
index ad6fba960..7b472054e 100644
--- a/traffic_ops/traffic_ops_golang/routes.go
+++ b/traffic_ops/traffic_ops_golang/routes.go
@@ -98,6 +98,8 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) {
 		{1.1, http.MethodPost, `cachegroups/?$`, api.CreateHandler(cachegroup.GetRefType(), d.DB), auth.PrivLevelOperations, Authenticated, nil},
 		{1.1, http.MethodDelete, `cachegroups/{id}$`, api.DeleteHandler(cachegroup.GetRefType(), d.DB), auth.PrivLevelOperations, Authenticated, nil},
 
+		{1.1, http.MethodPost, `cachegroups/{id}/queue_update$`, cachegroup.QueueUpdates(d.DB.DB), auth.PrivLevelOperations, Authenticated, nil},
+
 		//CDN
 		{1.1, http.MethodGet, `cdns/metric_types`, notImplementedHandler, 0, NoAuth, nil}, // MUST NOT end in $, because the 1.x route is longer
 		{1.1, http.MethodGet, `cdns/capacity$`, handlerToFunc(proxyHandler), 0, NoAuth, []Middleware{}},


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services