You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by el...@apache.org on 2018/07/06 17:17:11 UTC

[trafficcontrol] 01/02: Add TO Go deliveryservice_matches

This is an automated email from the ASF dual-hosted git repository.

elsloo pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git

commit 90279384b7b5c1436d4ba1925f7ed3b4bd125ee3
Author: Robert Butts <ro...@apache.org>
AuthorDate: Thu Jun 14 17:05:12 2018 -0600

    Add TO Go deliveryservice_matches
---
 lib/go-tc/deliveryservices.go                      |   7 ++
 .../deliveryservice/deliveryservicesv13.go         |   2 +-
 .../traffic_ops_golang/deliveryservice/matches.go  | 125 +++++++++++++++++++++
 .../deliveryservice/request/requests.go            |   2 +-
 traffic_ops/traffic_ops_golang/routes.go           |   2 +
 traffic_ops/traffic_ops_golang/tenant/tenancy.go   |  24 ++--
 6 files changed, 147 insertions(+), 15 deletions(-)

diff --git a/lib/go-tc/deliveryservices.go b/lib/go-tc/deliveryservices.go
index 7cd1324..519e97b 100644
--- a/lib/go-tc/deliveryservices.go
+++ b/lib/go-tc/deliveryservices.go
@@ -526,6 +526,13 @@ type DeliveryServiceCapacity struct {
 	MaintenancePercent float64 `json:"maintenancePercent"`
 }
 
+type DeliveryServiceMatchesResp []DeliveryServicePatterns
+
+type DeliveryServicePatterns struct {
+	Patterns []string            `json:"patterns"`
+	DSName   DeliveryServiceName `json:"dsName"`
+}
+
 // DeliveryServiceRoutingResponse ...
 type DeliveryServiceRoutingResponse struct {
 	Response DeliveryServiceRouting `json:"response"`
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv13.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv13.go
index cd6bfa9..f48e948 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv13.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv13.go
@@ -623,7 +623,7 @@ func readGetDeliveryServices(params map[string]string, tx *sqlx.Tx, user *auth.C
 
 	if tenancyEnabled {
 		log.Debugln("Tenancy is enabled")
-		tenantIDs, err := tenant.GetUserTenantIDListTx(user, tx)
+		tenantIDs, err := tenant.GetUserTenantIDListTx(tx.Tx, user.TenantID)
 		if err != nil {
 			log.Errorln("received error querying for user's tenants: " + err.Error())
 			return nil, []error{tc.DBError}, tc.SystemError
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/matches.go b/traffic_ops/traffic_ops_golang/deliveryservice/matches.go
new file mode 100644
index 0000000..972a578
--- /dev/null
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/matches.go
@@ -0,0 +1,125 @@
+package deliveryservice
+
+/*
+ * 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"
+	"errors"
+	"net/http"
+	"strings"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
+	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/tenant"
+
+	"github.com/lib/pq"
+)
+
+func GetMatches(w http.ResponseWriter, r *http.Request) {
+	inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+	if userErr != nil || sysErr != nil {
+		api.HandleErr(w, r, errCode, userErr, sysErr)
+		return
+	}
+	defer inf.Close()
+	matches, err := getUserDSMatches(inf.Tx.Tx, inf.User.TenantID)
+	if err != nil {
+		api.HandleErr(w, r, http.StatusInternalServerError, nil, errors.New("getting delivery service matches: "+err.Error()))
+		return
+	}
+	*inf.CommitTx = true
+	api.WriteResp(w, r, matches)
+}
+
+func getUserDSMatches(tx *sql.Tx, userTenantID int) ([]tc.DeliveryServicePatterns, error) {
+	q := `
+SELECT ds.xml_id, ds.remap_text, r.pattern
+FROM deliveryservice as ds
+JOIN deliveryservice_regex as dsr ON dsr.deliveryservice = ds.id
+JOIN regex as r ON r.id = dsr.regex
+WHERE ds.active = true
+`
+	qParams := []interface{}{}
+	tenancyEnabled, err := tenant.IsTenancyEnabledTx(tx)
+	if err != nil {
+		return nil, errors.New("checking tenancy enabled: " + err.Error())
+	}
+	if tenancyEnabled {
+		tenantIDs, err := tenant.GetUserTenantIDListTx(tx, userTenantID)
+		if err != nil {
+			return nil, errors.New("getting user tenant ID list: " + err.Error())
+		}
+		q += `
+AND ds.tenant_id = ANY($1)
+`
+		qParams = append(qParams, pq.Array(tenantIDs))
+	}
+
+	q += `
+ORDER BY dsr.set_number
+`
+
+	rows, err := tx.Query(q, qParams...)
+	if err != nil {
+		return nil, errors.New("querying delivery service matches: " + err.Error())
+	}
+	defer rows.Close()
+
+	matches := []tc.DeliveryServicePatterns{}
+	matchRegexes := map[tc.DeliveryServiceName][]string{}
+	for rows.Next() {
+		ds := tc.DeliveryServiceName("")
+		remapText := (*string)(nil)
+		pattern := ""
+		if err := rows.Scan(&ds, &remapText, &pattern); err != nil {
+			return nil, errors.New("scanning delivery service matches: " + err.Error())
+		}
+		if remapText != nil && strings.HasPrefix(*remapText, `regex_map`) {
+			matches = append(matches, tc.DeliveryServicePatterns{DSName: dsNameToUnderscores(ds), Patterns: []string{remapToMatch(*remapText)}})
+		} else {
+			matchRegexes[ds] = append(matchRegexes[ds], regexToMatch(pattern))
+		}
+	}
+	for ds, dsMatches := range matchRegexes {
+		matches = append(matches, tc.DeliveryServicePatterns{DSName: dsNameToUnderscores(ds), Patterns: dsMatches})
+	}
+	return matches, nil
+}
+
+// dsNameToUnderscores changes delivery service name (xml_id) hyphens to underscores, to emulate the behavior of the old Perl Traffic Ops API.
+func dsNameToUnderscores(ds tc.DeliveryServiceName) tc.DeliveryServiceName {
+	return tc.DeliveryServiceName(strings.Replace(string(ds), `-`, `_`, -1))
+}
+
+func remapToMatch(regex string) string {
+	// TODO: emulates old Perl behavior; verify correctness and usefulness
+	regex = strings.TrimPrefix(regex, `regex_map http://`)
+	hyphenI := strings.Index(regex, `-`)
+	if hyphenI > 0 {
+		regex = regex[:hyphenI+1]
+	}
+	return regex
+}
+
+func regexToMatch(remap string) string {
+	remap = strings.Replace(remap, `\`, ``, -1)
+	remap = strings.Replace(remap, `.*`, ``, -1)
+	return remap
+}
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go b/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go
index 317a79e..78c4546 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/request/requests.go
@@ -108,7 +108,7 @@ func (req *TODeliveryServiceRequest) Read(parameters map[string]string) ([]inter
 	}
 	if tenancyEnabled {
 		log.Debugln("Tenancy is enabled")
-		tenantIDs, err := tenant.GetUserTenantIDListTx(req.ReqInfo.User, req.ReqInfo.Tx)
+		tenantIDs, err := tenant.GetUserTenantIDListTx(req.ReqInfo.Tx.Tx, req.ReqInfo.User.TenantID)
 		if err != nil {
 			log.Errorln("received error querying for user's tenants: " + err.Error())
 			return nil, []error{tc.DBError}, tc.SystemError
diff --git a/traffic_ops/traffic_ops_golang/routes.go b/traffic_ops/traffic_ops_golang/routes.go
index 6ce58df..cd6b623 100644
--- a/traffic_ops/traffic_ops_golang/routes.go
+++ b/traffic_ops/traffic_ops_golang/routes.go
@@ -195,6 +195,8 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) {
 		{1.1, http.MethodGet, `deliveryservices/{id}/unassigned_servers$`, dsserver.GetReadHandler(d.DB, tc.Unassigned), auth.PrivLevelReadOnly, Authenticated, nil},
 		//{1.1, http.MethodGet, `deliveryservices/{id}/servers/eligible$`, dsserver.GetReadHandler(d.Tx, tc.Eligible),auth.PrivLevelReadOnly, Authenticated, nil},
 
+		{1.1, http.MethodGet, `deliveryservice_matches/?(\.json)?$`, deliveryservice.GetMatches, auth.PrivLevelReadOnly, Authenticated, nil},
+
 		//Server
 		{1.1, http.MethodGet, `servers/checks$`, handlerToFunc(proxyHandler), 0, NoAuth, []Middleware{}},
 		{1.1, http.MethodGet, `servers/status$`, handlerToFunc(proxyHandler), 0, NoAuth, []Middleware{}},
diff --git a/traffic_ops/traffic_ops_golang/tenant/tenancy.go b/traffic_ops/traffic_ops_golang/tenant/tenancy.go
index 51f41ad..d24bab3 100644
--- a/traffic_ops/traffic_ops_golang/tenant/tenancy.go
+++ b/traffic_ops/traffic_ops_golang/tenant/tenancy.go
@@ -180,30 +180,26 @@ func GetUserTenantIDList(user auth.CurrentUser, db *sqlx.DB) ([]int, error) {
 	return tenants, nil
 }
 
-func GetUserTenantIDListTx(user *auth.CurrentUser, tx *sqlx.Tx) ([]int, error) {
-	query := `WITH RECURSIVE q AS (SELECT id, name, active, parent_id FROM tenant WHERE id = $1
-	UNION SELECT t.id, t.name, t.active, t.parent_id  FROM tenant t JOIN q ON q.id = t.parent_id)
-	SELECT id FROM q;`
-
-	log.Debugln("\nQuery: ", query)
-
-	var tenantID int
-
-	rows, err := tx.Query(query, user.TenantID)
+func GetUserTenantIDListTx(tx *sql.Tx, userTenantID int) ([]int, error) {
+	query := `
+WITH RECURSIVE q AS (SELECT id, name, active, parent_id FROM tenant WHERE id = $1
+UNION SELECT t.id, t.name, t.active, t.parent_id  FROM tenant t JOIN q ON q.id = t.parent_id)
+SELECT id FROM q;
+`
+	rows, err := tx.Query(query, userTenantID)
 	if err != nil {
 		return nil, err
 	}
 	defer rows.Close()
 
 	tenants := []int{}
-
 	for rows.Next() {
+		tenantID := 0
 		if err := rows.Scan(&tenantID); err != nil {
 			return nil, err
 		}
 		tenants = append(tenants, tenantID)
 	}
-
 	return tenants, nil
 }
 
@@ -219,10 +215,12 @@ func IsTenancyEnabled(db *sqlx.DB) bool {
 	return useTenancy
 }
 
+// IsTenancyEnabledTx returns true if tenancy is enabled or false otherwise
 func IsTenancyEnabledTx(tx *sql.Tx) (bool, error) {
 	query := `SELECT COALESCE(value::boolean,FALSE) AS value FROM parameter WHERE name = 'use_tenancy' AND config_file = 'global' UNION ALL SELECT FALSE FETCH FIRST 1 ROW ONLY`
 	useTenancy := false
-	if err := tx.QueryRow(query).Scan(&useTenancy); err != nil {
+	err := tx.QueryRow(query).Scan(&useTenancy)
+	if err != nil {
 		return false, errors.New("checking if tenancy is enabled: " + err.Error())
 	}
 	return useTenancy, nil