You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by oc...@apache.org on 2020/12/03 18:56:03 UTC

[trafficcontrol] branch 5.0.x updated: Validate ORG server for topology based DS (#5307)

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

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


The following commit(s) were added to refs/heads/5.0.x by this push:
     new 38c86ba  Validate ORG server for topology based DS (#5307)
38c86ba is described below

commit 38c86ba87d45ca09cafd648384023e046a2efbfb
Author: rimashah25 <22...@users.noreply.github.com>
AuthorDate: Wed Dec 2 15:20:10 2020 -0700

    Validate ORG server for topology based DS (#5307)
    
    * Edited updateV30() to check if ORG server exists and is part of topology cachegroup
    
    * Added helper function call to db_helpers.go
    
    * Updated code based on review feedback
    
    * Removed fmt statements
    
    * Added test case. Formatted code.
    
    * Updated CHANGELOG.md
    
    * Updated based on feedback.
    
    * Updated testcase
    
    (cherry picked from commit 38fc19e5af2cb4a2dca168dd2ccbbc81654dbe47)
---
 CHANGELOG.md                                       |  1 +
 .../testing/api/v3/deliveryservices_test.go        | 48 ++++++++++++++++++++
 .../traffic_ops_golang/dbhelpers/db_helpers.go     | 53 +++++++++++++++++++++-
 .../deliveryservice/deliveryservices.go            |  5 ++
 .../topology_validation/topology_validation.go     |  5 +-
 5 files changed, 109 insertions(+), 3 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5245584..d3fd9f1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -73,6 +73,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 - Traffic Portal: upgraded change log UI table to use more powerful/performant ag-grid component
 - Traffic Portal: change log days are now configurable in traffic_portal_properties.json (default is 7 days) and can be overridden by the user in TP
 - [#5319](https://github.com/apache/trafficcontrol/issues/5319) - Added support for building RPMs that target CentOS 8
+- Traffic Ops: Added validation to ensure assigned ORG server cachegroups are in the topology when updating a delivery service
 
 ### Fixed
 - Fixed #5188 - DSR (delivery service request) incorrectly marked as complete and error message not displaying when DSR fulfilled and DS update fails in Traffic Portal. [Related Github issue](https://github.com/apache/trafficcontrol/issues/5188)
diff --git a/traffic_ops/testing/api/v3/deliveryservices_test.go b/traffic_ops/testing/api/v3/deliveryservices_test.go
index 5842990..c51ccf8 100644
--- a/traffic_ops/testing/api/v3/deliveryservices_test.go
+++ b/traffic_ops/testing/api/v3/deliveryservices_test.go
@@ -48,6 +48,7 @@ func TestDeliveryServices(t *testing.T) {
 		GetTestDeliveryServicesIMS(t)
 		GetAccessibleToTest(t)
 		UpdateTestDeliveryServices(t)
+		UpdateValidateORGServerCacheGroup(t)
 		UpdateTestDeliveryServicesWithHeaders(t, header)
 		UpdateNullableTestDeliveryServices(t)
 		UpdateDeliveryServiceWithInvalidRemapText(t)
@@ -880,6 +881,53 @@ func UpdateDeliveryServiceWithInvalidSliceRangeRequest(t *testing.T) {
 
 }
 
+// UpdateValidateORGServerCacheGroup validates ORG server's cachegroup are part of topology's cachegroup
+func UpdateValidateORGServerCacheGroup(t *testing.T) {
+	params := url.Values{}
+	params.Set("xmlId", "ds-top")
+
+	//Get the correct DS
+	remoteDS, _, err := TOSession.GetDeliveryServicesV30WithHdr(nil, params)
+	if err != nil {
+		t.Errorf("cannot GET Delivery Services: %v", err)
+	}
+
+	//Assign ORG server to DS
+	assignServer := []string{"denver-mso-org-01"}
+	_, _, err = TOSession.AssignServersToDeliveryService(assignServer, *remoteDS[0].XMLID)
+	if err != nil {
+		t.Errorf("cannot assign server to Delivery Services: %v", err)
+	}
+
+	//Update DS's Topology to a non-ORG server's cachegroup
+	origTopo := *remoteDS[0].Topology
+	*remoteDS[0].Topology = "4-tiers"
+	ds, reqInf, err := TOSession.UpdateDeliveryServiceV30WithHdr(*remoteDS[0].ID, remoteDS[0], nil)
+	if err == nil {
+		t.Errorf("shouldnot UPDATE DeliveryService by ID: %v, but update was successful", ds.XMLID)
+	}
+	if reqInf.StatusCode != http.StatusBadRequest {
+		t.Fatalf("expected to fail since ORG server's topology not part of DS. Expected:%v, Got: :%v", http.StatusBadRequest, reqInf.StatusCode)
+	}
+
+	// Retrieve the DS to check if topology was updated with missing ORG server
+	params.Set("id", strconv.Itoa(*remoteDS[0].ID))
+	apiResp, _, err := TOSession.GetDeliveryServicesV30WithHdr(nil, params)
+	if err != nil {
+		t.Fatalf("cannot GET Delivery Service by ID: %v - %v", *remoteDS[0].XMLID, err)
+	}
+	if len(apiResp) < 1 {
+		t.Fatalf("cannot GET Delivery Service by ID: %v - nil", *remoteDS[0].XMLID)
+	}
+
+	//Set topology back to as it was for further testing
+	remoteDS[0].Topology = &origTopo
+	_, _, err = TOSession.UpdateDeliveryServiceV30WithHdr(*remoteDS[0].ID, remoteDS[0], nil)
+	if err != nil {
+		t.Fatalf("couldn't update topology:%v, %v", *remoteDS[0].Topology, err)
+	}
+}
+
 func GetAccessibleToTest(t *testing.T) {
 	//Every delivery service is associated with the root tenant
 	err := getByTenants(1, len(testData.DeliveryServices))
diff --git a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go
index 53edd6d..09a9e06 100644
--- a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go
+++ b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go
@@ -23,7 +23,6 @@ import (
 	"database/sql"
 	"errors"
 	"fmt"
-	"github.com/jmoiron/sqlx"
 	"net/http"
 	"strconv"
 	"strings"
@@ -32,6 +31,7 @@ import (
 	"github.com/apache/trafficcontrol/lib/go-tc"
 	"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/topology/topology_validation"
 
+	"github.com/jmoiron/sqlx"
 	"github.com/lib/pq"
 )
 
@@ -1090,3 +1090,54 @@ GROUP BY t.name, ds.topology
 	}
 	return dsType, reqCap, topology, true, nil
 }
+
+// CheckOriginServerInCacheGroupTopology checks if a DS has ORG server and if it does, to make sure the cachegroup is part of DS
+func CheckOriginServerInCacheGroupTopology(tx *sql.Tx, dsID int, dsTopology string) (error, error, int) {
+	// get servers and respective cachegroup name that have ORG type in a delivery service
+	q := `
+		SELECT s.host_name, c.name 
+		FROM server s
+			INNER JOIN deliveryservice_server ds ON ds.server = s.id
+			INNER JOIN type t ON t.id = s.type
+			INNER JOIN cachegroup c ON c.id = s.cachegroup
+		WHERE ds.deliveryservice=$1 AND t.name=$2
+	`
+
+	serverName := ""
+	cacheGroupName := ""
+	servers := make(map[string]string)
+	var offendingSCG []string
+	rows, err := tx.Query(q, dsID, tc.OriginTypeName)
+	if err != nil {
+		return nil, fmt.Errorf("querying deliveryservice origin server: %s", err), http.StatusInternalServerError
+	}
+	defer log.Close(rows, "error closing rows")
+	for rows.Next() {
+		if err := rows.Scan(&serverName, &cacheGroupName); err != nil {
+			return nil, fmt.Errorf("querying deliveryservice origin server: %s", err), http.StatusInternalServerError
+		}
+		servers[cacheGroupName] = serverName
+	}
+
+	if len(servers) > 0 {
+		_, cachegroups, sysErr := GetTopologyCachegroups(tx, dsTopology)
+		if sysErr != nil {
+			return nil, fmt.Errorf("validating %s servers in topology: %v", tc.OriginTypeName, sysErr), http.StatusInternalServerError
+		}
+		// put slice values into map
+		topoCachegroups := make(map[string]string)
+		for _, cg := range cachegroups {
+			topoCachegroups[cg] = ""
+		}
+		for cg, s := range servers {
+			_, ok := topoCachegroups[cg]
+			if !ok {
+				offendingSCG = append(offendingSCG, fmt.Sprintf("%s (%s)", cg, s))
+			}
+		}
+	}
+	if len(offendingSCG) > 0 {
+		return errors.New("the following ORG server cachegroups are not in the delivery service's topology (" + dsTopology + "): " + strings.Join(offendingSCG, ", ")), nil, http.StatusBadRequest
+	}
+	return nil, nil, http.StatusOK
+}
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go
index 199058a..eb1bad3 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservices.go
@@ -796,6 +796,11 @@ func updateV30(w http.ResponseWriter, r *http.Request, inf *api.APIInfo, ds *tc.
 				return nil, status, userErr, sysErr
 			}
 		}
+
+		userErr, sysErr, status := dbhelpers.CheckOriginServerInCacheGroupTopology(tx, *ds.ID, *ds.Topology)
+		if userErr != nil || sysErr != nil {
+			return nil, status, userErr, sysErr
+		}
 	}
 
 	resultRows, err := tx.Query(updateDSQuery(),
diff --git a/traffic_ops/traffic_ops_golang/topology/topology_validation/topology_validation.go b/traffic_ops/traffic_ops_golang/topology/topology_validation/topology_validation.go
index e91f9e7..de19198 100644
--- a/traffic_ops/traffic_ops_golang/topology/topology_validation/topology_validation.go
+++ b/traffic_ops/traffic_ops_golang/topology/topology_validation/topology_validation.go
@@ -25,11 +25,12 @@ package topology_validation
 import (
 	"errors"
 	"fmt"
-	"github.com/jmoiron/sqlx"
-	"github.com/lib/pq"
 	"strings"
 
 	"github.com/apache/trafficcontrol/lib/go-log"
+
+	"github.com/jmoiron/sqlx"
+	"github.com/lib/pq"
 )
 
 // CheckForEmptyCacheGroups checks if the cachegroups are empty (altogether) or empty in any of the given CDN IDs.