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 2021/04/26 23:43:50 UTC

[trafficcontrol] branch 5.1.x updated (924138d -> 48a6398)

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

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


    from 924138d  Ensure that 5.x TS is not logging all 0's for cache_stats, when linked with a 5.x TM/TO (#5714)
     new 00916fb  Return legacy Monitoring Config from legacy Monitoring Config handler (#5755)
     new d1b3487  Fix ORT adding remap lines for DSes not on Mids (#5713)
     new 737f777  TM UI - Sort Delivery Service States (#5745)
     new 47b68cd  Fixes an issue where multiple interfaces reported by a cache are included in the vitals (bandwidth) (#5730)
     new 48a6398  Fixed TM to report ONLINE caches as available (#5776)

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 CHANGELOG.md                                |   4 +
 lib/go-atscfg/remapdotconfig.go             |   3 +-
 lib/go-atscfg/remapdotconfig_test.go        | 143 ++++++++++++
 lib/go-tc/nullable_test.go                  |   1 +
 lib/go-tc/traffic_monitor.go                |  47 +++-
 traffic_monitor/datareq/cachestate.go       |  15 ++
 traffic_monitor/health/cache.go             |  37 +++-
 traffic_monitor/health/cache_test.go        | 329 ++++++++++++++++++++++++++--
 traffic_monitor/manager/monitorconfig.go    |   2 +-
 traffic_monitor/static/script.js            |   5 +-
 traffic_ops/testing/api/v1/crconfig_test.go |  83 ++++++-
 traffic_ops/testing/api/v1/tc-fixtures.json |  36 +--
 traffic_ops/testing/api/v2/crconfig_test.go |  83 ++++++-
 traffic_ops/testing/api/v2/tc-fixtures.json |  36 +--
 traffic_ops/testing/api/v3/crconfig_test.go |  81 +++++++
 traffic_ops/testing/api/v3/tc-fixtures.json |  36 +--
 16 files changed, 870 insertions(+), 71 deletions(-)

[trafficcontrol] 04/05: Fixes an issue where multiple interfaces reported by a cache are included in the vitals (bandwidth) (#5730)

Posted by oc...@apache.org.
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

commit 47b68cd4c2ad6ac7699661a1b5e7ba8053a357a6
Author: Taylor Clayton Frey <ta...@gmail.com>
AuthorDate: Thu Apr 15 17:10:20 2021 -0600

    Fixes an issue where multiple interfaces reported by a cache are included in the vitals (bandwidth) (#5730)
    
    * Normalizing README.md for MacOS case insensitive discrepancies
    
    * Removed whitespace at end of line
    
    * Only use monitored interfaces for vitals
    
    Per bug report #5695, any and all interfaces returned in polling
    were used to calculate vitals, such as bytes in or out, bandwidth
    and more. However, only designated interfaces should be used for
    calculating such metrics and vitals. As such, this commit will
    check for monitored interfaces and only use those for the calculations.
    
    * Normalized README.md file
    
    * Normalized README file
    
    * Add bugfix info to CHANGELOG
    
    * Check monitor config for nil
    
    Ensure callers for GetVitals must include a valid config
    and the config should contain interfaces
    
    * Fix merge issue with CHANGELOG
    
    * Address PR feedback.
    
    Remove extra blank line from CHANGELOG
    Condense test structs for sake of clarity
    Change log levels to reflect actual logging issues
    Add logging clarity to missing or empty caches and interfaces
    
    Co-authored-by: Taylor Frey <ta...@comcast.com>
    (cherry picked from commit 89669fd67428cabe3a6450480a6ff22853e53b19)
---
 CHANGELOG.md                         |   2 +
 traffic_monitor/health/cache.go      |  37 +++-
 traffic_monitor/health/cache_test.go | 329 +++++++++++++++++++++++++++++++++--
 3 files changed, 351 insertions(+), 17 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 60b4fa0..267275a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 - Fixed ORT being unable to update URLSIG keys for Delivery Services
 - Fixed an issue where Traffic Ops becoming unavailable caused Traffic Monitor to segfault and crash
 - [#5754](https://github.com/apache/trafficcontrol/issues/5754) - Ensure Health Threshold Parameters use legacy format for legacy Monitoring Config handler
+- [#5695](https://github.com/apache/trafficcontrol/issues/5695) - Ensure vitals are calculated only against monitored interfaces
+
 - [#5744](https://github.com/apache/trafficcontrol/issues/5744) - Sort TM Delivery Service States page by DS name
 
 ## [5.1.1] - 2021-03-19
diff --git a/traffic_monitor/health/cache.go b/traffic_monitor/health/cache.go
index 899187f..efcab8f 100644
--- a/traffic_monitor/health/cache.go
+++ b/traffic_monitor/health/cache.go
@@ -53,6 +53,11 @@ func GetVitals(newResult *cache.Result, prevResult *cache.Result, mc *tc.Traffic
 		return
 	}
 
+	if mc == nil {
+		log.Errorf("TrafficMonitorConfigMap must not be nil")
+		return
+	}
+
 	if newResult.InterfaceVitals == nil {
 		newResult.InterfaceVitals = map[string]cache.Vitals{}
 	}
@@ -60,7 +65,37 @@ func GetVitals(newResult *cache.Result, prevResult *cache.Result, mc *tc.Traffic
 	// proc.loadavg -- we're using the 1 minute average (!?)
 	newResult.Vitals.LoadAvg = newResult.Statistics.Loadavg.One
 
-	for ifaceName, iface := range newResult.Interfaces() {
+	ts, exists := mc.TrafficServer[newResult.ID]
+	if !exists {
+		log.Errorf("cache server not found in config map for cache: %s", newResult.ID)
+		return
+	}
+	if ts.Interfaces == nil {
+		log.Warnf("no interfaces reported in config map for cache: %s", newResult.ID)
+		return
+	}
+
+	var monitoredInterfaces []tc.ServerInterfaceInfo
+	for _, srvrIfaceInfo := range mc.TrafficServer[newResult.ID].Interfaces {
+		if srvrIfaceInfo.Monitor {
+			monitoredInterfaces = append(monitoredInterfaces, srvrIfaceInfo)
+		}
+	}
+
+	if len(monitoredInterfaces) == 0 {
+		log.Warnf("no interfaces selected to be monitored for %v", newResult.ID)
+		return
+	}
+
+	for _, monitoredInterface := range monitoredInterfaces {
+		ifaceName := monitoredInterface.Name
+		iface, exists := newResult.Interfaces()[ifaceName]
+		if !exists {
+			// monitored interface doesn't exist in Result interfaces, skip
+			log.Warnf("monitored interface %v does not exist in cache %v", ifaceName, newResult.ID)
+			continue
+		}
+
 		ifaceVitals := cache.Vitals{
 			BytesIn:    iface.BytesIn,
 			BytesOut:   iface.BytesOut,
diff --git a/traffic_monitor/health/cache_test.go b/traffic_monitor/health/cache_test.go
index 74486e8..f87f744 100644
--- a/traffic_monitor/health/cache_test.go
+++ b/traffic_monitor/health/cache_test.go
@@ -33,9 +33,315 @@ import (
 	"github.com/apache/trafficcontrol/lib/go-tc"
 )
 
+// TestNoMonitoredInterfacesGetVitals assures that GetVitals
+// does not fail even if no interfaces are marked to be monitored
+func TestNoMonitoredInterfacesGetVitals(t *testing.T) {
+	serverID := "no-monitored"
+	fakeRequestTime := time.Now()
+	zeroValueVitals := cache.Vitals{}
+
+	// Interfaces to monitor are marked true (none)
+	tmcm := tc.TrafficMonitorConfigMap{
+		TrafficServer: map[string]tc.TrafficServer{
+			serverID: {
+				Interfaces: []tc.ServerInterfaceInfo{
+					{
+						Name:    "bond0",
+						Monitor: false,
+					},
+					{
+						Name:    "bond1",
+						Monitor: false,
+					},
+					{
+						Name:    "lo",
+						Monitor: false,
+					},
+				},
+			},
+		},
+	}
+
+	// multiple interfaces, plus extra
+	firstResult := cache.Result{
+		ID:            serverID,
+		Error:         nil,
+		Miscellaneous: map[string]interface{}{},
+		Statistics: cache.Statistics{
+			Interfaces: map[string]cache.Interface{
+				"bond0": {
+					Speed:    100000,
+					BytesIn:  570791700709,
+					BytesOut: 4212211168526,
+				},
+				"bond1": {
+					Speed:    100000,
+					BytesIn:  1989352297218,
+					BytesOut: 10630690813,
+				},
+				"lo": {
+					Speed:    0,
+					BytesIn:  181882394,
+					BytesOut: 181882394,
+				},
+				"em5": {
+					Speed:    0,
+					BytesIn:  0,
+					BytesOut: 0,
+				},
+			},
+		},
+		Time:            fakeRequestTime,
+		RequestTime:     time.Second,
+		Vitals:          cache.Vitals{},
+		InterfaceVitals: nil,
+		PollID:          42,
+		PollFinished:    make(chan uint64, 1),
+		PrecomputedData: cache.PrecomputedData{},
+		Available:       true,
+		UsingIPv4:       false,
+	}
+	GetVitals(&firstResult, nil, &tmcm)
+
+	// No interfaces were selected to be monitored so none
+	// should have been added later
+	if len(firstResult.InterfaceVitals) > 0 {
+		t.Errorf("InterfaceVitals map should be empty. expected: %v actual: %v:", 0, len(firstResult.InterfaceVitals))
+	}
+
+	// No interfaces were selected to be monitored so no vitals
+	// should have been calculated
+	if firstResult.Vitals != zeroValueVitals {
+		t.Errorf("Vitals should have zero values. expected: %v actual: %v:", zeroValueVitals, firstResult.Vitals)
+	}
+
+	secondResult := firstResult
+	secondResult.Time = fakeRequestTime.Add(5 * time.Second)
+
+	GetVitals(&secondResult, &firstResult, &tmcm)
+
+	// No interfaces were selected to be monitored so none
+	// should have been added later
+	if len(secondResult.InterfaceVitals) > 0 {
+		t.Errorf("InterfaceVitals map should be empty. expected: %v actual: %v:", 0, len(secondResult.InterfaceVitals))
+	}
+
+	// No interfaces were selected to be monitored so no vitals
+	// should have been calculated
+	if secondResult.Vitals != zeroValueVitals {
+		t.Errorf("Vitals should have zero values. expected: %v actual: %v:", zeroValueVitals, secondResult.Vitals)
+	}
+
+	// The previous results should not have been impacted
+	if firstResult.Vitals != zeroValueVitals {
+		t.Errorf("Vitals should have zero values. expected: %v actual: %v:", zeroValueVitals, firstResult.Vitals)
+	}
+}
+
+// TestDualHomingMonitoredInterfacesGetVitals ensures cache servers
+// with multiple interfaces correctly calculate bandwidth based on
+// whether the interfaces are marked as "Monitor this interface"
+func TestDualHomingMonitoredInterfacesGetVitals(t *testing.T) {
+
+	serverID := "dual-homed"
+	fakeRequestTime := time.Now()
+
+	// Interfaces to monitor are marked true
+	tmcm := tc.TrafficMonitorConfigMap{
+		TrafficServer: map[string]tc.TrafficServer{
+			serverID: {
+				Interfaces: []tc.ServerInterfaceInfo{
+					{
+						Name:    "bond0",
+						Monitor: true,
+					},
+					{
+						Name:    "bond1",
+						Monitor: true,
+					},
+					{
+						Name:    "lo",
+						Monitor: false,
+					},
+				},
+			},
+		},
+	}
+
+	// multiple interfaces, plus extras
+	firstResult := cache.Result{
+		ID:            serverID,
+		Error:         nil,
+		Miscellaneous: map[string]interface{}{},
+		Statistics: cache.Statistics{
+			Interfaces: map[string]cache.Interface{
+				"bond0": {
+					Speed:    100000,
+					BytesIn:  570791700709,
+					BytesOut: 4212211168526,
+				},
+				"bond1": {
+					Speed:    100000,
+					BytesIn:  1989352297218,
+					BytesOut: 10630690813,
+				},
+				"p1p1": {
+					Speed:    100000,
+					BytesIn:  570793589545,
+					BytesOut: 4212220919951,
+				},
+				"p3p1": {
+					Speed:    100000,
+					BytesIn:  1989354450479,
+					BytesOut: 10630690813,
+				},
+				"lo": {
+					Speed:    0,
+					BytesIn:  181882394,
+					BytesOut: 181882394,
+				},
+				"em5": {
+					Speed:    0,
+					BytesIn:  0,
+					BytesOut: 0,
+				},
+				"em6": {
+					Speed:    0,
+					BytesIn:  0,
+					BytesOut: 0,
+				},
+			},
+		},
+		Time:            fakeRequestTime,
+		RequestTime:     time.Second,
+		Vitals:          cache.Vitals{},
+		InterfaceVitals: nil,
+		PollID:          42,
+		PollFinished:    make(chan uint64, 1),
+		PrecomputedData: cache.PrecomputedData{},
+		Available:       true,
+		UsingIPv4:       false,
+	}
+	GetVitals(&firstResult, nil, &tmcm)
+
+	// Two interfaces were selected to be monitored so they
+	// should have been added later
+	if len(firstResult.InterfaceVitals) != 2 {
+		t.Errorf("InterfaceVitals map should not be empty. expected: %v actual: %v:", 2, len(firstResult.InterfaceVitals))
+	}
+
+	expectedFirstVitals := cache.Vitals{
+		LoadAvg:    0,
+		BytesIn:    2560143997927,
+		BytesOut:   4222841859339,
+		KbpsOut:    0,
+		MaxKbpsOut: 200000000,
+	}
+	// Only two interfaces were selected to be monitored so vitals
+	// should have been calculated based on those two (bond0 and bond1)
+	if firstResult.Vitals != expectedFirstVitals {
+		t.Errorf("Vitals do not match expected output. expected: %v actual: %v:", expectedFirstVitals, firstResult.Vitals)
+	}
+
+	secondResult := firstResult
+	secondResult.Statistics.Interfaces = map[string]cache.Interface{
+		"bond0": {
+			Speed:    100000,
+			BytesIn:  572608907987,
+			BytesOut: 4227149141326,
+		},
+		"bond1": {
+			Speed:    100000,
+			BytesIn:  1996376171468,
+			BytesOut: 10630696953,
+		},
+		"p1p1": {
+			Speed:    100000,
+			BytesIn:  572609282353,
+			BytesOut: 4227157881921,
+		},
+		"p3p1": {
+			Speed:    100000,
+			BytesIn:  1996378204692,
+			BytesOut: 10630696953,
+		},
+		"lo": {
+			Speed:    0,
+			BytesIn:  181882394,
+			BytesOut: 181882394,
+		},
+		"em5": {
+			Speed:    0,
+			BytesIn:  0,
+			BytesOut: 0,
+		},
+		"em6": {
+			Speed:    0,
+			BytesIn:  0,
+			BytesOut: 0,
+		},
+	}
+	secondResult.Time = fakeRequestTime.Add(5 * time.Second)
+	secondResult.Vitals = cache.Vitals{}
+
+	GetVitals(&secondResult, &firstResult, &tmcm)
+
+	// Two interfaces were selected to be monitored so they
+	// should have been added later
+	if len(secondResult.InterfaceVitals) != 2 {
+		t.Errorf("InterfaceVitals map should not be empty. expected: %v actual: %v:", 2, len(secondResult.InterfaceVitals))
+	}
+
+	expectedSecondVitals := cache.Vitals{
+		LoadAvg:    0,
+		BytesIn:    2568985079455,
+		BytesOut:   4237779838279,
+		KbpsOut:    23900766,
+		MaxKbpsOut: 200000000,
+	}
+
+	// Only two interfaces were selected to be monitored so vitals
+	// should have been calculated based on those two (bond0 and bond1)
+	if secondResult.Vitals != expectedSecondVitals {
+		t.Errorf("Vitals do not match expected output. expected: %v actual: %v:", expectedSecondVitals, secondResult.Vitals)
+	}
+
+	// Previous result values should have been altered
+	if firstResult.Vitals != expectedFirstVitals {
+		t.Errorf("Vitals do not match expected output. expected: %v actual: %v:", expectedFirstVitals, firstResult.Vitals)
+	}
+}
+
 func TestCalcAvailabilityThresholds(t *testing.T) {
+
+	resultID := "myCacheName"
+
+	mc := tc.TrafficMonitorConfigMap{
+		TrafficServer: map[string]tc.TrafficServer{
+			string(resultID): {
+				ServerStatus: string(tc.CacheStatusReported),
+				Profile:      "myProfileName",
+				Interfaces: []tc.ServerInterfaceInfo{
+					{
+						Name:    "bond0",
+						Monitor: true,
+					},
+					{
+						Name:    "eth0",
+						Monitor: true,
+					},
+					{
+						Name:    "lo",
+						Monitor: false,
+					},
+				},
+			},
+		},
+		Profile: map[string]tc.TMProfile{},
+	}
+
 	result := cache.Result{
-		ID:            "myCacheName",
+		ID:            resultID,
 		Error:         nil,
 		Miscellaneous: map[string]interface{}{},
 		Statistics: cache.Statistics{
@@ -48,12 +354,12 @@ func TestCalcAvailabilityThresholds(t *testing.T) {
 				LatestPID:        32109,
 			},
 			Interfaces: map[string]cache.Interface{
-				"bond0": cache.Interface{
+				"bond0": {
 					Speed:    20000,
 					BytesIn:  1234567891011121,
 					BytesOut: 12345678910111213,
 				},
-				"eth0": cache.Interface{
+				"eth0": {
 					Speed:    30000,
 					BytesIn:  1234567891011121,
 					BytesOut: 12345678910111213,
@@ -71,7 +377,7 @@ func TestCalcAvailabilityThresholds(t *testing.T) {
 		Available:       true,
 		UsingIPv4:       false,
 	}
-	GetVitals(&result, nil, nil)
+	GetVitals(&result, nil, &mc)
 
 	totalBytesOut := result.Statistics.Interfaces["bond0"].BytesOut + result.Statistics.Interfaces["eth0"].BytesOut
 	if totalBytesOut != result.Vitals.BytesOut {
@@ -86,23 +392,13 @@ func TestCalcAvailabilityThresholds(t *testing.T) {
 		Vitals:          cache.Vitals{BytesOut: result.Vitals.BytesOut - 1250000000}, // 10 gigabits
 		InterfaceVitals: prevIV,
 	}
-	GetVitals(&result, &prevResult, nil)
+	GetVitals(&result, &prevResult, &mc)
 
-	statResultHistory := (*threadsafe.ResultStatHistory)(nil)
-	mc := tc.TrafficMonitorConfigMap{
-		TrafficServer: map[string]tc.TrafficServer{
-			string(result.ID): {
-				ServerStatus: string(tc.CacheStatusReported),
-				Profile:      "myProfileName",
-			},
-		},
-		Profile: map[string]tc.TMProfile{},
-	}
 	mc.Profile[mc.TrafficServer[string(result.ID)].Profile] = tc.TMProfile{
 		Name: mc.TrafficServer[string(result.ID)].Profile,
 		Parameters: tc.TMParameters{
 			Thresholds: map[string]tc.HealthThreshold{
-				"availableBandwidthInKbps": tc.HealthThreshold{
+				"availableBandwidthInKbps": {
 					Val:        15000000,
 					Comparator: ">",
 				},
@@ -130,6 +426,7 @@ func TestCalcAvailabilityThresholds(t *testing.T) {
 
 	// Ensure that if the interfaces haven't been reported yet that CalcAvailability doesn't panic
 	original := results[0].Statistics.Interfaces
+	statResultHistory := (*threadsafe.ResultStatHistory)(nil)
 	results[0].Statistics.Interfaces = make(map[string]cache.Interface)
 	CalcAvailability(results, pollerName, statResultHistory, mc, toData, localCacheStatusThreadsafe, localStates, events, config.Both)
 	results[0].Statistics.Interfaces = original

[trafficcontrol] 02/05: Fix ORT adding remap lines for DSes not on Mids (#5713)

Posted by oc...@apache.org.
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

commit d1b3487551ead61e1ee1153da0d89d1029f86baf
Author: Robert O Butts <ro...@users.noreply.github.com>
AuthorDate: Mon Apr 5 14:07:31 2021 -0600

    Fix ORT adding remap lines for DSes not on Mids (#5713)
    
    Bug was ORT Mid remap gen not using the new lib/go-tc DSType
    UsesMidCache func, but having old code checking live and natnl,
    which ended up with HTTP_NO_CACHE generating remap lines on Mids.
    
    This could particularly cause issues because the hdr_rw_mid_ file
    generation did use ds.Type.UsesMidCache, potentially resulting
    in a remap line with a file that didn't exist, causing ATS to fail
    to load.
    
    This could be mitigated by creating a locatin Param for the file,
    to force it to be created.
    
    Note this did not affect Topologies, which use their own criteria
    for both header rewrite file and remap line generation.
    
    (cherry picked from commit 4b85e933f0ff402f4813ddbe8efd9b13e19743d3)
---
 lib/go-atscfg/remapdotconfig.go      |   3 +-
 lib/go-atscfg/remapdotconfig_test.go | 143 +++++++++++++++++++++++++++++++++++
 2 files changed, 145 insertions(+), 1 deletion(-)

diff --git a/lib/go-atscfg/remapdotconfig.go b/lib/go-atscfg/remapdotconfig.go
index e5ca856..3ad3af1 100644
--- a/lib/go-atscfg/remapdotconfig.go
+++ b/lib/go-atscfg/remapdotconfig.go
@@ -137,7 +137,8 @@ func getServerConfigRemapDotConfigForMid(
 				continue
 			}
 		}
-		if ds.Type.IsLive() && !ds.Type.IsNational() && !hasTopology {
+
+		if !ds.Type.UsesMidCache() && (!hasTopology || *ds.Topology == "") {
 			continue // Live local delivery services skip mids (except Topologies ignore DS types)
 		}
 
diff --git a/lib/go-atscfg/remapdotconfig_test.go b/lib/go-atscfg/remapdotconfig_test.go
index 8b1c60c..e054ad5 100644
--- a/lib/go-atscfg/remapdotconfig_test.go
+++ b/lib/go-atscfg/remapdotconfig_test.go
@@ -8267,3 +8267,146 @@ func makeTestRemapServer() *Server {
 	server.Type = "MID"
 	return server
 }
+
+func TestMakeRemapDotConfigMidNoNoCacheRemapLine(t *testing.T) {
+	hdr := "myHeaderComment"
+
+	server := makeTestRemapServer()
+	server.Type = "MID"
+
+	ds := DeliveryService{}
+	ds.ID = util.IntPtr(48)
+	dsType := tc.DSType("HTTP_NO_CACHE")
+	ds.Type = &dsType
+	ds.OrgServerFQDN = util.StrPtr("origin.example.test")
+	ds.RangeRequestHandling = util.IntPtr(tc.RangeRequestHandlingCacheRangeRequest)
+	ds.RemapText = util.StrPtr("@plugin=tslua.so @pparam=my-range-manipulator.lua")
+	ds.SigningAlgorithm = util.StrPtr("foo")
+	ds.XMLID = util.StrPtr("mydsname")
+	ds.QStringIgnore = util.IntPtr(int(tc.QueryStringIgnoreIgnoreInCacheKeyAndPassUp))
+	ds.RegexRemap = util.StrPtr("")
+	ds.FQPacingRate = util.IntPtr(314159)
+	ds.DSCP = util.IntPtr(0)
+	ds.RoutingName = util.StrPtr("myroutingname")
+	ds.MultiSiteOrigin = util.BoolPtr(false)
+	ds.OriginShield = util.StrPtr("myoriginshield")
+	ds.ProfileID = util.IntPtr(49)
+	ds.ProfileName = util.StrPtr("dsprofile")
+	ds.Protocol = util.IntPtr(int(tc.DSProtocolHTTPToHTTPS))
+	ds.AnonymousBlockingEnabled = util.BoolPtr(false)
+	ds.Active = util.BoolPtr(true)
+
+	// non-nil default values should not trigger header rewrite plugin directive
+	ds.EdgeHeaderRewrite = util.StrPtr("")
+	ds.MidHeaderRewrite = util.StrPtr("mid-header-rewrite")
+	ds.ServiceCategory = util.StrPtr("")
+	ds.MaxOriginConnections = util.IntPtr(0)
+
+	dses := []DeliveryService{ds}
+
+	dss := []tc.DeliveryServiceServer{
+		tc.DeliveryServiceServer{
+			Server:          util.IntPtr(*server.ID),
+			DeliveryService: util.IntPtr(*ds.ID),
+		},
+	}
+
+	dsRegexes := []tc.DeliveryServiceRegexes{
+		tc.DeliveryServiceRegexes{
+			DSName: *ds.XMLID,
+			Regexes: []tc.DeliveryServiceRegex{
+				tc.DeliveryServiceRegex{
+					Type:      string(tc.DSMatchTypeHostRegex),
+					SetNumber: 0,
+					Pattern:   `.*\.mypattern\..*`,
+				},
+			},
+		},
+	}
+
+	serverParams := []tc.Parameter{
+		tc.Parameter{
+			Name:       "trafficserver",
+			ConfigFile: "package",
+			Value:      "7",
+			Profiles:   []byte(`["global"]`),
+		},
+		tc.Parameter{
+			Name:       "serverpkgval",
+			ConfigFile: "package",
+			Value:      "serverpkgval __HOSTNAME__ foo",
+			Profiles:   []byte(*server.Profile),
+		},
+		tc.Parameter{
+			Name:       "dscp_remap_no",
+			ConfigFile: "package",
+			Value:      "notused",
+			Profiles:   []byte(*server.Profile),
+		},
+	}
+
+	cacheKeyParams := []tc.Parameter{
+		tc.Parameter{
+			Name:       "cachekeykey",
+			ConfigFile: "cacheurl.config",
+			Value:      "cachekeyval",
+			Profiles:   []byte(`["dsprofile"]`),
+		},
+		tc.Parameter{
+			Name:       "shouldnotexist",
+			ConfigFile: "cacheurl.config",
+			Value:      "shouldnotexisteither",
+			Profiles:   []byte(`["not-dsprofile"]`),
+		},
+		tc.Parameter{
+			Name:       "cachekeykey",
+			ConfigFile: "cacheurl.config",
+			Value:      "cachekeyval",
+			Profiles:   []byte(`["global"]`),
+		},
+		tc.Parameter{
+			Name:       "not_location",
+			ConfigFile: "cacheurl.config",
+			Value:      "notinconfig",
+			Profiles:   []byte(`["global"]`),
+		},
+		tc.Parameter{
+			Name:       "not_location",
+			ConfigFile: "cachekey.config",
+			Value:      "notinconfig",
+			Profiles:   []byte(`["global"]`),
+		},
+	}
+
+	cdn := &tc.CDN{
+		DomainName: "cdndomain.example",
+		Name:       "my-cdn-name",
+	}
+
+	topologies := []tc.Topology{}
+	cgs := []tc.CacheGroupNullable{}
+	serverCapabilities := map[int]map[ServerCapability]struct{}{}
+	dsRequiredCapabilities := map[int]map[ServerCapability]struct{}{}
+
+	cfg, err := MakeRemapDotConfig(server, dses, dss, dsRegexes, serverParams, cdn, cacheKeyParams, topologies, cgs, serverCapabilities, dsRequiredCapabilities, hdr)
+	if err != nil {
+		t.Fatal(err)
+	}
+	txt := cfg.Text
+
+	txt = strings.TrimSpace(txt)
+
+	testComment(t, txt, hdr)
+
+	txtLines := strings.Split(txt, "\n")
+
+	if len(txtLines) != 1 {
+		t.Fatalf("expected 0 remaps from HTTP_NO_CACHE DS on Mid, actual: '%v' count %v", txt, len(txtLines))
+	}
+
+	remapLine := txtLines[0]
+
+	if strings.Contains(remapLine, "hdr_rw_mid_mydsname.config") {
+		t.Errorf("expected remap line for HTTP_NO_CACHE to not exist on Mid server, regardless of Mid Header Rewrite, actual '%v'", txt)
+	}
+}

[trafficcontrol] 03/05: TM UI - Sort Delivery Service States (#5745)

Posted by oc...@apache.org.
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

commit 737f777f0298342c6ee326e8b691cd5895261994
Author: Steve Hamrick <sh...@users.noreply.github.com>
AuthorDate: Wed Apr 14 10:35:42 2021 -0600

    TM UI - Sort Delivery Service States (#5745)
    
    * Sort Delivery Services
    
    * Add changelog
    
    (cherry picked from commit 47ca424625ba8f1cbc3a8357f33e9ad73dcde897)
---
 CHANGELOG.md                     | 1 +
 traffic_monitor/static/script.js | 5 ++++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index f0a94c8..60b4fa0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 - Fixed ORT being unable to update URLSIG keys for Delivery Services
 - Fixed an issue where Traffic Ops becoming unavailable caused Traffic Monitor to segfault and crash
 - [#5754](https://github.com/apache/trafficcontrol/issues/5754) - Ensure Health Threshold Parameters use legacy format for legacy Monitoring Config handler
+- [#5744](https://github.com/apache/trafficcontrol/issues/5744) - Sort TM Delivery Service States page by DS name
 
 ## [5.1.1] - 2021-03-19
 ### Added
diff --git a/traffic_monitor/static/script.js b/traffic_monitor/static/script.js
index f2511c4..ac86a5c 100644
--- a/traffic_monitor/static/script.js
+++ b/traffic_monitor/static/script.js
@@ -313,7 +313,10 @@ function getDSProperty(ds, prop) {
 function getDsStats() {
 	/// \todo add /api/delivery-service-stats which only returns the data needed by the UI, for efficiency
 	ajax("/publish/DsStats", function(r) {
-		const deliveryServices = new Map(Object.entries(JSON.parse(r).deliveryService));
+		const deliveryServices = new Map(Object.entries(JSON.parse(r).deliveryService).sort((dsTupleA, dsTupleB) => {
+			return -1 * dsTupleA[0].localeCompare(dsTupleB[0]);
+		}));
+
 		const table = document.createElement('TBODY');
 		table.id = "deliveryservice-stats";
 

[trafficcontrol] 01/05: Return legacy Monitoring Config from legacy Monitoring Config handler (#5755)

Posted by oc...@apache.org.
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

commit 00916fb690c5aee9a946f3bd7928c8feabe5abbe
Author: Zach Hoffman <zr...@apache.org>
AuthorDate: Fri Apr 23 12:43:02 2021 -0600

    Return legacy Monitoring Config from legacy Monitoring Config handler (#5755)
    
    * Set Health Threshold Parameters when converting to legacy Traffic Monitor Config
    
    * Make tc.strToThreshold() visibile
    
    * Return legacy Monitoring Config from legacy Monitoring Config handler
    
    * Remove duplicate parameters
    
    * Remove SnapshotGetMonitoringLegacyHandler()
    
    * Remove "Legacy" from logging
    
    * Copy new API tests to API v3 and API v4
    
    * Revert "Remove SnapshotGetMonitoringLegacyHandler()"
    
    * Revert crconfig.SnapshotGetMonitoringLegacyHandler() changes
    
    * Add godocs
    
    * Check the length of profiles, not cdns
    
    * Remove redundant condition
    
    * gofmt
    
    (cherry picked from commit a233b14a9a72c80f855c2b91ee88b71a783c49d0)
---
 CHANGELOG.md                                |  1 +
 lib/go-tc/nullable_test.go                  |  1 +
 lib/go-tc/traffic_monitor.go                | 47 ++++++++++++++--
 traffic_ops/testing/api/v1/crconfig_test.go | 83 ++++++++++++++++++++++++++++-
 traffic_ops/testing/api/v1/tc-fixtures.json | 36 +++++++------
 traffic_ops/testing/api/v2/crconfig_test.go | 83 ++++++++++++++++++++++++++++-
 traffic_ops/testing/api/v2/tc-fixtures.json | 36 +++++++------
 traffic_ops/testing/api/v3/crconfig_test.go | 81 ++++++++++++++++++++++++++++
 traffic_ops/testing/api/v3/tc-fixtures.json | 36 +++++++------
 9 files changed, 353 insertions(+), 51 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d5759f5..f0a94c8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 - [#5712](https://github.com/apache/trafficcontrol/issues/5712) - Ensure that 5.x Traffic Stats is compatible with 5.x Traffic Monitor and 5.x Traffic Ops, and that it doesn't log all 0's for `cache_stats`
 - Fixed ORT being unable to update URLSIG keys for Delivery Services
 - Fixed an issue where Traffic Ops becoming unavailable caused Traffic Monitor to segfault and crash
+- [#5754](https://github.com/apache/trafficcontrol/issues/5754) - Ensure Health Threshold Parameters use legacy format for legacy Monitoring Config handler
 
 ## [5.1.1] - 2021-03-19
 ### Added
diff --git a/lib/go-tc/nullable_test.go b/lib/go-tc/nullable_test.go
index 9c0fcdf..442bc8e 100644
--- a/lib/go-tc/nullable_test.go
+++ b/lib/go-tc/nullable_test.go
@@ -2,6 +2,7 @@
 // skip this unless specifically testing for nullable vs non-nullable struct comparison
 
 // Run as `go test -tags nullable`
+//go:build nullable
 // +build nullable
 
 package tc
diff --git a/lib/go-tc/traffic_monitor.go b/lib/go-tc/traffic_monitor.go
index 6f7f1b2..e4b7d09 100644
--- a/lib/go-tc/traffic_monitor.go
+++ b/lib/go-tc/traffic_monitor.go
@@ -80,6 +80,10 @@ type TrafficMonitorConfig struct {
 	Profiles []TMProfile `json:"profiles,omitempty"`
 }
 
+const healthThresholdAvailableBandwidthInKbps = "availableBandwidthInKbps"
+const healthThresholdLoadAverage = "loadavg"
+const healthThresholdQueryTime = "queryTime"
+
 // ToLegacyConfig converts TrafficMonitorConfig to LegacyTrafficMonitorConfig.
 func (tmc *TrafficMonitorConfig) ToLegacyConfig() LegacyTrafficMonitorConfig {
 	var servers []LegacyTrafficServer
@@ -87,6 +91,23 @@ func (tmc *TrafficMonitorConfig) ToLegacyConfig() LegacyTrafficMonitorConfig {
 		servers = append(servers, s.ToLegacyServer())
 	}
 
+	for profileIndex, profile := range tmc.Profiles {
+		thresholds := profile.Parameters.Thresholds
+		if _, exists := thresholds[healthThresholdAvailableBandwidthInKbps]; exists {
+			tmc.Profiles[profileIndex].Parameters.AvailableBandwidthInKbps = thresholds[healthThresholdAvailableBandwidthInKbps].String()
+			delete(tmc.Profiles[profileIndex].Parameters.Thresholds, healthThresholdAvailableBandwidthInKbps)
+		}
+		if _, exists := thresholds[healthThresholdLoadAverage]; exists {
+			tmc.Profiles[profileIndex].Parameters.LoadAverage = thresholds[healthThresholdLoadAverage].String()
+			delete(tmc.Profiles[profileIndex].Parameters.Thresholds, healthThresholdLoadAverage)
+		}
+		if _, exists := thresholds[healthThresholdQueryTime]; exists {
+			//tmc.Profiles[profileIndex].Parameters.QueryTime = int(thresholds[healthThresholdQueryTime].Val)
+			tmc.Profiles[profileIndex].Parameters.QueryTime = thresholds[healthThresholdQueryTime].String()
+			delete(tmc.Profiles[profileIndex].Parameters.Thresholds, healthThresholdQueryTime)
+		}
+	}
+
 	legacy := LegacyTrafficMonitorConfig{
 		CacheGroups:      tmc.CacheGroups,
 		Config:           tmc.Config,
@@ -426,7 +447,25 @@ type TMParameters struct {
 	HealthPollingType       string `json:"health.polling.type"`
 	HistoryCount            int    `json:"history.count"`
 	MinFreeKbps             int64
-	Thresholds              map[string]HealthThreshold `json:"health_threshold"`
+	// HealthThresholdJSONParameters contains the Parameters contained in the
+	// Thresholds field, formatted as individual string Parameters, rather than as
+	// a JSON object.
+	Thresholds map[string]HealthThreshold `json:"health_threshold,omitempty"`
+	HealthThresholdJSONParameters
+}
+
+// HealthThresholdJSONParameters contains Parameters whose Thresholds must be met in order for
+// Caches using the Profile containing these Parameters to be marked as Healthy.
+type HealthThresholdJSONParameters struct {
+	// AvailableBandwidthInKbps is The total amount of bandwidth that servers using this profile are
+	// allowed, in Kilobits per second. This is a string and using comparison operators to specify
+	// ranges, e.g. ">10" means "more than 10 kbps".
+	AvailableBandwidthInKbps string `json:"health.threshold.availableBandwidthInKbps,omitempty"`
+	// LoadAverage is the UNIX loadavg at which the server should be marked "unhealthy".
+	LoadAverage string `json:"health.threshold.loadavg,omitempty"`
+	// QueryTime is the highest allowed length of time for completing health queries (after
+	// connection has been established) in milliseconds.
+	QueryTime string `json:"health.threshold.queryTime,omitempty"`
 }
 
 const DefaultHealthThresholdComparator = "<"
@@ -446,11 +485,11 @@ func (t HealthThreshold) String() string {
 	return fmt.Sprintf("%s%f", t.Comparator, t.Val)
 }
 
-// strToThreshold takes a string like ">=42" and returns a HealthThreshold with
+// StrToThreshold takes a string like ">=42" and returns a HealthThreshold with
 // a Val of `42` and a Comparator of `">="`. If no comparator exists,
 // `DefaultHealthThresholdComparator` is used. If the string does not match
 // "(>|<|)(=|)\d+" an error is returned.
-func strToThreshold(s string) (HealthThreshold, error) {
+func StrToThreshold(s string) (HealthThreshold, error) {
 	// The order of these is important - don't re-order without considering the
 	// consequences.
 	comparators := []string{">=", "<=", ">", "<", "="}
@@ -523,7 +562,7 @@ func (params *TMParameters) UnmarshalJSON(bytes []byte) (err error) {
 		if strings.HasPrefix(k, ThresholdPrefix) {
 			stat := k[len(ThresholdPrefix):]
 			vStr := fmt.Sprintf("%v", v) // allows string or numeric JSON types. TODO check if a type switch is faster.
-			if t, err := strToThreshold(vStr); err != nil {
+			if t, err := StrToThreshold(vStr); err != nil {
 				return fmt.Errorf("Unmarshalling TMParameters `%s` parameter value not of the form `(>|)(=|)\\d+`: stat '%s' value '%v': %v", ThresholdPrefix, k, v, err)
 			} else {
 				params.Thresholds[stat] = t
diff --git a/traffic_ops/testing/api/v1/crconfig_test.go b/traffic_ops/testing/api/v1/crconfig_test.go
index e02a0c8..d964029 100644
--- a/traffic_ops/testing/api/v1/crconfig_test.go
+++ b/traffic_ops/testing/api/v1/crconfig_test.go
@@ -26,6 +26,7 @@ import (
 func TestCRConfig(t *testing.T) {
 	WithObjs(t, []TCObj{CDNs, Types, Tenants, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, DeliveryServices}, func() {
 		UpdateTestCRConfigSnapshot(t)
+		MonitoringConfig(t)
 		SnapshotTestCDNbyName(t)
 		SnapshotTestCDNbyInvalidName(t)
 		SnapshotTestCDNbyID(t)
@@ -35,7 +36,7 @@ func TestCRConfig(t *testing.T) {
 
 func UpdateTestCRConfigSnapshot(t *testing.T) {
 	if len(testData.CDNs) < 1 {
-		t.Error("no cdn test data")
+		t.Fatalf("no cdn test data")
 	}
 	cdn := testData.CDNs[0].Name
 
@@ -156,6 +157,86 @@ func UpdateTestCRConfigSnapshot(t *testing.T) {
 	}
 }
 
+func MonitoringConfig(t *testing.T) {
+	if len(testData.CDNs) < 1 {
+		t.Fatalf("no cdn test data")
+	}
+	const cdnName = "cdn1"
+	const profileName = "EDGE1"
+	cdns, _, err := TOSession.GetCDNByName(cdnName)
+	if err != nil {
+		t.Fatalf("getting CDNs with name '%s': %s", cdnName, err.Error())
+	}
+	if len(cdns) < 1 {
+		t.Fatalf("expected to find a CDN named %s", cdnName)
+	}
+	if len(cdns) > 1 {
+		t.Fatalf("expected exactly 1 CDN named %s but found %d CDNs", cdnName, len(cdns))
+	}
+	profiles, _, err := TOSession.GetProfileByName(profileName)
+	if err != nil {
+		t.Fatalf("getting Profiles with name '%s': %s", profileName, err.Error())
+	}
+	if len(profiles) != 1 {
+		t.Fatalf("expected exactly 1 Profiles named %s but found %d Profiles", profileName, len(profiles))
+	}
+	parameters, _, err := TOSession.GetParametersByProfileName(profileName)
+	if err != nil {
+		t.Fatalf("getting Parameters by Profile name '%s': %s", profileName, err.Error())
+	}
+	parameterMap := map[string]tc.HealthThreshold{}
+	parameterFound := map[string]bool{}
+	const thresholdPrefixLength = len(tc.ThresholdPrefix)
+	for _, parameter := range parameters {
+		if !strings.HasPrefix(parameter.Name, tc.ThresholdPrefix) {
+			continue
+		}
+		parameterName := parameter.Name[thresholdPrefixLength:]
+		parameterMap[parameterName], err = tc.StrToThreshold(parameter.Value)
+		if err != nil {
+			t.Fatalf("converting string '%s' to HealthThreshold: %s", parameter.Value, err.Error())
+		}
+		parameterFound[parameterName] = false
+	}
+	const expectedThresholdParameters = 3
+	if len(parameterMap) != expectedThresholdParameters {
+		t.Fatalf("expected Profile '%s' to contain %d Parameters with names starting with '%s' but %d such Parameters were found", profileName, expectedThresholdParameters, tc.ThresholdPrefix, len(parameterMap))
+	}
+	tmConfig, _, err := TOSession.GetTrafficMonitorConfig(cdnName)
+	if err != nil {
+		t.Fatalf("getting Traffic Monitor Config: %s", err.Error())
+	}
+	profileFound := false
+	var profile tc.TMProfile
+	for _, profile = range tmConfig.Profiles {
+		if profile.Name == profileName {
+			profileFound = true
+			break
+		}
+	}
+	if !profileFound {
+		t.Fatalf("Traffic Monitor Config contained no Profile named '%s", profileName)
+	}
+	for parameterName, value := range profile.Parameters.Thresholds {
+		if _, ok := parameterFound[parameterName]; !ok {
+			t.Fatalf("unexpected Threshold Parameter name '%s' found in Profile '%s' in Traffic Monitor Config", parameterName, profileName)
+		}
+		parameterFound[parameterName] = true
+		if parameterMap[parameterName].String() != value.String() {
+			t.Fatalf("expected '%s' but received '%s' for Threshold Parameter '%s' in Profile '%s' in Traffic Monitor Config", parameterMap[parameterName].String(), value.String(), parameterName, profileName)
+		}
+	}
+	missingParameters := []string{}
+	for parameterName, found := range parameterFound {
+		if !found {
+			missingParameters = append(missingParameters, parameterName)
+		}
+	}
+	if len(missingParameters) != 0 {
+		t.Fatalf("Threshold parameters defined for Profile '%s' but missing for Profile '%s' in Traffic Monitor Config: %s", profileName, profileName, strings.Join(missingParameters, ", "))
+	}
+}
+
 func SnapshotTestCDNbyName(t *testing.T) {
 
 	firstCDN := testData.CDNs[0]
diff --git a/traffic_ops/testing/api/v1/tc-fixtures.json b/traffic_ops/testing/api/v1/tc-fixtures.json
index 20af859..1c45592 100644
--- a/traffic_ops/testing/api/v1/tc-fixtures.json
+++ b/traffic_ops/testing/api/v1/tc-fixtures.json
@@ -794,20 +794,6 @@
     "parameters": [
         {
             "configFile": "rascal.properties",
-            "lastUpdated": "2018-01-19T19:01:21.455131+00:00",
-            "name": "health.threshold.loadavg",
-            "secure": false,
-            "value": "25.0"
-        },
-        {
-            "configFile": "rascal.properties",
-            "lastUpdated": "2018-01-19T19:01:21.472279+00:00",
-            "name": "health.threshold.availableBandwidthInKbps",
-            "secure": false,
-            "value": ">1750000"
-        },
-        {
-            "configFile": "rascal.properties",
             "lastUpdated": "2018-01-19T19:01:21.489534+00:00",
             "name": "history.count",
             "secure": false,
@@ -1363,7 +1349,27 @@
             "lastUpdated": "2018-03-02T17:27:11.818418+00:00",
             "name": "EDGE1",
             "routing_disabled": false,
-            "type": "ATS_PROFILE"
+            "type": "ATS_PROFILE",
+            "params": [
+                {
+                    "configFile": "rascal.properties",
+                    "name": "health.threshold.loadavg",
+                    "secure": false,
+                    "value": "25.0"
+                },
+                {
+                    "configFile": "rascal.properties",
+                    "name": "health.threshold.availableBandwidthInKbps",
+                    "secure": false,
+                    "value": ">1750000"
+                },
+                {
+                    "configFile": "rascal.properties",
+                    "name": "health.threshold.queryTime",
+                    "secure": false,
+                    "value": "1000"
+                }
+            ]
         },
         {
             "cdnName": "cdn2",
diff --git a/traffic_ops/testing/api/v2/crconfig_test.go b/traffic_ops/testing/api/v2/crconfig_test.go
index c5d2c57..ab9dae5 100644
--- a/traffic_ops/testing/api/v2/crconfig_test.go
+++ b/traffic_ops/testing/api/v2/crconfig_test.go
@@ -26,6 +26,7 @@ import (
 func TestCRConfig(t *testing.T) {
 	WithObjs(t, []TCObj{CDNs, Types, Tenants, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, DeliveryServices}, func() {
 		UpdateTestCRConfigSnapshot(t)
+		MonitoringConfig(t)
 		SnapshotTestCDNbyName(t)
 		SnapshotTestCDNbyInvalidName(t)
 		SnapshotTestCDNbyID(t)
@@ -35,7 +36,7 @@ func TestCRConfig(t *testing.T) {
 
 func UpdateTestCRConfigSnapshot(t *testing.T) {
 	if len(testData.CDNs) < 1 {
-		t.Error("no cdn test data")
+		t.Fatalf("no cdn test data")
 	}
 	cdn := testData.CDNs[0].Name
 
@@ -156,6 +157,86 @@ func UpdateTestCRConfigSnapshot(t *testing.T) {
 	}
 }
 
+func MonitoringConfig(t *testing.T) {
+	if len(testData.CDNs) < 1 {
+		t.Fatalf("no cdn test data")
+	}
+	const cdnName = "cdn1"
+	const profileName = "EDGE1"
+	cdns, _, err := TOSession.GetCDNByName(cdnName)
+	if err != nil {
+		t.Fatalf("getting CDNs with name '%s': %s", cdnName, err.Error())
+	}
+	if len(cdns) < 1 {
+		t.Fatalf("expected to find a CDN named %s", cdnName)
+	}
+	if len(cdns) > 1 {
+		t.Fatalf("expected exactly 1 CDN named %s but found %d CDNs", cdnName, len(cdns))
+	}
+	profiles, _, err := TOSession.GetProfileByName(profileName)
+	if err != nil {
+		t.Fatalf("getting Profiles with name '%s': %s", profileName, err.Error())
+	}
+	if len(profiles) != 1 {
+		t.Fatalf("expected exactly 1 Profiles named %s but found %d Profiles", profileName, len(profiles))
+	}
+	parameters, _, err := TOSession.GetParametersByProfileName(profileName)
+	if err != nil {
+		t.Fatalf("getting Parameters by Profile name '%s': %s", profileName, err.Error())
+	}
+	parameterMap := map[string]tc.HealthThreshold{}
+	parameterFound := map[string]bool{}
+	const thresholdPrefixLength = len(tc.ThresholdPrefix)
+	for _, parameter := range parameters {
+		if !strings.HasPrefix(parameter.Name, tc.ThresholdPrefix) {
+			continue
+		}
+		parameterName := parameter.Name[thresholdPrefixLength:]
+		parameterMap[parameterName], err = tc.StrToThreshold(parameter.Value)
+		if err != nil {
+			t.Fatalf("converting string '%s' to HealthThreshold: %s", parameter.Value, err.Error())
+		}
+		parameterFound[parameterName] = false
+	}
+	const expectedThresholdParameters = 3
+	if len(parameterMap) != expectedThresholdParameters {
+		t.Fatalf("expected Profile '%s' to contain %d Parameters with names starting with '%s' but %d such Parameters were found", profileName, expectedThresholdParameters, tc.ThresholdPrefix, len(parameterMap))
+	}
+	tmConfig, _, err := TOSession.GetTrafficMonitorConfig(cdnName)
+	if err != nil {
+		t.Fatalf("getting Traffic Monitor Config: %s", err.Error())
+	}
+	profileFound := false
+	var profile tc.TMProfile
+	for _, profile = range tmConfig.Profiles {
+		if profile.Name == profileName {
+			profileFound = true
+			break
+		}
+	}
+	if !profileFound {
+		t.Fatalf("Traffic Monitor Config contained no Profile named '%s", profileName)
+	}
+	for parameterName, value := range profile.Parameters.Thresholds {
+		if _, ok := parameterFound[parameterName]; !ok {
+			t.Fatalf("unexpected Threshold Parameter name '%s' found in Profile '%s' in Traffic Monitor Config", parameterName, profileName)
+		}
+		parameterFound[parameterName] = true
+		if parameterMap[parameterName].String() != value.String() {
+			t.Fatalf("expected '%s' but received '%s' for Threshold Parameter '%s' in Profile '%s' in Traffic Monitor Config", parameterMap[parameterName].String(), value.String(), parameterName, profileName)
+		}
+	}
+	missingParameters := []string{}
+	for parameterName, found := range parameterFound {
+		if !found {
+			missingParameters = append(missingParameters, parameterName)
+		}
+	}
+	if len(missingParameters) != 0 {
+		t.Fatalf("Threshold parameters defined for Profile '%s' but missing for Profile '%s' in Traffic Monitor Config: %s", profileName, profileName, strings.Join(missingParameters, ", "))
+	}
+}
+
 func SnapshotTestCDNbyName(t *testing.T) {
 
 	firstCDN := testData.CDNs[0]
diff --git a/traffic_ops/testing/api/v2/tc-fixtures.json b/traffic_ops/testing/api/v2/tc-fixtures.json
index e8046de..cb5e1ac 100644
--- a/traffic_ops/testing/api/v2/tc-fixtures.json
+++ b/traffic_ops/testing/api/v2/tc-fixtures.json
@@ -825,20 +825,6 @@
     "parameters": [
         {
             "configFile": "rascal.properties",
-            "lastUpdated": "2018-01-19T19:01:21.455131+00:00",
-            "name": "health.threshold.loadavg",
-            "secure": false,
-            "value": "25.0"
-        },
-        {
-            "configFile": "rascal.properties",
-            "lastUpdated": "2018-01-19T19:01:21.472279+00:00",
-            "name": "health.threshold.availableBandwidthInKbps",
-            "secure": false,
-            "value": ">1750000"
-        },
-        {
-            "configFile": "rascal.properties",
             "lastUpdated": "2018-01-19T19:01:21.489534+00:00",
             "name": "history.count",
             "secure": false,
@@ -1387,7 +1373,27 @@
             "lastUpdated": "2018-03-02T17:27:11.818418+00:00",
             "name": "EDGE1",
             "routing_disabled": false,
-            "type": "ATS_PROFILE"
+            "type": "ATS_PROFILE",
+            "params": [
+                {
+                    "configFile": "rascal.properties",
+                    "name": "health.threshold.loadavg",
+                    "secure": false,
+                    "value": "25.0"
+                },
+                {
+                    "configFile": "rascal.properties",
+                    "name": "health.threshold.availableBandwidthInKbps",
+                    "secure": false,
+                    "value": ">1750000"
+                },
+                {
+                    "configFile": "rascal.properties",
+                    "name": "health.threshold.queryTime",
+                    "secure": false,
+                    "value": "1000"
+                }
+            ]
         },
         {
             "cdnName": "cdn2",
diff --git a/traffic_ops/testing/api/v3/crconfig_test.go b/traffic_ops/testing/api/v3/crconfig_test.go
index 1a651f7..b3db34c 100644
--- a/traffic_ops/testing/api/v3/crconfig_test.go
+++ b/traffic_ops/testing/api/v3/crconfig_test.go
@@ -26,6 +26,7 @@ import (
 func TestCRConfig(t *testing.T) {
 	WithObjs(t, []TCObj{CDNs, Types, Tenants, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, Topologies, DeliveryServices}, func() {
 		UpdateTestCRConfigSnapshot(t)
+		MonitoringConfig(t)
 		SnapshotTestCDNbyName(t)
 		SnapshotTestCDNbyInvalidName(t)
 		SnapshotTestCDNbyID(t)
@@ -157,6 +158,86 @@ func UpdateTestCRConfigSnapshot(t *testing.T) {
 	}
 }
 
+func MonitoringConfig(t *testing.T) {
+	if len(testData.CDNs) < 1 {
+		t.Fatalf("no cdn test data")
+	}
+	const cdnName = "cdn1"
+	const profileName = "EDGE1"
+	cdns, _, err := TOSession.GetCDNByNameWithHdr(cdnName, nil)
+	if err != nil {
+		t.Fatalf("getting CDNs with name '%s': %s", cdnName, err.Error())
+	}
+	if len(cdns) < 1 {
+		t.Fatalf("expected to find a CDN named %s", cdnName)
+	}
+	if len(cdns) > 1 {
+		t.Fatalf("expected exactly 1 CDN named %s but found %d CDNs", cdnName, len(cdns))
+	}
+	profiles, _, err := TOSession.GetProfileByNameWithHdr(profileName, nil)
+	if err != nil {
+		t.Fatalf("getting Profiles with name '%s': %s", profileName, err.Error())
+	}
+	if len(profiles) != 1 {
+		t.Fatalf("expected exactly 1 Profiles named %s but found %d Profiles", profileName, len(profiles))
+	}
+	parameters, _, err := TOSession.GetParametersByProfileNameWithHdr(profileName, nil)
+	if err != nil {
+		t.Fatalf("getting Parameters by Profile name '%s': %s", profileName, err.Error())
+	}
+	parameterMap := map[string]tc.HealthThreshold{}
+	parameterFound := map[string]bool{}
+	const thresholdPrefixLength = len(tc.ThresholdPrefix)
+	for _, parameter := range parameters {
+		if !strings.HasPrefix(parameter.Name, tc.ThresholdPrefix) {
+			continue
+		}
+		parameterName := parameter.Name[thresholdPrefixLength:]
+		parameterMap[parameterName], err = tc.StrToThreshold(parameter.Value)
+		if err != nil {
+			t.Fatalf("converting string '%s' to HealthThreshold: %s", parameter.Value, err.Error())
+		}
+		parameterFound[parameterName] = false
+	}
+	const expectedThresholdParameters = 3
+	if len(parameterMap) != expectedThresholdParameters {
+		t.Fatalf("expected Profile '%s' to contain %d Parameters with names starting with '%s' but %d such Parameters were found", profileName, expectedThresholdParameters, tc.ThresholdPrefix, len(parameterMap))
+	}
+	tmConfig, _, err := TOSession.GetTrafficMonitorConfig(cdnName)
+	if err != nil {
+		t.Fatalf("getting Traffic Monitor Config: %s", err.Error())
+	}
+	profileFound := false
+	var profile tc.TMProfile
+	for _, profile = range tmConfig.Profiles {
+		if profile.Name == profileName {
+			profileFound = true
+			break
+		}
+	}
+	if !profileFound {
+		t.Fatalf("Traffic Monitor Config contained no Profile named '%s", profileName)
+	}
+	for parameterName, value := range profile.Parameters.Thresholds {
+		if _, ok := parameterFound[parameterName]; !ok {
+			t.Fatalf("unexpected Threshold Parameter name '%s' found in Profile '%s' in Traffic Monitor Config", parameterName, profileName)
+		}
+		parameterFound[parameterName] = true
+		if parameterMap[parameterName].String() != value.String() {
+			t.Fatalf("expected '%s' but received '%s' for Threshold Parameter '%s' in Profile '%s' in Traffic Monitor Config", parameterMap[parameterName].String(), value.String(), parameterName, profileName)
+		}
+	}
+	missingParameters := []string{}
+	for parameterName, found := range parameterFound {
+		if !found {
+			missingParameters = append(missingParameters, parameterName)
+		}
+	}
+	if len(missingParameters) != 0 {
+		t.Fatalf("Threshold parameters defined for Profile '%s' but missing for Profile '%s' in Traffic Monitor Config: %s", profileName, profileName, strings.Join(missingParameters, ", "))
+	}
+}
+
 func SnapshotTestCDNbyName(t *testing.T) {
 
 	firstCDN := testData.CDNs[0]
diff --git a/traffic_ops/testing/api/v3/tc-fixtures.json b/traffic_ops/testing/api/v3/tc-fixtures.json
index bb24c57..10c2d0f 100644
--- a/traffic_ops/testing/api/v3/tc-fixtures.json
+++ b/traffic_ops/testing/api/v3/tc-fixtures.json
@@ -1668,20 +1668,6 @@
     "parameters": [
         {
             "configFile": "rascal.properties",
-            "lastUpdated": "2018-01-19T19:01:21.455131+00:00",
-            "name": "health.threshold.loadavg",
-            "secure": false,
-            "value": "25.0"
-        },
-        {
-            "configFile": "rascal.properties",
-            "lastUpdated": "2018-01-19T19:01:21.472279+00:00",
-            "name": "health.threshold.availableBandwidthInKbps",
-            "secure": false,
-            "value": ">1750000"
-        },
-        {
-            "configFile": "rascal.properties",
             "lastUpdated": "2018-01-19T19:01:21.489534+00:00",
             "name": "history.count",
             "secure": false,
@@ -2248,7 +2234,27 @@
             "lastUpdated": "2018-03-02T17:27:11.818418+00:00",
             "name": "EDGE1",
             "routing_disabled": false,
-            "type": "ATS_PROFILE"
+            "type": "ATS_PROFILE",
+            "params": [
+                {
+                    "configFile": "rascal.properties",
+                    "name": "health.threshold.loadavg",
+                    "secure": false,
+                    "value": "25.0"
+                },
+                {
+                    "configFile": "rascal.properties",
+                    "name": "health.threshold.availableBandwidthInKbps",
+                    "secure": false,
+                    "value": ">1750000"
+                },
+                {
+                    "configFile": "rascal.properties",
+                    "name": "health.threshold.queryTime",
+                    "secure": false,
+                    "value": "1000"
+                }
+            ]
         },
         {
             "cdnName": "cdn2",

[trafficcontrol] 05/05: Fixed TM to report ONLINE caches as available (#5776)

Posted by oc...@apache.org.
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

commit 48a63985da651bdfd6b090d951f3d95f747aa495
Author: mattjackson220 <33...@users.noreply.github.com>
AuthorDate: Thu Apr 22 10:17:20 2021 -0600

    Fixed TM to report ONLINE caches as available (#5776)
    
    (cherry picked from commit 6ba291470cc18ed86b79921ce28a41af594b3770)
---
 CHANGELOG.md                             |  2 +-
 traffic_monitor/datareq/cachestate.go    | 15 +++++++++++++++
 traffic_monitor/manager/monitorconfig.go |  2 +-
 3 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 267275a..a14594a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,7 +11,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 - Fixed an issue where Traffic Ops becoming unavailable caused Traffic Monitor to segfault and crash
 - [#5754](https://github.com/apache/trafficcontrol/issues/5754) - Ensure Health Threshold Parameters use legacy format for legacy Monitoring Config handler
 - [#5695](https://github.com/apache/trafficcontrol/issues/5695) - Ensure vitals are calculated only against monitored interfaces
-
+- Fixed Traffic Monitor to report `ONLINE` caches as available.
 - [#5744](https://github.com/apache/trafficcontrol/issues/5744) - Sort TM Delivery Service States page by DS name
 
 ## [5.1.1] - 2021-03-19
diff --git a/traffic_monitor/datareq/cachestate.go b/traffic_monitor/datareq/cachestate.go
index 4597e2e..2482744 100644
--- a/traffic_monitor/datareq/cachestate.go
+++ b/traffic_monitor/datareq/cachestate.go
@@ -38,6 +38,9 @@ import (
 // the polled interface data.
 const NotFoundStatus = "unavailable - interface not found"
 
+// OnlineStatus is the status value of all interfaces that are associated with an ONLINE server.
+const OnlineStatus = "available - server ONLINE"
+
 // CacheStatus contains summary stat data about the given cache.
 type CacheStatus struct {
 	Type        *string  `json:"type,omitempty"`
@@ -183,6 +186,11 @@ func createCacheStatuses(
 				}
 			}
 
+			if serverInfo.ServerStatus == tc.CacheStatusOnline.String() {
+				infStatus.Status = OnlineStatus
+				infStatus.Available = true
+			}
+
 			interfaceStatuses[interfaceName] = infStatus
 		}
 
@@ -235,6 +243,13 @@ func createCacheStatuses(
 			log.Infof("Error getting cache %v health span: %v\n", cacheName, err)
 		}
 
+		if serverInfo.ServerStatus == tc.CacheStatusOnline.String() {
+			cacheStatus.Why = "ONLINE - available"
+			cacheStatus.Available.IPv4 = serverInfo.IPv4() != ""
+			cacheStatus.Available.IPv6 = serverInfo.IPv6() != ""
+			cacheStatus.ProcessedAvailable = cacheStatus.Available.IPv4 || cacheStatus.Available.IPv6
+		}
+
 		statii[cacheName] = CacheStatus{
 			Type:                   &cacheTypeStr,
 			LoadAverage:            &loadAverage,
diff --git a/traffic_monitor/manager/monitorconfig.go b/traffic_monitor/manager/monitorconfig.go
index 4f44042..719720c 100644
--- a/traffic_monitor/manager/monitorconfig.go
+++ b/traffic_monitor/manager/monitorconfig.go
@@ -240,7 +240,7 @@ func monitorConfigListen(
 
 			srvStatus := tc.CacheStatusFromString(srv.ServerStatus)
 			if srvStatus == tc.CacheStatusOnline {
-				localStates.AddCache(cacheName, tc.IsAvailable{IsAvailable: true})
+				localStates.AddCache(cacheName, tc.IsAvailable{IsAvailable: true, Ipv6Available: srv.IPv6() != "", Ipv4Available: srv.IPv4() != ""})
 				continue
 			}
 			if srvStatus == tc.CacheStatusOffline {