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

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

commit 959f1ed338d2a812ffa0d662bdd42bde5e9a9aaa
Author: John J. Rushford <[email protected]>
AuthorDate: Tue Aug 31 14:46:49 2021 -0600

    Updates to the tm-health-client (#6147)
    
    - fix to ensure marking parents up or down is only done using
       the configured reason code.
     - fixes an issue where available parents reported by TM are
       not marked up when 'enable-active-markdowns' disabled.
     - checks for updates to the config file applying new updates.
     - reloads the available traffic monitors list with a config
       file update.
     - reloads the available traffic monitors list if there are
       any errors encountered when polling a traffic monitor.
     - added a configuration parameter 'tm-update-cycles' to set
       a periodic refresh on the available traffic monitors list.
     - added a util module and renamed tmutil to tmagent
     - refactored unit tests.
    
    (cherry picked from commit 89fdc0e30c1adb4e8b86b4d98fd744d5b5b569f5)
---
 cache-config/tm-health-client/README.md            |  21 +++-
 cache-config/tm-health-client/config/config.go     |  87 ++++++++++----
 .../tm-health-client/config/config_test.go         |  14 ++-
 .../tm-health-client/tm-health-client-logrotate    |   2 +-
 cache-config/tm-health-client/tm-health-client.go  |   4 +-
 .../tm-health-client/tm-health-client.json         |   3 +-
 .../{tmutil => tmagent}/test_files/bin/traffic_ctl |   0
 .../test_files/etc/parent.config                   |   0
 .../test_files/etc/strategies.yaml                 |   0
 .../test_files/tm-health-client.json               |   0
 .../{tmutil/tmutil.go => tmagent/tmagent.go}       | 126 ++++++++++++---------
 .../tmutil_test.go => tmagent/tmagent_test.go}     |  57 +++++++---
 .../{tm-health-client.go => util/util.go}          |  36 +++---
 13 files changed, 233 insertions(+), 117 deletions(-)

diff --git a/cache-config/tm-health-client/README.md 
b/cache-config/tm-health-client/README.md
index 6acb20e..d3a2ea8 100644
--- a/cache-config/tm-health-client/README.md
+++ b/cache-config/tm-health-client/README.md
@@ -58,6 +58,17 @@ otherwise unavailable, the tm-health-client will utilize the 
**Traffic Server**
 and **Traffic Monitor** has determined that the marked down host is now 
available, 
 the client will then utilize the **Traffic Server** tool to mark the host back 
up.
 
+Also on each polling cycle the configuration file, **tm-health-client.json** 
is 
+checked and a new config is reloaded if the file has changed since the last 
+polling cycle.  The **Traffic Monitors** list is refreshed from **Traffic 
Ops**.
+
+If errors are encountered while polling a Traffic Monitor, the error is logged
+and the **Traffic Monitors** list is refreshed from **Traffic Ops**.
+
+# REQUIREMENTS
+
+Requires Apache TrafficServer 8.1.0 or later.
+
 # OPTIONS
 
 -f, -\-config-file=config-file 
@@ -97,6 +108,7 @@ Sample configuarion file:
     "to-url": "https://tp.cdn.com:443";, 
     "to-request-timeout-seconds": "5s",
     "tm-poll-interval-seconds": "60s",
+    "tm-update-cycles": 5,
     "trafficserver-config-dir": "/opt/trafficserver/etc/trafficserver",
     "trafficserver-bin-dir": "/opt/trafficserver/bin",
   }
@@ -110,7 +122,8 @@ Sample configuarion file:
 
   When enabled, the client will actively mark down Traffic Server parents.
   When disabled, the client will only log that it would have marked down
-  Traffic Server parents
+  Traffic Server parents.  Down Parents are always marked UP if Traffic Monitor
+  reports them available irregardless of this setting.
 
 ### reason-code
 
@@ -140,6 +153,12 @@ Sample configuarion file:
   The polling interval in seconds used to update **Traffic Server** parent
   status.
 
+### tm-update-cycles
+
+  Each time a polling cycle completes a count is incremented. When the count
+  reaches **tm-update-cycles**, TrafficOps is polled for a new list of 
available
+  TrafficMonitors for the CDN and the poll count is reset to 0.
+
 ### trafficserver-config-dir
 
   The location on the host where **Traffic Server** configuration files are 
diff --git a/cache-config/tm-health-client/config/config.go 
b/cache-config/tm-health-client/config/config.go
index 5c5d8a8..f46d618 100644
--- a/cache-config/tm-health-client/config/config.go
+++ b/cache-config/tm-health-client/config/config.go
@@ -30,6 +30,7 @@ import (
        "strings"
        "time"
 
+       "github.com/apache/trafficcontrol/cache-config/tm-health-client/util"
        "github.com/apache/trafficcontrol/lib/go-log"
        toclient "github.com/apache/trafficcontrol/traffic_ops/v3-client"
 
@@ -45,6 +46,7 @@ const (
        DefaultLogFile                = "tm-health-client.log"
        DefaultTrafficServerConfigDir = "/opt/trafficserver/etc/trafficserver"
        DefaultTrafficServerBinDir    = "/opt/trafficserver/bin"
+       DefaultTmUpdateCycles         = 10
 )
 
 type Cfg struct {
@@ -57,9 +59,11 @@ type Cfg struct {
        TOUrl                   string
        TOUser                  string
        TmPollIntervalSeconds   string          
`json:"tm-poll-interval-seconds"`
+       TmUpdateCycles          int             `json:"tm-update-cycles"`
        TrafficServerConfigDir  string          
`json:"trafficserver-config-dir"`
        TrafficServerBinDir     string          `json:"trafficserver-bin-dir"`
        TrafficMonitors         map[string]bool 
`json:"trafficmonitors,omitempty"`
+       HealthClientConfigFile  util.ConfigFile
 }
 
 type LogCfg struct {
@@ -75,7 +79,7 @@ func (lcfg LogCfg) InfoLog() log.LogLocation    { return 
log.LogLocation(lcfg.Lo
 func (lcfg LogCfg) DebugLog() log.LogLocation   { return 
log.LogLocation(lcfg.LogLocationDebug) }
 func (lcfg LogCfg) EventLog() log.LogLocation   { return 
log.LogLocation(log.LogLocationNull) } // not used
 
-func readCredentials(cfg *Cfg) error {
+func ReadCredentials(cfg *Cfg) error {
        fn := cfg.TOCredentialFile
        f, err := os.Open(fn)
 
@@ -179,19 +183,24 @@ func GetConfig() (Cfg, error, bool) {
                return Cfg{}, errors.New("Initializing loggers: " + err.Error() 
+ "\n"), false
        }
 
+       cf := util.ConfigFile{
+               Filename:       configFile,
+               LastModifyTime: 0,
+       }
+
        cfg := Cfg{
-               TrafficMonitors: make(map[string]bool, 0),
+               HealthClientConfigFile: cf,
        }
 
-       if err = LoadConfig(&cfg, configFile); err != nil {
+       if _, err = LoadConfig(&cfg); err != nil {
                return Cfg{}, errors.New(err.Error() + "\n"), false
        }
 
-       if err = readCredentials(&cfg); err != nil {
+       if err = ReadCredentials(&cfg); err != nil {
                return cfg, err, false
        }
 
-       err = GetTrafficMonitorsStatus(&cfg)
+       err = GetTrafficMonitors(&cfg)
        if err != nil {
                return cfg, err, false
        }
@@ -199,7 +208,7 @@ func GetConfig() (Cfg, error, bool) {
        return cfg, nil, false
 }
 
-func GetTrafficMonitorsStatus(cfg *Cfg) error {
+func GetTrafficMonitors(cfg *Cfg) error {
        u, err := url.Parse(cfg.TOUrl)
        if err != nil {
                return errors.New("error parsing TOURL parameters: " + 
err.Error())
@@ -215,6 +224,7 @@ func GetTrafficMonitorsStatus(cfg *Cfg) error {
                return errors.New("error fetching Trafficmonitor server list: " 
+ err.Error())
        }
 
+       cfg.TrafficMonitors = make(map[string]bool, 0)
        for _, v := range srvs {
                if v.CDNName == cfg.CDNName && v.Status == "ONLINE" {
                        hostname := v.HostName + "." + v.DomainName
@@ -233,26 +243,65 @@ func GetRequestTimeout() time.Duration {
        return toRequestTimeout
 }
 
-func LoadConfig(cfg *Cfg, configFile string) error {
-       content, err := ioutil.ReadFile(configFile)
+func LoadConfig(cfg *Cfg) (bool, error) {
+       updated := false
+       configFile := cfg.HealthClientConfigFile.Filename
+       modTime, err := util.GetFileModificationTime(configFile)
        if err != nil {
-               return errors.New(err.Error())
+               return updated, errors.New(err.Error())
        }
-       if err = json.Unmarshal(content, cfg); err == nil {
-               tmPollingInterval, err = 
time.ParseDuration(cfg.TmPollIntervalSeconds)
-               if err != nil {
-                       return errors.New("parsing TMPollingIntervalSeconds: " 
+ err.Error())
-               }
-               toRequestTimeout, err = 
time.ParseDuration(cfg.TORequestTimeOutSeconds)
+
+       if modTime > cfg.HealthClientConfigFile.LastModifyTime {
+               log.Infoln("Loading a new config file.")
+               content, err := ioutil.ReadFile(configFile)
                if err != nil {
-                       return errors.New("parsing TORequestTimeOutSeconds: " + 
err.Error())
+                       return updated, errors.New(err.Error())
                }
-               if cfg.ReasonCode != "active" && cfg.ReasonCode != "local" {
-                       return errors.New("invalid reason-code: " + 
cfg.ReasonCode + ", valid reason codes are 'active' or 'local'")
+               if err = json.Unmarshal(content, cfg); err == nil {
+                       tmPollingInterval, err = 
time.ParseDuration(cfg.TmPollIntervalSeconds)
+                       if err != nil {
+                               return updated, errors.New("parsing 
TMPollingIntervalSeconds: " + err.Error())
+                       }
+                       toRequestTimeout, err = 
time.ParseDuration(cfg.TORequestTimeOutSeconds)
+                       if err != nil {
+                               return updated, errors.New("parsing 
TORequestTimeOutSeconds: " + err.Error())
+                       }
+                       if cfg.ReasonCode != "active" && cfg.ReasonCode != 
"local" {
+                               return updated, errors.New("invalid 
reason-code: " + cfg.ReasonCode + ", valid reason codes are 'active' or 
'local'")
+                       }
+                       if cfg.TrafficServerConfigDir == "" {
+                               cfg.TrafficServerConfigDir = 
DefaultTrafficServerConfigDir
+                       }
+                       if cfg.TrafficServerBinDir == "" {
+                               cfg.TrafficServerBinDir = 
DefaultTrafficServerBinDir
+                       }
+                       if cfg.TmUpdateCycles == 0 {
+                               cfg.TmUpdateCycles = DefaultTmUpdateCycles
+                       }
                }
+
+               cfg.HealthClientConfigFile.LastModifyTime = modTime
+               updated = true
        }
+       return updated, nil
+}
 
-       return err
+func UpdateConfig(cfg *Cfg, newCfg *Cfg) {
+       log.Infoln("Installing config updates")
+       cfg.CDNName = newCfg.CDNName
+       cfg.EnableActiveMarkdowns = newCfg.EnableActiveMarkdowns
+       cfg.ReasonCode = newCfg.ReasonCode
+       cfg.TOCredentialFile = newCfg.TOCredentialFile
+       cfg.TORequestTimeOutSeconds = newCfg.TORequestTimeOutSeconds
+       cfg.TOPass = newCfg.TOPass
+       cfg.TOUrl = newCfg.TOUrl
+       cfg.TOUser = newCfg.TOUser
+       cfg.TmPollIntervalSeconds = newCfg.TmPollIntervalSeconds
+       cfg.TmUpdateCycles = newCfg.TmUpdateCycles
+       cfg.TrafficServerConfigDir = newCfg.TrafficServerConfigDir
+       cfg.TrafficServerBinDir = newCfg.TrafficServerBinDir
+       cfg.TrafficMonitors = newCfg.TrafficMonitors
+       cfg.HealthClientConfigFile = newCfg.HealthClientConfigFile
 }
 
 func Usage() {
diff --git a/cache-config/tm-health-client/config/config_test.go 
b/cache-config/tm-health-client/config/config_test.go
index 385439d..2bafe09 100644
--- a/cache-config/tm-health-client/config/config_test.go
+++ b/cache-config/tm-health-client/config/config_test.go
@@ -21,6 +21,8 @@ package config
 
 import (
        "testing"
+
+       "github.com/apache/trafficcontrol/cache-config/tm-health-client/util"
 )
 
 const (
@@ -28,11 +30,17 @@ const (
 )
 
 func TestLoadConfig(t *testing.T) {
+       cf := util.ConfigFile{
+               Filename:       test_config_file,
+               LastModifyTime: 0,
+       }
+
        cfg := Cfg{
-               TrafficMonitors: make(map[string]bool, 0),
+               TrafficMonitors:        make(map[string]bool, 0),
+               HealthClientConfigFile: cf,
        }
 
-       err := LoadConfig(&cfg, test_config_file)
+       _, err := LoadConfig(&cfg)
        if err != nil {
                t.Fatalf("failed to load %s: %s\n", test_config_file, 
err.Error())
        }
@@ -61,7 +69,7 @@ func TestLoadConfig(t *testing.T) {
                t.Fatalf("expected '%s', got %s\n", expect, creds)
        }
 
-       readCredentials(&cfg)
+       ReadCredentials(&cfg)
 
        expect = "https://tp.cdn.com:443";
        tourl := cfg.TOUrl
diff --git a/cache-config/tm-health-client/tm-health-client-logrotate 
b/cache-config/tm-health-client/tm-health-client-logrotate
index a3bfd30..9e97f3b 100644
--- a/cache-config/tm-health-client/tm-health-client-logrotate
+++ b/cache-config/tm-health-client/tm-health-client-logrotate
@@ -24,5 +24,5 @@
     nomail
     notifempty
     rotate 10
-    size 100M
+    size 5M
 }
diff --git a/cache-config/tm-health-client/tm-health-client.go 
b/cache-config/tm-health-client/tm-health-client.go
index b84bc61..b886e26 100644
--- a/cache-config/tm-health-client/tm-health-client.go
+++ b/cache-config/tm-health-client/tm-health-client.go
@@ -23,7 +23,7 @@ import (
        "os"
 
        "github.com/apache/trafficcontrol/cache-config/tm-health-client/config"
-       "github.com/apache/trafficcontrol/cache-config/tm-health-client/tmutil"
+       "github.com/apache/trafficcontrol/cache-config/tm-health-client/tmagent"
        "github.com/apache/trafficcontrol/lib/go-log"
 )
 
@@ -44,7 +44,7 @@ func main() {
                os.Exit(Success)
        }
 
-       tmInfo, err := tmutil.NewParentInfo(cfg)
+       tmInfo, err := tmagent.NewParentInfo(cfg)
        if err != nil {
                log.Errorf("startup could not initialize ATS parent info: 
%s\n", err.Error())
        }
diff --git a/cache-config/tm-health-client/tm-health-client.json 
b/cache-config/tm-health-client/tm-health-client.json
index 3523cda..8df62f6 100644
--- a/cache-config/tm-health-client/tm-health-client.json
+++ b/cache-config/tm-health-client/tm-health-client.json
@@ -6,6 +6,7 @@
   "to-url": "https://tp.cdn.com:443";, 
   "to-request-timeout-seconds": "5s",
   "tm-poll-interval-seconds": "15s",
+  "tm-update-cycles": 5,
   "trafficserver-config-dir": "/opt/trafficserver/etc/trafficserver",
-  "trafficserver-bin-dir": "/opt/trafficserver/bin",
+  "trafficserver-bin-dir": "/opt/trafficserver/bin"
 }
diff --git a/cache-config/tm-health-client/tmutil/test_files/bin/traffic_ctl 
b/cache-config/tm-health-client/tmagent/test_files/bin/traffic_ctl
similarity index 100%
rename from cache-config/tm-health-client/tmutil/test_files/bin/traffic_ctl
rename to cache-config/tm-health-client/tmagent/test_files/bin/traffic_ctl
diff --git a/cache-config/tm-health-client/tmutil/test_files/etc/parent.config 
b/cache-config/tm-health-client/tmagent/test_files/etc/parent.config
similarity index 100%
rename from cache-config/tm-health-client/tmutil/test_files/etc/parent.config
rename to cache-config/tm-health-client/tmagent/test_files/etc/parent.config
diff --git 
a/cache-config/tm-health-client/tmutil/test_files/etc/strategies.yaml 
b/cache-config/tm-health-client/tmagent/test_files/etc/strategies.yaml
similarity index 100%
rename from cache-config/tm-health-client/tmutil/test_files/etc/strategies.yaml
rename to cache-config/tm-health-client/tmagent/test_files/etc/strategies.yaml
diff --git 
a/cache-config/tm-health-client/tmutil/test_files/tm-health-client.json 
b/cache-config/tm-health-client/tmagent/test_files/tm-health-client.json
similarity index 100%
rename from 
cache-config/tm-health-client/tmutil/test_files/tm-health-client.json
rename to cache-config/tm-health-client/tmagent/test_files/tm-health-client.json
diff --git a/cache-config/tm-health-client/tmutil/tmutil.go 
b/cache-config/tm-health-client/tmagent/tmagent.go
similarity index 86%
rename from cache-config/tm-health-client/tmutil/tmutil.go
rename to cache-config/tm-health-client/tmagent/tmagent.go
index 45cb3d7..85329d8 100644
--- a/cache-config/tm-health-client/tmutil/tmutil.go
+++ b/cache-config/tm-health-client/tmagent/tmagent.go
@@ -1,4 +1,4 @@
-package tmutil
+package tmagent
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -33,6 +33,7 @@ import (
        "time"
 
        "github.com/apache/trafficcontrol/cache-config/tm-health-client/config"
+       "github.com/apache/trafficcontrol/cache-config/tm-health-client/util"
        "github.com/apache/trafficcontrol/lib/go-log"
        "github.com/apache/trafficcontrol/lib/go-tc"
        "github.com/apache/trafficcontrol/traffic_monitor/datareq"
@@ -48,22 +49,15 @@ const (
 )
 
 type ParentAvailable interface {
-       available() bool
-}
-
-// the necessary fields of a trafficserver parents config file needed to
-// read the file and keep track of it's modification time.
-type ParentConfigFile struct {
-       Filename       string
-       LastModifyTime int64
+       available(reasonCode string) bool
 }
 
 // the necessary data required to keep track of trafficserver config
 // files, lists of parents a trafficserver instance uses, and directory
 // locations used for configuration and trafficserver executables.
 type ParentInfo struct {
-       ParentDotConfig        ParentConfigFile
-       StrategiesDotYaml      ParentConfigFile
+       ParentDotConfig        util.ConfigFile
+       StrategiesDotYaml      util.ConfigFile
        TrafficServerBinDir    string
        TrafficServerConfigDir string
        Parents                map[string]ParentStatus
@@ -93,15 +87,18 @@ type ParentStatus struct {
 // used to get the overall parent availablity from the
 // HostStatus markdown reasons.  all markdown reasons
 // must be true for a parent to be considered available.
-func (p ParentStatus) available() bool {
-       if !p.ActiveReason {
-               return false
-       } else if !p.LocalReason {
-               return false
-       } else if !p.ManualReason {
-               return false
-       }
-       return true
+func (p ParentStatus) available(reasonCode string) bool {
+       rc := false
+
+       switch reasonCode {
+       case "active":
+               rc = p.ActiveReason
+       case "local":
+               rc = p.LocalReason
+       case "manual":
+               rc = p.ManualReason
+       }
+       return rc
 }
 
 // used to log that a parent's status is either UP or
@@ -184,22 +181,22 @@ type Strategies struct {
 func NewParentInfo(cfg config.Cfg) (*ParentInfo, error) {
 
        parentConfig := filepath.Join(cfg.TrafficServerConfigDir, ParentsFile)
-       modTime, err := getFileModificationTime(parentConfig)
+       modTime, err := util.GetFileModificationTime(parentConfig)
        if err != nil {
                return nil, errors.New("error reading " + ParentsFile + ": " + 
err.Error())
        }
-       parents := ParentConfigFile{
+       parents := util.ConfigFile{
                Filename:       parentConfig,
                LastModifyTime: modTime,
        }
 
        stratyaml := filepath.Join(cfg.TrafficServerConfigDir, StrategiesFile)
-       modTime, err = getFileModificationTime(stratyaml)
+       modTime, err = util.GetFileModificationTime(stratyaml)
        if err != nil {
                return nil, errors.New("error reading " + StrategiesFile + ": " 
+ err.Error())
        }
 
-       strategies := ParentConfigFile{
+       strategies := util.ConfigFile{
                Filename:       filepath.Join(cfg.TrafficServerConfigDir, 
StrategiesFile),
                LastModifyTime: modTime,
        }
@@ -259,10 +256,35 @@ func (c *ParentInfo) GetCacheStatuses() 
(map[tc.CacheName]datareq.CacheStatus, e
 // down in the trafficserver subsystem based upon that hosts current status and
 // the status that trafficmonitor health protocol has determined for a parent.
 func (c *ParentInfo) PollAndUpdateCacheStatus() {
+       cycleCount := 0
        pollingInterval := config.GetTMPollingInterval()
        log.Infoln("polling started")
 
        for {
+               // check for config file updates
+               newCfg := config.Cfg{
+                       HealthClientConfigFile: c.Cfg.HealthClientConfigFile,
+               }
+               isNew, err := config.LoadConfig(&newCfg)
+               if err != nil {
+                       log.Errorf("error reading changed config file %s: 
%s\n", c.Cfg.HealthClientConfigFile.Filename, err.Error())
+               }
+               if isNew {
+                       if err = config.ReadCredentials(&newCfg); err != nil {
+                               log.Errorln("could not load credentials for 
config updates, keeping the old config")
+                       } else {
+                               if err = config.GetTrafficMonitors(&newCfg); 
err != nil {
+                                       log.Errorln("could not update the list 
of trafficmonitors, keeping the old config")
+                               } else {
+                                       config.UpdateConfig(&c.Cfg, &newCfg)
+                                       log.Infof("the configuration has been 
successfully updated")
+                               }
+                       }
+               }
+
+               // check for parent and strategies config file updates, and 
trafficserver
+               // host status changes.  If an error is encountered reading 
data the current
+               // parents lists and hoststatus remains unchanged.
                if err := c.UpdateParentInfo(); err != nil {
                        log.Errorf("could not load new ATS parent info: %s\n", 
err.Error())
                } else {
@@ -272,7 +294,14 @@ func (c *ParentInfo) PollAndUpdateCacheStatus() {
                // read traffic manager cache statuses.
                caches, err := c.GetCacheStatuses()
                if err != nil {
-                       log.Errorln(err.Error())
+                       log.Errorf("error in TrafficMonitor polling: %s\n", 
err.Error())
+                       if err = config.GetTrafficMonitors(&c.Cfg); err != nil {
+                               log.Errorln("could not update the list of 
trafficmonitors, keeping the old config")
+                       } else {
+                               log.Infoln("Updated TrafficMonitor statuses 
from TrafficOps")
+                       }
+                       time.Sleep(pollingInterval)
+                       continue
                }
 
                for k, v := range caches {
@@ -280,13 +309,10 @@ func (c *ParentInfo) PollAndUpdateCacheStatus() {
                        cs, ok := c.Parents[hostName]
                        if ok {
                                tmAvailable := *v.CombinedAvailable
-                               if cs.available() != tmAvailable {
-                                       if !c.Cfg.EnableActiveMarkdowns {
-                                               if !tmAvailable {
-                                                       log.Infof("TM reports 
that %s is not available and should be marked DOWN but, mark downs are disabled 
by configuration", hostName)
-                                               } else {
-                                                       log.Infof("TM reports 
that %s is available and should be marked UP but, mark up is disabled by 
configuration", hostName)
-                                               }
+                               if cs.available(c.Cfg.ReasonCode) != 
tmAvailable {
+                                       // do not mark down if the 
configuration disables mark downs.
+                                       if !c.Cfg.EnableActiveMarkdowns && 
!tmAvailable {
+                                               log.Infof("TM reports that %s 
is not available and should be marked DOWN but, mark downs are disabled by 
configuration", hostName)
                                        } else {
                                                if err = c.markParent(cs.Fqdn, 
*v.Status, tmAvailable); err != nil {
                                                        log.Errorln(err.Error())
@@ -296,6 +322,18 @@ func (c *ParentInfo) PollAndUpdateCacheStatus() {
                        }
                }
 
+               // periodically update the TrafficMonitor list and statuses
+               if cycleCount == c.Cfg.TmUpdateCycles {
+                       cycleCount = 0
+                       if err = config.GetTrafficMonitors(&c.Cfg); err != nil {
+                               log.Errorln("could not update the list of 
trafficmonitors, keeping the old config")
+                       } else {
+                               log.Infoln("Updated TrafficMonitor statuses 
from TrafficOps")
+                       }
+               } else {
+                       cycleCount++
+               }
+
                time.Sleep(pollingInterval)
        }
 }
@@ -305,11 +343,11 @@ func (c *ParentInfo) PollAndUpdateCacheStatus() {
 // availability is also updated to reflect the current state from
 // the trafficserver HostStatus subsystem.
 func (c *ParentInfo) UpdateParentInfo() error {
-       ptime, err := getFileModificationTime(c.ParentDotConfig.Filename)
+       ptime, err := util.GetFileModificationTime(c.ParentDotConfig.Filename)
        if err != nil {
                return errors.New("error reading " + ParentsFile + ": " + 
err.Error())
        }
-       stime, err := getFileModificationTime(c.StrategiesDotYaml.Filename)
+       stime, err := util.GetFileModificationTime(c.StrategiesDotYaml.Filename)
        if err != nil {
                return errors.New("error reading " + StrategiesFile + ": " + 
err.Error())
        }
@@ -372,22 +410,6 @@ func (c *ParentInfo) findATrafficMonitor() (string, error) 
{
        return tmHostname, nil
 }
 
-// get the file modification times for a trafficserver configuration
-// file.
-func getFileModificationTime(fn string) (int64, error) {
-       f, err := os.Open(fn)
-       if err != nil {
-               return 0, errors.New("opening " + fn + ": " + err.Error())
-       }
-       defer f.Close()
-
-       finfo, err := f.Stat()
-       if err != nil {
-               return 0, errors.New("unable to get file status for " + fn + ": 
" + err.Error())
-       }
-       return finfo.ModTime().UnixNano(), nil
-}
-
 // parse out the hostname of a parent listed in parents.config
 // or 'strategies.yaml'. the hostname can be an IP address.
 func parseFqdn(fqdn string) string {
@@ -507,8 +529,8 @@ func (c *ParentInfo) readHostStatus(parentStatus 
map[string]ParentStatus) error
                                                parentStatus[hostName] = pstat
                                                log.Infof("added Host '%s' from 
ATS Host Status to the parents map\n", hostName)
                                        } else {
-                                               available := pstat.available()
-                                               if pv.available() != available {
+                                               available := 
pstat.available(c.Cfg.ReasonCode)
+                                               if 
pv.available(c.Cfg.ReasonCode) != available {
                                                        log.Infof("host status 
for '%s' has changed to %s\n", hostName, pstat.Status())
                                                        parentStatus[hostName] 
= pstat
                                                }
diff --git a/cache-config/tm-health-client/tmutil/tmutil_test.go 
b/cache-config/tm-health-client/tmagent/tmagent_test.go
similarity index 81%
rename from cache-config/tm-health-client/tmutil/tmutil_test.go
rename to cache-config/tm-health-client/tmagent/tmagent_test.go
index 417612d..f3ea96c 100644
--- a/cache-config/tm-health-client/tmutil/tmutil_test.go
+++ b/cache-config/tm-health-client/tmagent/tmagent_test.go
@@ -1,4 +1,4 @@
-package tmutil
+package tmagent
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -22,6 +22,7 @@ package tmutil
 import (
        "fmt"
        "github.com/apache/trafficcontrol/cache-config/tm-health-client/config"
+       "github.com/apache/trafficcontrol/cache-config/tm-health-client/util"
        "testing"
 )
 
@@ -30,11 +31,17 @@ const (
 )
 
 func TestReadParentDotConfig(t *testing.T) {
+       cf := util.ConfigFile{
+               Filename:       test_config_file,
+               LastModifyTime: 0,
+       }
+
        cfg := config.Cfg{
-               TrafficMonitors: make(map[string]bool, 0),
+               TrafficMonitors:        make(map[string]bool, 0),
+               HealthClientConfigFile: cf,
        }
 
-       parentDotConfig := ParentConfigFile{
+       parentDotConfig := util.ConfigFile{
                Filename:       "test_files/etc/parent.config",
                LastModifyTime: 1,
        }
@@ -44,7 +51,7 @@ func TestReadParentDotConfig(t *testing.T) {
                Cfg:             cfg,
        }
 
-       err := config.LoadConfig(&cfg, test_config_file)
+       _, err := config.LoadConfig(&cfg)
        if err != nil {
                t.Fatalf("failed to load %s: %s\n", test_config_file, 
err.Error())
        }
@@ -61,11 +68,17 @@ func TestReadParentDotConfig(t *testing.T) {
 }
 
 func TestReadStrategiesDotYaml(t *testing.T) {
+       cf := util.ConfigFile{
+               Filename:       test_config_file,
+               LastModifyTime: 0,
+       }
+
        cfg := config.Cfg{
-               TrafficMonitors: make(map[string]bool, 0),
+               TrafficMonitors:        make(map[string]bool, 0),
+               HealthClientConfigFile: cf,
        }
 
-       strategiesDotYaml := ParentConfigFile{
+       strategiesDotYaml := util.ConfigFile{
                Filename:       "test_files/etc/strategies.yaml",
                LastModifyTime: 1,
        }
@@ -75,7 +88,7 @@ func TestReadStrategiesDotYaml(t *testing.T) {
                Cfg:               cfg,
        }
 
-       err := config.LoadConfig(&cfg, test_config_file)
+       _, err := config.LoadConfig(&cfg)
        if err != nil {
                t.Fatalf("failed to load %s: %s\n", test_config_file, 
err.Error())
        }
@@ -92,8 +105,14 @@ func TestReadStrategiesDotYaml(t *testing.T) {
 }
 
 func TestReadHostStatus(t *testing.T) {
+       cf := util.ConfigFile{
+               Filename:       test_config_file,
+               LastModifyTime: 0,
+       }
+
        cfg := config.Cfg{
-               TrafficMonitors: make(map[string]bool, 0),
+               TrafficMonitors:        make(map[string]bool, 0),
+               HealthClientConfigFile: cf,
        }
 
        pi := ParentInfo{
@@ -101,7 +120,7 @@ func TestReadHostStatus(t *testing.T) {
                Cfg:                 cfg,
        }
 
-       err := config.LoadConfig(&cfg, test_config_file)
+       _, err := config.LoadConfig(&cfg)
        if err != nil {
                t.Fatalf("failed to load %s: %s\n", test_config_file, 
err.Error())
        }
@@ -119,15 +138,21 @@ func TestReadHostStatus(t *testing.T) {
 }
 
 func TestFindATrafficMonitor(t *testing.T) {
+       cf := util.ConfigFile{
+               Filename:       test_config_file,
+               LastModifyTime: 0,
+       }
+
        cfg := config.Cfg{
-               TrafficMonitors: make(map[string]bool, 0),
+               TrafficMonitors:        make(map[string]bool, 0),
+               HealthClientConfigFile: cf,
        }
 
        pi := ParentInfo{
                Cfg: cfg,
        }
 
-       err := config.LoadConfig(&cfg, test_config_file)
+       _, err := config.LoadConfig(&cfg)
        if err != nil {
                t.Fatalf("failed to load %s: %s\n", test_config_file, 
err.Error())
        }
@@ -154,7 +179,7 @@ func TestParentStatus(t *testing.T) {
                ManualReason: false,
        }
 
-       available := pstat.available()
+       available := pstat.available("manual")
        if available {
                t.Fatalf("expected parent status for %s to be false, got %v\n",
                        pstat.Fqdn, available)
@@ -164,7 +189,7 @@ func TestParentStatus(t *testing.T) {
                t.Fatalf("expected status 'DOWN' got %s\n", status)
        }
        pstat.ManualReason = true
-       available = pstat.available()
+       available = pstat.available("active")
        if !available {
                t.Fatalf("expected parent status for %s to be true, got %v\n",
                        pstat.Fqdn, available)
@@ -174,7 +199,7 @@ func TestParentStatus(t *testing.T) {
                t.Fatalf("expected status 'UP' got %s\n", status)
        }
        pstat.LocalReason = false
-       available = pstat.available()
+       available = pstat.available("local")
        if available {
                t.Fatalf("expected parent status for %s to be false, got %v\n",
                        pstat.Fqdn, available)
@@ -186,7 +211,7 @@ func TestParentStatus(t *testing.T) {
 
        pstat.LocalReason = true
        pstat.ActiveReason = false
-       available = pstat.available()
+       available = pstat.available("active")
        if available {
                t.Fatalf("expected parent status for %s to be false, got %v\n",
                        pstat.Fqdn, available)
@@ -196,7 +221,7 @@ func TestParentStatus(t *testing.T) {
                t.Fatalf("expected status 'DOWN' got %s\n", status)
        }
        pstat.ActiveReason = true
-       available = pstat.available()
+       available = pstat.available("active")
        if !available {
                t.Fatalf("expected parent status for %s to be false, got %v\n",
                        pstat.Fqdn, available)
diff --git a/cache-config/tm-health-client/tm-health-client.go 
b/cache-config/tm-health-client/util/util.go
similarity index 57%
copy from cache-config/tm-health-client/tm-health-client.go
copy to cache-config/tm-health-client/util/util.go
index b84bc61..951c701 100644
--- a/cache-config/tm-health-client/tm-health-client.go
+++ b/cache-config/tm-health-client/util/util.go
@@ -1,4 +1,4 @@
-package main
+package util
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
@@ -20,34 +20,26 @@ package main
  */
 
 import (
+       "errors"
        "os"
-
-       "github.com/apache/trafficcontrol/cache-config/tm-health-client/config"
-       "github.com/apache/trafficcontrol/cache-config/tm-health-client/tmutil"
-       "github.com/apache/trafficcontrol/lib/go-log"
 )
 
-const (
-       Success     = 0
-       ConfigError = 166
-)
+type ConfigFile struct {
+       Filename       string
+       LastModifyTime int64
+}
 
-func main() {
-       cfg, err, helpflag := config.GetConfig()
+// get the file modification times for a configuration file.
+func GetFileModificationTime(fn string) (int64, error) {
+       f, err := os.Open(fn)
        if err != nil {
-               log.Errorln(err.Error())
-               os.Exit(ConfigError)
-       } else {
-               log.Infoln("startup complete, the config has been loaded")
-       }
-       if helpflag { // user used --help option
-               os.Exit(Success)
+               return 0, errors.New("opening " + fn + ": " + err.Error())
        }
+       defer f.Close()
 
-       tmInfo, err := tmutil.NewParentInfo(cfg)
+       finfo, err := f.Stat()
        if err != nil {
-               log.Errorf("startup could not initialize ATS parent info: 
%s\n", err.Error())
+               return 0, errors.New("unable to get file status for " + fn + ": 
" + err.Error())
        }
-
-       tmInfo.PollAndUpdateCacheStatus()
+       return finfo.ModTime().UnixNano(), nil
 }

Reply via email to