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

ocket8888 pushed a commit to branch 5.1.x
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git


The following commit(s) were added to refs/heads/5.1.x by this push:
     new 9455a88  Fix servers?dsID=<> route to return mids correctly (#5538) 
(#5588)
9455a88 is described below

commit 9455a882b68a4f5c434e971cce71330f40c16f8a
Author: ocket8888 <[email protected]>
AuthorDate: Fri Feb 26 17:04:41 2021 -0500

    Fix servers?dsID=<> route to return mids correctly (#5538) (#5588)
    
    * fix servers?dsID=<> route to return mids correctly
    
    * code review fixes
    
    * code review fixes
    
    (cherry picked from commit f0130ff48caa3dc07dbf4350193a39308759afd0)
    
    Co-authored-by: Srijeet Chatterjee 
<[email protected]>
---
 .../testing/api/v3/serverservercapability_test.go  |  96 +++++++++++
 traffic_ops/testing/api/v3/tc-fixtures.json        | 192 +++++++++++++++++++++
 traffic_ops/traffic_ops_golang/server/servers.go   |  80 +++++++--
 .../traffic_ops_golang/server/servers_test.go      |   2 +-
 4 files changed, 353 insertions(+), 17 deletions(-)

diff --git a/traffic_ops/testing/api/v3/serverservercapability_test.go 
b/traffic_ops/testing/api/v3/serverservercapability_test.go
index eb5903e..f971f0d 100644
--- a/traffic_ops/testing/api/v3/serverservercapability_test.go
+++ b/traffic_ops/testing/api/v3/serverservercapability_test.go
@@ -19,6 +19,7 @@ import (
        "net/http"
        "net/url"
        "sort"
+       "strconv"
        "testing"
        "time"
 
@@ -32,6 +33,7 @@ func TestServerServerCapabilities(t *testing.T) {
                SortTestServerServerCapabilities(t)
                GetTestServerServerCapabilitiesIMS(t)
                GetTestServerServerCapabilities(t)
+               GetDeliveryServiceServersWithCapabilities(t)
        })
 }
 
@@ -385,3 +387,97 @@ func DeleteTestServerServerCapabilitiesForTopologies(t 
*testing.T) {
        }
 
 }
+
+func GetDeliveryServiceServersWithCapabilities(t *testing.T) {
+       dses, _, err := TOSession.GetDeliveryServicesV30WithHdr(nil, 
url.Values{"xmlId": []string{"ds4"}})
+       if err != nil {
+               t.Fatalf("Failed to get Delivery Services: %v", err)
+       }
+       if len(dses) < 1 {
+               t.Fatal("Failed to get at least one Delivery Service")
+       }
+
+       ds := dses[0]
+       if ds.ID == nil {
+               t.Fatal("Got Delivery Service with nil ID")
+       }
+
+       // Get an edge
+       params := url.Values{}
+       params.Add("hostName", "atlanta-edge-16")
+       rs, _, err := TOSession.GetServersWithHdr(&params, nil)
+       if err != nil {
+               t.Fatalf("Failed to fetch server information: %v", err)
+       } else if len(rs.Response) == 0 {
+               t.Fatalf("Failed to fetch server information: No results 
returned!")
+       }
+       edgeID := *rs.Response[0].ID
+
+       // Get a MID
+       params = url.Values{}
+       params.Add("hostName", "atlanta-mid-02")
+       rs, _, err = TOSession.GetServersWithHdr(&params, nil)
+       if err != nil {
+               t.Fatalf("Failed to fetch server information: %v", err)
+       } else if len(rs.Response) == 0 {
+               t.Fatalf("Failed to fetch server information: No results 
returned!")
+       }
+       midID := *rs.Response[0].ID
+       // assign edge and mid
+       _, _, err = TOSession.CreateDeliveryServiceServers(*ds.ID, 
[]int{edgeID, midID}, true)
+       if err != nil {
+               t.Fatalf("expected no error while assigning servers to DS, but 
got %s", err.Error())
+       }
+       params = url.Values{}
+       params.Add("dsId", strconv.Itoa(*ds.ID))
+       servers, _, err := TOSession.GetServersWithHdr(&params, nil)
+       if err != nil {
+               t.Fatalf("Failed to get server by Delivery Service ID: %v", err)
+       }
+       if len(servers.Response) != 2 {
+               t.Fatalf("expected to get 2 servers for Delivery Service: %d, 
actual: %d", *ds.ID, len(servers.Response))
+       }
+
+       // now assign a capability
+       reqCap := tc.DeliveryServicesRequiredCapability{
+               DeliveryServiceID:  ds.ID,
+               RequiredCapability: util.StrPtr("blah"),
+       }
+       _, _, err = TOSession.CreateDeliveryServicesRequiredCapability(reqCap)
+       // this should fail because the mid doesn't have the reqd capability
+       if err == nil {
+               t.Fatalf("expected error creating DS reqd capability, but got 
nothing")
+       }
+       ssc := tc.ServerServerCapability{
+               ServerID:         &midID,
+               ServerCapability: util.StrPtr("blah"),
+       }
+       // assign the capability to the mid
+       _, _, err = TOSession.CreateServerServerCapability(ssc)
+       if err != nil {
+               t.Fatalf("couldn't assign server capability to server with ID 
%d, err: %s", midID, err.Error())
+       }
+       _, _, err = TOSession.CreateDeliveryServicesRequiredCapability(reqCap)
+       // this should pass now because the mid has the reqd capability
+       if err != nil {
+               t.Fatalf("expected no error creating DS reqd capability, but 
got %s", err.Error())
+       }
+
+       params = url.Values{}
+       params.Add("dsId", strconv.Itoa(*ds.ID))
+       servers, _, err = TOSession.GetServersWithHdr(&params, nil)
+       if err != nil {
+               t.Fatalf("Failed to get server by Delivery Service ID: %v", err)
+       }
+       if len(servers.Response) != 2 {
+               t.Fatalf("expected to get 2 servers for Delivery Service: %d, 
actual: %d", *ds.ID, len(servers.Response))
+       }
+       _, _, err = TOSession.DeleteDeliveryServiceServer(*ds.ID, edgeID)
+       if err != nil {
+               t.Errorf("error trying to delete delivery service server: %s", 
err.Error())
+       }
+       _, _, err = TOSession.DeleteDeliveryServiceServer(*ds.ID, midID)
+       if err != nil {
+               t.Errorf("error trying to delete delivery service server: %s", 
err.Error())
+       }
+}
diff --git a/traffic_ops/testing/api/v3/tc-fixtures.json 
b/traffic_ops/testing/api/v3/tc-fixtures.json
index 03ce021..bb24c57 100644
--- a/traffic_ops/testing/api/v3/tc-fixtures.json
+++ b/traffic_ops/testing/api/v3/tc-fixtures.json
@@ -41,6 +41,13 @@
         {
             "latitude": 0,
             "longitude": 0,
+            "name": "parentCachegroup3",
+            "shortName": "pg3",
+            "typeName": "MID_LOC"
+        },
+        {
+            "latitude": 0,
+            "longitude": 0,
             "name": "secondaryCachegroup",
             "shortName": "sg1",
             "typeName": "MID_LOC"
@@ -118,6 +125,19 @@
         {
             "latitude": 0,
             "longitude": 0,
+            "name": "cachegroup4",
+            "parentCachegroupName": "parentCachegroup3",
+            "shortName": "cg4",
+            "localizationMethods": [
+                "CZ",
+                "DEEP_CZ",
+                "GEO"
+            ],
+            "typeName": "EDGE_LOC"
+        },
+        {
+            "latitude": 0,
+            "longitude": 0,
             "name": "cachegroup3",
             "parentCachegroupName": "parentCachegroup",
             "secondaryParentCachegroupName": "secondaryCachegroup",
@@ -1437,6 +1457,75 @@
             "type": "HTTP",
             "xmlId": "test-ds-server-assignments",
             "maxRequestHeaderBytes": 131072
+        },
+        {
+            "active": false,
+            "cdnName": "cdn1",
+            "cacheurl": "cacheUrl3",
+            "ccrDnsTtl": 3600,
+            "checkPath": "",
+            "consistentHashQueryParams": null,
+            "deepCachingType": "NEVER",
+            "displayName": "d s 4",
+            "dnsBypassCname": null,
+            "dnsBypassIp": "",
+            "dnsBypassIp6": "",
+            "dnsBypassTtl": 30,
+            "dscp": 40,
+            "edgeHeaderRewrite": "edgeRewrite1\nedgeHeader2",
+            "exampleURLs": [
+                "http://ccr.ds4.example.net";,
+                "https://ccr.ds4x.example.net";
+            ],
+            "fqPacingRate": 0,
+            "geoLimit": 0,
+            "geoLimitCountries": "",
+            "geoLimitRedirectURL": null,
+            "geoProvider": 0,
+            "globalMaxMbps": 0,
+            "globalMaxTps": 0,
+            "httpBypassFqdn": "",
+            "infoUrl": "TBD",
+            "initialDispersion": 1,
+            "ipv6RoutingEnabled": true,
+            "lastUpdated": "2018-04-06 16:48:51+00",
+            "logsEnabled": false,
+            "longDesc": "d s 4",
+            "longDesc1": "ds4",
+            "longDesc2": "ds4",
+            "matchList": [
+                {
+                    "pattern": ".*\\.ds4\\..*",
+                    "setNumber": 0,
+                    "type": "HOST_REGEXP"
+                }
+            ],
+            "maxDnsAnswers": 0,
+            "maxOriginConnections": 0,
+            "midHeaderRewrite": "midHeader1\nmidHeader2",
+            "missLat": 41.881944,
+            "missLong": -87.627778,
+            "multiSiteOrigin": false,
+            "orgServerFqdn": "http://origin.ds4.example.net";,
+            "originShield": null,
+            "profileDescription": null,
+            "profileName": null,
+            "protocol": 2,
+            "qstringIgnore": 1,
+            "rangeRequestHandling": 0,
+            "regexRemap": "rr1\nrr2",
+            "regionalGeoBlocking": false,
+            "remapText": "@plugin=tslua.so 
@pparam=/opt/trafficserver/etc/trafficserver/ds4plugin.lua",
+            "routingName": "ccr-ds4",
+            "signed": false,
+            "signingAlgorithm": "url_sig",
+            "sslKeyVersion": 2,
+            "tenant": "tenant3",
+            "tenantName": "tenant3",
+            "type": "HTTP_LIVE",
+            "xmlId": "ds4",
+            "anonymousBlockingEnabled": true,
+            "maxRequestHeaderBytes": 131072
         }
     ],
     "deliveryServicesRegexes": [
@@ -4420,6 +4509,102 @@
             "tcpPort": 80,
             "type": "EDGE",
             "updPending": false
+        },
+        {
+            "cachegroup": "cachegroup1",
+            "cdnName": "cdn1",
+            "domainName": "ga.atlanta.kabletown.net",
+            "guid": null,
+            "hostName": "atlanta-edge-16",
+            "httpsPort": 443,
+            "iloIpAddress": "",
+            "iloIpGateway": "",
+            "iloIpNetmask": "",
+            "iloPassword": "",
+            "iloUsername": "",
+            "interfaces": [
+                {
+                    "ipAddresses": [
+                        {
+                            "address": "127.1.0.21/30",
+                            "gateway": "127.1.0.21",
+                            "serviceAddress": true
+                        },
+                        {
+                            "address": "2346:1234:12:8::1/64",
+                            "gateway": "2346:1234:12:8::1",
+                            "serviceAddress": false
+                        }
+                    ],
+                    "maxBandwidth": null,
+                    "monitor": true,
+                    "mtu": 9000,
+                    "name": "bond0"
+                }
+            ],
+            "lastUpdated": "2018-03-28T17:30:00.220351+00:00",
+            "mgmtIpAddress": "",
+            "mgmtIpGateway": "",
+            "mgmtIpNetmask": "",
+            "offlineReason": null,
+            "physLocation": "Denver",
+            "profile": "EDGE1",
+            "rack": "RR 119.02",
+            "revalPending": false,
+            "status": "REPORTED",
+            "tcpPort": 80,
+            "type": "EDGE",
+            "updPending": false,
+            "xmppId": "atlanta-edge-16\\\\@ocdn.kabletown.net",
+            "xmppPasswd": "X"
+        },
+        {
+            "cachegroup": "parentCachegroup3",
+            "cdnName": "cdn1",
+            "domainName": "ga.atlanta.kabletown.net",
+            "guid": null,
+            "hostName": "atlanta-mid-02",
+            "httpsPort": 443,
+            "iloIpAddress": "",
+            "iloIpGateway": "",
+            "iloIpNetmask": "",
+            "iloPassword": "",
+            "iloUsername": "",
+            "interfaces": [
+                {
+                    "ipAddresses": [
+                        {
+                            "address": "127.1.0.2/30",
+                            "gateway": "127.1.0.2",
+                            "serviceAddress": true
+                        },
+                        {
+                            "address": "2346:1234:12:9::10/64",
+                            "gateway": "2346:1234:12:9::10",
+                            "serviceAddress": false
+                        }
+                    ],
+                    "maxBandwidth": null,
+                    "monitor": true,
+                    "mtu": 9000,
+                    "name": "bond0"
+                }
+            ],
+            "lastUpdated": "2018-03-28T17:30:00.220351+00:00",
+            "mgmtIpAddress": "",
+            "mgmtIpGateway": "",
+            "mgmtIpNetmask": "",
+            "offlineReason": null,
+            "physLocation": "Denver",
+            "profile": "MID1",
+            "rack": "RR 119.02",
+            "revalPending": false,
+            "status": "REPORTED",
+            "tcpPort": 80,
+            "type": "MID",
+            "updPending": false,
+            "xmppId": "atlanta-mid-02\\\\@ocdn.kabletown.net",
+            "xmppPasswd": "X"
         }
     ],
     "serverCapabilities": [
@@ -4437,6 +4622,9 @@
         },
         {
             "name": "asdf"
+        },
+        {
+            "name": "blah"
         }
     ],
     "serverServerCapabilities": [
@@ -4511,6 +4699,10 @@
         {
             "serverHostName": "dtrc-mid-04",
             "serverCapability": "asdf"
+        },
+        {
+            "serverHostName": "atlanta-edge-16",
+            "serverCapability": "blah"
         }
     ],
     "serviceCategories": [
diff --git a/traffic_ops/traffic_ops_golang/server/servers.go 
b/traffic_ops/traffic_ops_golang/server/servers.go
index 3094cf1..abcbdce 100644
--- a/traffic_ops/traffic_ops_golang/server/servers.go
+++ b/traffic_ops/traffic_ops_golang/server/servers.go
@@ -153,6 +153,22 @@ SELECT
        s.status_last_updated
 ` + serversFromAndJoin
 
+const selectIDQuery = `
+SELECT
+       s.id
+` + serversFromAndJoin
+
+const midWhereClause = `
+WHERE t.name = :cache_type_mid AND s.cachegroup IN (
+       SELECT cg.parent_cachegroup_id FROM cachegroup AS cg
+       WHERE cg.id IN (
+       SELECT s.cachegroup FROM server AS s
+       WHERE s.id = ANY(:edge_ids)))
+       AND (SELECT d.topology
+               FROM deliveryservice d
+               WHERE d.id = :ds_id) IS NULL
+`
+
 const insertQueryV3 = `
 INSERT INTO server (
        cachegroup,
@@ -400,9 +416,9 @@ RETURNING
 `
 
 const originServerQuery = `
-JOIN deliveryservice_server dsorg 
-ON dsorg.server = s.id 
-WHERE t.name = '` + tc.OriginTypeName + `' 
+JOIN deliveryservice_server dsorg
+ON dsorg.server = s.id
+WHERE t.name = '` + tc.OriginTypeName + `'
 AND dsorg.deliveryservice=:dsId
 `
 const deleteServerQuery = `DELETE FROM server WHERE id=$1`
@@ -937,10 +953,11 @@ func getServers(h http.Header, params map[string]string, 
tx *sqlx.Tx, user *auth
 
        // if ds requested uses mid-tier caches, add those to the list as well
        if usesMids {
-               midIDs, userErr, sysErr, errCode := getMidServers(ids, servers, 
dsID, cdnID, tx)
+               midIDs, userErr, sysErr, errCode := getMidServers(ids, servers, 
dsID, cdnID, tx, dsHasRequiredCapabilities)
 
                log.Debugf("getting mids: %v, %v, %s\n", userErr, sysErr, 
http.StatusText(errCode))
 
+               serverCount = serverCount + uint64(len(midIDs))
                if userErr != nil || sysErr != nil {
                        return nil, serverCount, userErr, sysErr, errCode, nil
                }
@@ -1028,7 +1045,7 @@ func getServers(h http.Header, params map[string]string, 
tx *sqlx.Tx, user *auth
 }
 
 // getMidServers gets the mids used by the edges provided with an option to 
filter for a given cdn
-func getMidServers(edgeIDs []int, servers map[int]tc.ServerNullable, dsID int, 
cdnID int, tx *sqlx.Tx) ([]int, error, error, int) {
+func getMidServers(edgeIDs []int, servers map[int]tc.ServerNullable, dsID int, 
cdnID int, tx *sqlx.Tx, includeCapabilities bool) ([]int, error, error, int) {
        if len(edgeIDs) == 0 {
                return nil, nil, nil, http.StatusOK
        }
@@ -1039,17 +1056,48 @@ func getMidServers(edgeIDs []int, servers 
map[int]tc.ServerNullable, dsID int, c
                "ds_id":          dsID,
        }
 
-       // TODO: include secondary parent?
-       query := selectQuery + `
-       WHERE t.name = :cache_type_mid AND s.cachegroup IN (
-       SELECT cg.parent_cachegroup_id FROM cachegroup AS cg
-       WHERE cg.id IN (
-       SELECT s.cachegroup FROM server AS s
-       WHERE s.id = ANY(:edge_ids)))
-       AND (SELECT d.topology
-               FROM deliveryservice d
-               WHERE d.id = :ds_id) IS NULL
-       `
+       midIDs := []int{}
+       query := ""
+       if includeCapabilities {
+               // Query to select the associated mids for this DS
+               q := selectIDQuery + midWhereClause
+               rows, err := tx.NamedQuery(q, filters)
+               if err != nil {
+                       return nil, err, nil, http.StatusBadRequest
+               }
+               defer rows.Close()
+
+               for rows.Next() {
+                       var midID int
+                       if err := rows.Scan(&midID); err != nil {
+                               log.Errorf("could not scan mid server id: 
%s\n", err)
+                               return nil, nil, err, 
http.StatusInternalServerError
+                       }
+                       midIDs = append(midIDs, midID)
+               }
+               filters["mid_ids"] = pq.Array(midIDs)
+
+               // Query to select only those mids that match the required 
capabilities of the DS
+               query = selectQuery + midWhereClause + `
+               AND s.id IN (
+               WITH capabilities AS (
+               SELECT ARRAY_AGG(ssc.server_capability), server
+               FROM server_server_capability ssc
+               WHERE ssc.server = ANY(:mid_ids)
+               GROUP BY server)
+               SELECT server
+               FROM capabilities WHERE
+               capabilities.array_agg
+               @>
+               (
+               SELECT ARRAY_AGG(drc.required_capability)
+               FROM deliveryservices_required_capability drc
+               WHERE drc.deliveryservice_id=:ds_id)
+               )`
+       } else {
+               // TODO: include secondary parent?
+               query = selectQuery + midWhereClause
+       }
 
        if cdnID > 0 {
                query += ` AND s.cdn_id = :cdn_id`
diff --git a/traffic_ops/traffic_ops_golang/server/servers_test.go 
b/traffic_ops/traffic_ops_golang/server/servers_test.go
index ae7a55a..f8bf3fa 100644
--- a/traffic_ops/traffic_ops_golang/server/servers_test.go
+++ b/traffic_ops/traffic_ops_golang/server/servers_test.go
@@ -479,7 +479,7 @@ func TestGetMidServers(t *testing.T) {
 
        mock.ExpectBegin()
        mock.ExpectQuery("SELECT").WillReturnRows(rows2)
-       mid, userErr, sysErr, errCode := getMidServers(serverIDs, serverMap, 0, 
0, db.MustBegin())
+       mid, userErr, sysErr, errCode := getMidServers(serverIDs, serverMap, 0, 
0, db.MustBegin(), false)
 
        if userErr != nil || sysErr != nil {
                t.Fatalf("getMidServers expected: no errors, actual: %v %v with 
status: %s", userErr, sysErr, http.StatusText(errCode))

Reply via email to