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

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


The following commit(s) were added to refs/heads/master by this push:
     new f039b78cd2 `api/{{version}/deliveryservices/{id}/health` returns no 
info if the delivery service uses a topology (#6827)
f039b78cd2 is described below

commit f039b78cd2328f36b0314ca00bd06d31cf5ee8f3
Author: Srijeet Chatterjee <[email protected]>
AuthorDate: Mon May 23 15:52:36 2022 -0600

    `api/{{version}/deliveryservices/{id}/health` returns no info if the 
delivery service uses a topology (#6827)
    
    * initial changes
    
    * add tests. changelog
    
    * code review fixes
    
    * return error as last param
---
 CHANGELOG.md                                       |   1 +
 .../traffic_ops_golang/deliveryservice/health.go   |  59 +++++++--
 .../deliveryservice/health_test.go                 | 136 +++++++++++++++++++++
 3 files changed, 189 insertions(+), 7 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index da7fc76b6a..6ee6b7c859 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -31,6 +31,7 @@ The format is based on [Keep a 
Changelog](http://keepachangelog.com/en/1.0.0/).
 - Fixed Traffic Ops ignoring the configured database port value, which was 
prohibiting the use of anything other than port 5432 (the PostgreSQL default)
 - [#6580](https://github.com/apache/trafficcontrol/issues/6580) Fixed cache 
config generation remap.config targets for MID-type servers in a Topology with 
other caches as parents and HTTPS origins.
 - Traffic Router: fixed a null pointer exception that caused snapshots to be 
rejected if a topology cachegroup did not have any online/reported/admin\_down 
caches
+- [#6271](https://github.com/apache/trafficcontrol/issues/6271) 
`api/{{version}/deliveryservices/{id}/health` returns no info if the delivery 
service uses a topology.
 - [#6549](https://github.com/apache/trafficcontrol/issues/6549) Fixed internal 
server error while deleting a delivery service created from a DSR (Traafic Ops).
 - [#6538](https://github.com/apache/trafficcontrol/pull/6538) Fixed the 
incorrect use of secure.port on TrafficRouter and corrected to the httpsPort 
value from the TR server configuration.
 - [#6562](https://github.com/apache/trafficcontrol/pull/6562) Fixed incorrect 
template in Ansible dataset loader role when fallbackToClosest is defined.
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/health.go 
b/traffic_ops/traffic_ops_golang/deliveryservice/health.go
index c5676fc730..73c235519d 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/health.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/health.go
@@ -22,6 +22,7 @@ package deliveryservice
 import (
        "database/sql"
        "errors"
+       "fmt"
        "net/http"
        "strings"
 
@@ -102,8 +103,11 @@ func getMonitorHealth(tx *sql.Tx, ds 
tc.DeliveryServiceName, monitorFQDNs []stri
                        errs = append(errs, errors.New("getting CRConfig for 
delivery service '"+string(ds)+"' monitor '"+monitorFQDN+"': "+err.Error()))
                        continue
                }
-               cgData, totalOnline, totalOffline = addHealth(ds, cgData, 
totalOnline, totalOffline, crStates, crConfig)
-
+               cgData, totalOnline, totalOffline, err = addHealth(ds, cgData, 
totalOnline, totalOffline, crStates, crConfig)
+               if err != nil {
+                       errs = append(errs, err)
+                       continue
+               }
                healthData := tc.HealthData{TotalOffline: totalOffline, 
TotalOnline: totalOnline, CacheGroups: []tc.HealthDataCacheGroup{}}
                for _, health := range cgData {
                        healthData.CacheGroups = append(healthData.CacheGroups, 
health)
@@ -114,14 +118,38 @@ func getMonitorHealth(tx *sql.Tx, ds 
tc.DeliveryServiceName, monitorFQDNs []stri
 }
 
 // addHealth adds the given cache states to the given data and totals, and 
returns the new data and totals
-func addHealth(ds tc.DeliveryServiceName, data 
map[tc.CacheGroupName]tc.HealthDataCacheGroup, totalOnline uint64, totalOffline 
uint64, crStates tc.CRStates, crConfig tc.CRConfig) 
(map[tc.CacheGroupName]tc.HealthDataCacheGroup, uint64, uint64) {
+func addHealth(ds tc.DeliveryServiceName, data 
map[tc.CacheGroupName]tc.HealthDataCacheGroup, totalOnline uint64, totalOffline 
uint64, crStates tc.CRStates, crConfig tc.CRConfig) 
(map[tc.CacheGroupName]tc.HealthDataCacheGroup, uint64, uint64, error) {
+
+       var deliveryService tc.CRConfigDeliveryService
+       var ok bool
+       var topology string
+       var cacheGroupNameMap = make(map[string]bool)
+       var skip bool
+
+       if deliveryService, ok = crConfig.DeliveryServices[string(ds)]; !ok {
+               return map[tc.CacheGroupName]tc.HealthDataCacheGroup{}, 0, 0, 
errors.New("delivery service not found in CRConfig")
+       }
+       if deliveryService.Topology != nil {
+               var top tc.CRConfigTopology
+               topology = *deliveryService.Topology
+               if topology != "" {
+                       if top, ok = crConfig.Topologies[topology]; !ok {
+                               return 
map[tc.CacheGroupName]tc.HealthDataCacheGroup{}, 0, 0, fmt.Errorf("CRConfig 
topologies does not contain DS topology: %s", topology)
+                       }
+                       for _, n := range top.Nodes {
+                               cacheGroupNameMap[n] = true
+                       }
+               }
+       }
        for cacheName, avail := range crStates.Caches {
                cache, ok := crConfig.ContentServers[string(cacheName)]
                if !ok {
                        continue // TODO warn?
                }
-               if _, ok := cache.DeliveryServices[string(ds)]; !ok {
-                       continue
+               if topology == "" {
+                       if _, ok := cache.DeliveryServices[string(ds)]; !ok {
+                               continue
+                       }
                }
                if cache.ServerStatus == nil || *cache.ServerStatus != 
tc.CRConfigServerStatus(tc.CacheStatusReported) {
                        continue
@@ -132,7 +160,24 @@ func addHealth(ds tc.DeliveryServiceName, data 
map[tc.CacheGroupName]tc.HealthDa
                if cache.CacheGroup == nil {
                        continue // TODO warn?
                }
-
+               if topology != "" {
+                       if _, ok := cacheGroupNameMap[*cache.CacheGroup]; !ok {
+                               continue
+                       }
+                       cacheCapabilities := make(map[string]struct{}, 
len(cache.Capabilities))
+                       for _, cap := range cache.Capabilities {
+                               cacheCapabilities[cap] = struct{}{}
+                       }
+                       for _, rc := range deliveryService.RequiredCapabilities 
{
+                               if _, ok = cacheCapabilities[rc]; !ok {
+                                       skip = true
+                                       break
+                               }
+                       }
+                       if skip {
+                               continue
+                       }
+               }
                cgHealth := data[tc.CacheGroupName(*cache.CacheGroup)]
                cgHealth.Name = tc.CacheGroupName(*cache.CacheGroup)
                if avail.IsAvailable {
@@ -144,5 +189,5 @@ func addHealth(ds tc.DeliveryServiceName, data 
map[tc.CacheGroupName]tc.HealthDa
                }
                data[tc.CacheGroupName(*cache.CacheGroup)] = cgHealth
        }
-       return data, totalOnline, totalOffline
+       return data, totalOnline, totalOffline, nil
 }
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/health_test.go 
b/traffic_ops/traffic_ops_golang/deliveryservice/health_test.go
new file mode 100644
index 0000000000..64516e7561
--- /dev/null
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/health_test.go
@@ -0,0 +1,136 @@
+package deliveryservice
+
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+import (
+       "testing"
+       "time"
+
+       "github.com/apache/trafficcontrol/lib/go-tc"
+       "github.com/apache/trafficcontrol/lib/go-util"
+)
+
+func TestAddHealth(t *testing.T) {
+       crStates := tc.CRStates{
+               Caches: map[tc.CacheName]tc.IsAvailable{
+                       "cache1": {
+                               IsAvailable:   true,
+                               Ipv4Available: true,
+                               Ipv6Available: true,
+                               Status:        "REPORTED - available",
+                               LastPoll:      time.Now(),
+                       },
+                       "cache2": {
+                               IsAvailable:   true,
+                               Ipv4Available: true,
+                               Ipv6Available: true,
+                               Status:        "REPORTED - available",
+                               LastPoll:      time.Now(),
+                       },
+                       "cache3": {
+                               IsAvailable:   true,
+                               Ipv4Available: true,
+                               Ipv6Available: true,
+                               Status:        "REPORTED - available",
+                               LastPoll:      time.Now(),
+                       },
+               },
+               DeliveryService: 
map[tc.DeliveryServiceName]tc.CRStatesDeliveryService{
+                       "ds1": {
+                               DisabledLocations: []tc.CacheGroupName{},
+                               IsAvailable:       true,
+                       },
+                       "ds2-topology": {
+                               DisabledLocations: []tc.CacheGroupName{},
+                               IsAvailable:       true,
+                       },
+               },
+       }
+
+       status := tc.CRConfigServerStatus("REPORTED")
+       crConfig := tc.CRConfig{
+               Config: nil,
+               ContentServers: map[string]tc.CRConfigTrafficOpsServer{
+                       "cache1": {
+                               CacheGroup:   util.StrPtr("cg1"),
+                               Capabilities: []string{"cap1", "cap2"},
+                               ServerStatus: &status,
+                               ServerType:   util.StrPtr("EDGE"),
+                               DeliveryServices: map[string][]string{
+                                       "ds1": {"edge.ds1.test.net"},
+                               },
+                       },
+                       "cache2": {
+                               CacheGroup:   util.StrPtr("cg2"),
+                               Capabilities: []string{"cap2", "cap3"},
+                               ServerStatus: &status,
+                               ServerType:   util.StrPtr("EDGE"),
+                       },
+                       "cache3": {
+                               CacheGroup:   util.StrPtr("cg2"),
+                               Capabilities: []string{"cap3", "cap4"},
+                               ServerStatus: &status,
+                               ServerType:   util.StrPtr("EDGE"),
+                       },
+               },
+               ContentRouters: nil,
+               DeliveryServices: map[string]tc.CRConfigDeliveryService{
+                       "ds1": {},
+                       "ds2-topology": {
+                               Topology:             
util.StrPtr("test_topology"),
+                               RequiredCapabilities: []string{"cap2"},
+                       },
+               },
+               EdgeLocations:   nil,
+               RouterLocations: nil,
+               Monitors:        nil,
+               Stats:           tc.CRConfigStats{},
+               Topologies: map[string]tc.CRConfigTopology{
+                       "test_topology": {Nodes: []string{"cg2"}},
+               },
+       }
+       data := make(map[tc.CacheGroupName]tc.HealthDataCacheGroup)
+       data[tc.CacheGroupName("cache1")] = tc.HealthDataCacheGroup{
+               Offline: 0,
+               Online:  0,
+               Name:    "cg1",
+       }
+       data[tc.CacheGroupName("cache2")] = tc.HealthDataCacheGroup{
+               Offline: 0,
+               Online:  0,
+               Name:    "cg2",
+       }
+       data[tc.CacheGroupName("cache3")] = tc.HealthDataCacheGroup{
+               Offline: 0,
+               Online:  0,
+               Name:    "cg2",
+       }
+       _, available, unAvailable, err := addHealth("ds1", data, 0, 0, 
crStates, crConfig)
+       if err != nil {
+               t.Fatalf("expected no error while adding health of ds1, but got 
%v", err)
+       }
+       if available != 1 || unAvailable != 0 {
+               t.Errorf("expected ds1 to have 1 online and 0 offline caches, 
but got %d online and %d offline instead", available, unAvailable)
+       }
+       // Even though there are 2 REPORTED EDGE caches in cg2, the result 
should just include 1, because one of them should get filtered out because it's 
missing a required capability (cap2)
+       _, available, unAvailable, err = addHealth("ds2-topology", data, 0, 0, 
crStates, crConfig)
+       if err != nil {
+               t.Fatalf("expected no error while adding health of ds2, but got 
%v", err)
+       }
+       if available != 1 || unAvailable != 0 {
+               t.Errorf("expected ds2-topology to have 1 online and 0 offline 
caches, but got %d online and %d offline instead", available, unAvailable)
+       }
+}

Reply via email to