From 928200182581f68770397ab8a916de68f2eb80a9 Mon Sep 17 00:00:00 2001 From: Zach Hoffman Date: Mon, 10 Oct 2022 09:10:15 -0600 Subject: [PATCH 1/3] Divide MaxOriginConnections over a Server's own Cache Group if DS Regional field is set --- lib/go-atscfg/headerrewritedotconfig.go | 10 +- lib/go-atscfg/headerrewritedotconfig_test.go | 232 +++++++++++++++++++ lib/go-util/ptr.go | 4 + lib/go-util/ptr_test.go | 6 + 4 files changed, 250 insertions(+), 2 deletions(-) diff --git a/lib/go-atscfg/headerrewritedotconfig.go b/lib/go-atscfg/headerrewritedotconfig.go index 7cadd0bd06..83cf556578 100644 --- a/lib/go-atscfg/headerrewritedotconfig.go +++ b/lib/go-atscfg/headerrewritedotconfig.go @@ -297,7 +297,7 @@ func getAssignedTierPeers( dsRequiredCapabilities map[ServerCapability]struct{}, ) ([]Server, []string) { if ds.Topology != nil { - return getTopologyTierServers(dsRequiredCapabilities, tc.CacheGroupName(*server.Cachegroup), topology, cacheGroups, servers, serverCapabilities) + return getTopologyTierServers(ds, dsRequiredCapabilities, tc.CacheGroupName(*server.Cachegroup), topology, cacheGroups, servers, serverCapabilities) } if serverIsMid(server) { return getAssignedMids(server, ds, servers, deliveryServiceServers, cacheGroups) @@ -390,6 +390,9 @@ func getAssignedMids( if tc.CacheStatus(*sv.Status) != tc.CacheStatusReported && tc.CacheStatus(*sv.Status) != tc.CacheStatusOnline { continue } + if ds != nil && ds.Regional && *sv.Cachegroup != *server.Cachegroup { + continue + } serverCGs[tc.CacheGroupName(*sv.Cachegroup)] = struct{}{} } @@ -434,7 +437,7 @@ func getAssignedMids( // This should only be used for DSes with Topologies. // It returns all servers in with the Capabilities of ds in the same tier as cg. // Returns the servers, and any warnings. -func getTopologyTierServers(dsRequiredCapabilities map[ServerCapability]struct{}, cg tc.CacheGroupName, topology tc.Topology, cacheGroups []tc.CacheGroupNullable, servers []Server, serverCapabilities map[int]map[ServerCapability]struct{}) ([]Server, []string) { +func getTopologyTierServers(ds *DeliveryService, dsRequiredCapabilities map[ServerCapability]struct{}, cg tc.CacheGroupName, topology tc.Topology, cacheGroups []tc.CacheGroupNullable, servers []Server, serverCapabilities map[int]map[ServerCapability]struct{}) ([]Server, []string) { warnings := []string{} topoServers := []Server{} cacheGroupsInSameTier := getCachegroupsInSameTopologyTier(string(cg), cacheGroups, topology) @@ -453,6 +456,9 @@ func getTopologyTierServers(dsRequiredCapabilities map[ServerCapability]struct{} if !hasRequiredCapabilities(serverCapabilities[*sv.ID], dsRequiredCapabilities) { continue } + if ds != nil && ds.Regional && *sv.Cachegroup != string(cg) { + continue + } topoServers = append(topoServers, sv) } return topoServers, warnings diff --git a/lib/go-atscfg/headerrewritedotconfig_test.go b/lib/go-atscfg/headerrewritedotconfig_test.go index 4c98d7300b..c63d23280c 100644 --- a/lib/go-atscfg/headerrewritedotconfig_test.go +++ b/lib/go-atscfg/headerrewritedotconfig_test.go @@ -364,6 +364,238 @@ func TestGetCachegroupsInSameTopologyTier(t *testing.T) { } } +func TestGetTopologyTierServers(t *testing.T) { + allCachegroups := []tc.CacheGroupNullable{ + { + Name: util.StrPtr("edge1"), + Type: util.StrPtr(tc.CacheGroupEdgeTypeName), + }, + { + Name: util.StrPtr("edge2"), + Type: util.StrPtr(tc.CacheGroupEdgeTypeName), + }, + { + Name: util.StrPtr("org1"), + Type: util.StrPtr(tc.CacheGroupOriginTypeName), + }, + } + + allServers := []Server{ + { + Cachegroup: util.Ptr("edge1"), + HostName: util.Ptr("edgeCache1"), + ID: util.Ptr(0), + }, + { + Cachegroup: util.Ptr("edge2"), + HostName: util.Ptr("edgeCache2"), + ID: util.Ptr(0), + }, + } + + topology := tc.Topology{ + Nodes: []tc.TopologyNode{ + { + Cachegroup: "edge1", + Parents: []int{2}, + }, + { + Cachegroup: "edge2", + Parents: []int{2}, + }, + { + Cachegroup: "org1", + }, + }, + } + + type testCase struct { + ds *DeliveryService + dsRequiredCapabilities map[ServerCapability]struct{} + cg tc.CacheGroupName + topology tc.Topology + cacheGroups []tc.CacheGroupNullable + servers []Server + serverCapabilities map[int]map[ServerCapability]struct{} + + expectedHostnames []string + } + testCases := []testCase{ + { + ds: &DeliveryService{}, + cg: tc.CacheGroupName("edge1"), + topology: topology, + cacheGroups: allCachegroups, + servers: allServers, + + expectedHostnames: []string{"edgeCache1", "edgeCache2"}, + }, + { + ds: &DeliveryService{Regional: true}, + cg: tc.CacheGroupName("edge1"), + topology: topology, + cacheGroups: allCachegroups, + servers: allServers, + + expectedHostnames: []string{"edgeCache1"}, + }, + } + + for _, tc := range testCases { + actualServers, _ := getTopologyTierServers(tc.ds, tc.dsRequiredCapabilities, tc.cg, tc.topology, tc.cacheGroups, tc.servers, tc.serverCapabilities) + actualHostnames := []string{} + for _, as := range actualServers { + actualHostnames = append(actualHostnames, *as.HostName) + } + if !reflect.DeepEqual(tc.expectedHostnames, actualHostnames) { + t.Errorf("getting servers in same topology tier -- expected: %v, actual: %v", tc.expectedHostnames, actualHostnames) + } + } +} + +func TestGetAssignedMids(t *testing.T) { + allCachegroups := []tc.CacheGroupNullable{ + { + Name: util.StrPtr("edge1"), + ParentName: util.Ptr("mid1"), + Type: util.StrPtr(tc.CacheGroupEdgeTypeName), + }, + { + Name: util.StrPtr("edge2"), + ParentName: util.Ptr("mid2"), + Type: util.StrPtr(tc.CacheGroupEdgeTypeName), + }, + { + Name: util.StrPtr("mid1"), + ParentName: util.Ptr("org1"), + Type: util.StrPtr(tc.CacheGroupMidTypeName), + }, + { + Name: util.StrPtr("mid2"), + ParentName: util.Ptr("org1"), + Type: util.StrPtr(tc.CacheGroupMidTypeName), + }, + { + Name: util.StrPtr("org1"), + Type: util.StrPtr(tc.CacheGroupOriginTypeName), + }, + } + + allServers := []Server{ + { + Cachegroup: util.Ptr("edge1"), + CDNName: util.Ptr("mycdn"), + HostName: util.Ptr("edgeCache1"), + ID: util.Ptr(1), + Status: util.Ptr(string(tc.CacheStatusReported)), + }, + { + Cachegroup: util.Ptr("edge2"), + CDNName: util.Ptr("mycdn"), + HostName: util.Ptr("edgeCache2"), + ID: util.Ptr(2), + Status: util.Ptr(string(tc.CacheStatusReported)), + }, + + { + Cachegroup: util.Ptr("mid1"), + CDNName: util.Ptr("mycdn"), + HostName: util.Ptr("midCache1"), + ID: util.Ptr(3), + Status: util.Ptr(string(tc.CacheStatusReported)), + }, + { + Cachegroup: util.Ptr("mid2"), + CDNName: util.Ptr("mycdn"), + HostName: util.Ptr("midCache2"), + ID: util.Ptr(4), + Status: util.Ptr(string(tc.CacheStatusReported)), + }, + } + + allDeliveryServices := []DeliveryService{{}, {}} + allDeliveryServices[0].ID = util.Ptr(1) + allDeliveryServices[0].CDNName = util.Ptr("mycdn") + allDeliveryServices[1].ID = util.Ptr(2) + allDeliveryServices[1].Regional = true + allDeliveryServices[1].CDNName = util.Ptr("mycdn") + + type testCase struct { + server *Server + ds *DeliveryService + deliveryServiceServers []DeliveryServiceServer + servers []Server + cacheGroups []tc.CacheGroupNullable + + expectedHostnames []string + } + testCases := []testCase{ + { + server: &allServers[0], + ds: &allDeliveryServices[0], + servers: allServers, + deliveryServiceServers: []DeliveryServiceServer{ + { + Server: 1, + DeliveryService: 1, + }, + { + Server: 2, + DeliveryService: 1, + }, + { + Server: 3, + DeliveryService: 1, + }, + { + Server: 4, + DeliveryService: 1, + }, + }, + cacheGroups: allCachegroups, + + expectedHostnames: []string{"midCache1", "midCache2"}, + }, + { + server: &allServers[0], + ds: &allDeliveryServices[1], + servers: allServers, + deliveryServiceServers: []DeliveryServiceServer{ + { + Server: 1, + DeliveryService: 2, + }, + { + Server: 2, + DeliveryService: 2, + }, + { + Server: 3, + DeliveryService: 2, + }, + { + Server: 4, + DeliveryService: 2, + }, + }, + cacheGroups: allCachegroups, + + expectedHostnames: []string{"midCache1"}, + }, + } + + for _, tc := range testCases { + actualServers, _ := getAssignedMids(tc.server, tc.ds, tc.servers, tc.deliveryServiceServers, tc.cacheGroups) + actualHostnames := []string{} + for _, as := range actualServers { + actualHostnames = append(actualHostnames, *as.HostName) + } + if !reflect.DeepEqual(tc.expectedHostnames, actualHostnames) { + t.Errorf("getting servers in same topology tier -- expected: %v, actual: %v", tc.expectedHostnames, actualHostnames) + } + } +} + func TestMakeHeaderRewriteMidDotConfig(t *testing.T) { cdnName := "mycdn" hdr := "myHeaderComment" diff --git a/lib/go-util/ptr.go b/lib/go-util/ptr.go index e25ecbc85b..6b33346d41 100644 --- a/lib/go-util/ptr.go +++ b/lib/go-util/ptr.go @@ -21,6 +21,10 @@ package util import "time" +func Ptr[T any](v T) *T { + return &v +} + func StrPtr(str string) *string { return &str } diff --git a/lib/go-util/ptr_test.go b/lib/go-util/ptr_test.go index 95a27cc0f3..2cc769919d 100644 --- a/lib/go-util/ptr_test.go +++ b/lib/go-util/ptr_test.go @@ -21,6 +21,12 @@ package util import "fmt" +func ExamplePtr() { + ptr := Ptr("testquest") + fmt.Println(*ptr) + // Output: testquest +} + func ExampleStrPtr() { ptr := StrPtr("testquest") fmt.Println(*ptr) From 89dcfbe72bde4103967b160c862ca0d6bec30d0c Mon Sep 17 00:00:00 2001 From: Zach Hoffman Date: Wed, 12 Oct 2022 14:52:07 -0600 Subject: [PATCH 2/3] Reword error message --- lib/go-atscfg/headerrewritedotconfig_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/go-atscfg/headerrewritedotconfig_test.go b/lib/go-atscfg/headerrewritedotconfig_test.go index c63d23280c..4cc362d9ab 100644 --- a/lib/go-atscfg/headerrewritedotconfig_test.go +++ b/lib/go-atscfg/headerrewritedotconfig_test.go @@ -591,7 +591,7 @@ func TestGetAssignedMids(t *testing.T) { actualHostnames = append(actualHostnames, *as.HostName) } if !reflect.DeepEqual(tc.expectedHostnames, actualHostnames) { - t.Errorf("getting servers in same topology tier -- expected: %v, actual: %v", tc.expectedHostnames, actualHostnames) + t.Errorf("getting servers in same cachegroup tier -- expected: %v, actual: %v", tc.expectedHostnames, actualHostnames) } } } From d1d9d46c6a9a829e1f79b7ab0e44fa3befdf68a2 Mon Sep 17 00:00:00 2001 From: Zach Hoffman Date: Fri, 14 Oct 2022 10:50:35 -0600 Subject: [PATCH 3/3] Changelog entry --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca73bdd74a..9e715b5653 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - [#6021](https://github.com/apache/trafficcontrol/issues/6021) *Traffic Portal* Added the ability to view a change logs message in it's entirety by clicking on it. - [#6033](https://github.com/apache/trafficcontrol/issues/6033) *Traffic Ops, Traffic Portal* Added ability to assign multiple server capabilities to a server. - [#7032](https://github.com/apache/trafficcontrol/issues/7032) *Cache Config* Add t3c-apply flag to use local ATS version for config generation rather than Server package Parameter, to allow managing the ATS OS package via external tools. See 'man t3c-apply' and 'man t3c-generate' for details. -- [#7097](https://github.com/apache/trafficcontrol/issues/7097) *Traffic Ops, Traffic Portal* Added the `regional` field to Delivery Services, which indicates whether `maxOriginConnections` should be per Cache Group +- [#7097](https://github.com/apache/trafficcontrol/issues/7097) *Traffic Ops, Traffic Portal, t3c* Added the `regional` field to Delivery Services, which affects whether `maxOriginConnections` should be per Cache Group ### Changed - [#7063](https://github.com/apache/trafficcontrol/pull/7063) *Traffic Ops* Python client now uses Traffic Ops API 4.1 by default.