This is an automated email from the ASF dual-hosted git repository.
dgelinas pushed a commit to branch 3.0.x
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git
The following commit(s) were added to refs/heads/3.0.x by this push:
new 21a5491 Fix TM polling urls with ports (#3605) (#3642)
21a5491 is described below
commit 21a549189543a458a0ec8e5d24c0d22389dc6255
Author: Robert Butts <[email protected]>
AuthorDate: Wed May 29 12:17:37 2019 -0600
Fix TM polling urls with ports (#3605) (#3642)
* Fix TM polling urls with ports
* Add Changelog issue number '#'
* Add Docs terms for monitor poll url info
(cherry picked from commit 3871f80bba888bcca535d84d8638cd20e8633fe7)
---
CHANGELOG.md | 2 +-
docs/source/admin/traffic_monitor.rst | 27 +++++++
lib/go-tc/traffic_router.go | 1 +
traffic_monitor/manager/monitorconfig.go | 64 +++++++++++-----
traffic_monitor/manager/monitorconfig_test.go | 102 ++++++++++++++++++++++++++
traffic_monitor/towrap/towrap.go | 5 ++
6 files changed, 183 insertions(+), 18 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d0526fa..956eefa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,7 +24,7 @@ The format is based on [Keep a
Changelog](http://keepachangelog.com/en/1.0.0/).
- Correct FQDN case mismatch when generating DNSSEC.
- Issue 3223 - cannot add steering targets to steering delivery service.
- Issue 3466 - docs fail to build in python 3.6.
-
+- Issue #3605: Fixed Traffic Monitor custom ports in health polling URL.
## [3.0.0] - 2019-02-13
### Added
diff --git a/docs/source/admin/traffic_monitor.rst
b/docs/source/admin/traffic_monitor.rst
index 98b0080..fd4fc88 100755
--- a/docs/source/admin/traffic_monitor.rst
+++ b/docs/source/admin/traffic_monitor.rst
@@ -55,6 +55,33 @@ Configuration Overview
Traffic Monitor is configured via two JSON configuration files,
``traffic_ops.cfg`` and ``traffic_monitor.cfg``, by default located in the
``conf`` directory in the install location. ``traffic_ops.cfg`` contains
Traffic Ops connection information. Specify the URL, username, and password for
the instance of Traffic Ops of which this Traffic Monitor is a member.
``traffic_monitor.cfg`` contains log file locations, as well as detailed
application configuration variables such as processing f [...]
+Cache Polling URL
+-----------------------------------
+
+The :term:`cache servers` are polled at the URL specified in the
``health.polling.url`` :term:`parameter`, on the :term:`cache server`'s
:term:`profile`.
+
+This :term:`parameter` must have the config file ``rascal.properties``.
+
+The value is a template with the text ``${hostname}`` being replaced with the
:term:`cache server`'s Network IP (IPv4), and ``${interface_name}`` being
replaced with the :term:`cache server`'s network Interface Name. For example,
``http://${hostname}/_astats?application=&inf.name=${interface_name}``.
+
+If the template contains a port, that port will be used, and the :term:`cache
server`'s HTTPS and TCP Ports will not be added.
+
+If the template does not contain a port, then if the template starts with
``https`` the :term:`cache server`'s HTTPS Port will be added, and if the
template doesn't start with ``https`` the :term:`cache server`'s TCP Port will
be added.
+
+Examples:
+
+Template
``http://${hostname}/_astats?application=&inf.name=${interface_name}`` Server
IP ``192.0.2.42`` Server TCP Port ``8080`` HTTPS Port ``8443`` becomes
``http://192.0.2.42:8080/_astats?application=&inf.name=${interface_name}``.
+Template
``https://${hostname}/_astats?application=&inf.name=${interface_name}`` Server
IP ``192.0.2.42`` Server TCP Port ``8080`` HTTPS Port ``8443`` becomes
``https://192.0.2.42:8443/_astats?application=&inf.name=${interface_name}``.
+Template
``http://${hostname}:1234/_astats?application=&inf.name=${interface_name}``
Server IP ``192.0.2.42`` Server TCP Port ``8080`` HTTPS Port ``8443`` becomes
``http://192.0.2.42:1234/_astats?application=&inf.name=${interface_name}``.
+Template
``https://${hostname}:1234/_astats?application=&inf.name=${interface_name}``
Server IP ``192.0.2.42`` Server TCP Port ``8080`` HTTPS Port ``8443`` becomes
``https://192.0.2.42:1234/_astats?application=&inf.name=${interface_name}``.
+
+Stat and Health Flush Configuration
+-----------------------------------
+The Monitor has a health flush interval, a stat flush interval, and a stat
buffer interval. Recall that the monitor polls both stats and health. The
health poll is so small and fast, a buffer is largely unnecessary. However, in
a large CDN, the stat poll may involve thousands of :term:`cache server` s with
thousands of stats each, or more, and CPU may be a bottleneck.
+
+The flush intervals, ``health_flush_interval_ms`` and
``stat_flush_interval_ms``, indicate how often to flush stats or health, if
results are continuously coming in with no break. This prevents starvation.
Ideally, if there is enough CPU, the flushes should never occur. The default
flush times are 200 milliseconds, which is suggested as a reasonable starting
point; operators may adjust them higher or lower depending on the need to get
health data and stop directing client traffic to unhe [...]
+
+The stat buffer interval, ``stat_buffer_interval_ms``, also provides a
temporal buffer for stat processing. Stats will not be processed except after
this interval, whereupon all pending stats will be processed, unless the flush
interval occurs as a starvation safety. The stat buffer and flush intervals may
be thought of as a state machine with two states: the "buffer state" accepts
results until the buffer interval has elapsed, whereupon the "flush state" is
entered, and results are acce [...]
Troubleshooting and Log Files
=============================
diff --git a/lib/go-tc/traffic_router.go b/lib/go-tc/traffic_router.go
index f636f7a..554f64b 100644
--- a/lib/go-tc/traffic_router.go
+++ b/lib/go-tc/traffic_router.go
@@ -136,6 +136,7 @@ type TrafficServer struct {
CacheGroup string `json:"cacheGroup"`
IP6 string `json:"ip6"`
Port int `json:"port"`
+ HTTPSPort int `json:"httpsPort,omitempty"`
HostName string `json:"hostName"`
FQDN string `json:"fqdn"`
InterfaceName string `json:"interfaceName"`
diff --git a/traffic_monitor/manager/monitorconfig.go
b/traffic_monitor/manager/monitorconfig.go
index ab0bfbc..341c743 100644
--- a/traffic_monitor/manager/monitorconfig.go
+++ b/traffic_monitor/manager/monitorconfig.go
@@ -21,6 +21,7 @@ package manager
import (
"fmt"
+ "net/url"
"os"
"strconv"
"strings"
@@ -250,8 +251,8 @@ func monitorConfigListen(
localStates.AddCache(cacheName,
tc.IsAvailable{IsAvailable: false})
}
- url :=
monitorConfig.Profile[srv.Profile].Parameters.HealthPollingURL
- if url == "" {
+ pollURLStr :=
monitorConfig.Profile[srv.Profile].Parameters.HealthPollingURL
+ if pollURLStr == "" {
log.Errorf("monitor config server %v profile %v
has no polling URL; can't poll", srv.HostName, srv.Profile)
continue
}
@@ -268,18 +269,7 @@ func monitorConfigListen(
log.Infof("health.polling.type for '%v' is
empty, using default '%v'", srv.HostName, pollType)
}
- port := ""
- if srv.Port != 0 {
- port = ":" + strconv.Itoa(srv.Port)
- }
-
- r := strings.NewReplacer(
- "${hostname}", srv.IP+port,
- "${interface_name}", srv.InterfaceName,
- "application=plugin.remap",
"application=system",
- "application=", "application=system",
- )
- url = r.Replace(url)
+ pollURLStr = createServerHealthPollURL(pollURLStr, srv)
connTimeout :=
trafficOpsHealthConnectionTimeoutToDuration(monitorConfig.Profile[srv.Profile].Parameters.HealthConnectionTimeout)
if connTimeout == 0 {
@@ -287,9 +277,9 @@ func monitorConfigListen(
log.Warnln("profile " + srv.Profile + "
health.connection.timeout Parameter is missing or zero, using default " +
DefaultHealthConnectionTimeout.String())
}
- healthURLs[srv.HostName] = poller.PollConfig{URL: url,
Host: srv.FQDN, Timeout: connTimeout, Format: format, PollType: pollType}
- r = strings.NewReplacer("application=system",
"application=")
- statURL := r.Replace(url)
+ healthURLs[srv.HostName] = poller.PollConfig{URL:
pollURLStr, Host: srv.FQDN, Timeout: connTimeout, Format: format, PollType:
pollType}
+
+ statURL := createServerStatPollURL(pollURLStr)
statURLs[srv.HostName] = poller.PollConfig{URL:
statURL, Host: srv.FQDN, Timeout: connTimeout, Format: format, PollType:
pollType}
}
@@ -341,3 +331,43 @@ func monitorConfigListen(
}
}
}
+
+// createServerHealthPollURL takes the template pollingURLStr, and replaces
variables with data from srv, and returns the polling URL for srv.
+func createServerHealthPollURL(pollingURLStr string, srv tc.TrafficServer)
string {
+ pollingURLStr = strings.NewReplacer(
+ "${hostname}", srv.IP,
+ "${interface_name}", srv.InterfaceName,
+ "application=plugin.remap", "application=system",
+ "application=", "application=system",
+ ).Replace(pollingURLStr)
+
+ if strings.HasPrefix(strings.ToLower(pollingURLStr), "https") {
+ if srv.HTTPSPort != 0 {
+ pollURL, err := url.Parse(pollingURLStr)
+ if err != nil {
+ log.Warnln("profile " + srv.Profile + " cache
'" + srv.FQDN + "' polling URL '" + pollingURLStr + "' failed to parse, may not
be a valid URL! Using anyway, not using custom HTTPS Port " +
strconv.Itoa(srv.HTTPSPort) + "!")
+ } else if pollURL.Port() == "" { // if there's both an
HTTPS Port and a port in the polling URL, the polling URL takes precedence
+ pollURL.Host += ":" +
strconv.Itoa(srv.HTTPSPort)
+ pollingURLStr = pollURL.String()
+ }
+ }
+ } else {
+ if srv.Port != 0 {
+ pollURL, err := url.Parse(pollingURLStr)
+ if err != nil {
+ log.Warnln("profile " + srv.Profile + " cache
'" + srv.FQDN + "' polling URL '" + pollingURLStr + "' failed to parse, may not
be a valid URL! Using anyway, not using custom TCP Port " +
strconv.Itoa(srv.Port) + "!")
+ } else if pollURL.Port() == "" { // if there's both a
TCP Port and a port in the polling URL, the polling URL takes precedence
+ pollURL.Host += ":" + strconv.Itoa(srv.Port)
+ pollingURLStr = pollURL.String()
+ }
+ }
+ }
+
+ return pollingURLStr
+}
+
+// createServerStatPollURL takes the health polling URL string, and modifies
it to be the stat poll URL.
+// Note this does not replace template variables with server values,
healthPollURLStr must be the health URL for a given server, not a template.
+func createServerStatPollURL(healthPollURLStr string) string {
+ return strings.NewReplacer("application=system",
"application=").Replace(healthPollURLStr)
+}
diff --git a/traffic_monitor/manager/monitorconfig_test.go
b/traffic_monitor/manager/monitorconfig_test.go
new file mode 100644
index 0000000..5d5b145
--- /dev/null
+++ b/traffic_monitor/manager/monitorconfig_test.go
@@ -0,0 +1,102 @@
+package manager
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 (
+ "strconv"
+ "testing"
+
+ "github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+func TestCreateServerHealthPollURL(t *testing.T) {
+ tmpl :=
`http://${hostname}/_astats?application=&inf.name=${interface_name}`
+ srv := tc.TrafficServer{IP: "192.0.2.42", InterfaceName: "george"}
+
+ expected := `http://` + srv.IP +
`/_astats?application=system&inf.name=` + srv.InterfaceName
+ actual := createServerHealthPollURL(tmpl, srv)
+
+ if expected != actual {
+ t.Errorf("expected createServerHealthPollURL '" + expected + "'
actual: '" + actual + "'")
+ }
+}
+
+func TestCreateServerHealthPollURLTemplatePort(t *testing.T) {
+ tmpl :=
`http://${hostname}:1234/_astats?application=&inf.name=${interface_name}`
+ srv := tc.TrafficServer{IP: "192.0.2.42", InterfaceName: "george"}
+
+ expected := `http://` + srv.IP +
`:1234/_astats?application=system&inf.name=` + srv.InterfaceName
+ actual := createServerHealthPollURL(tmpl, srv)
+
+ if expected != actual {
+ t.Errorf("expected createServerHealthPollURL '" + expected + "'
actual: '" + actual + "'")
+ }
+}
+
+func TestCreateServerHealthPollURLServerPort(t *testing.T) {
+ tmpl :=
`http://${hostname}/_astats?application=&inf.name=${interface_name}`
+ srv := tc.TrafficServer{IP: "192.0.2.42", Port: 5678, HTTPSPort: 910,
InterfaceName: "george"}
+
+ expected := `http://` + srv.IP + ":" + strconv.Itoa(srv.Port) +
`/_astats?application=system&inf.name=` + srv.InterfaceName
+ actual := createServerHealthPollURL(tmpl, srv)
+
+ if expected != actual {
+ t.Errorf("expected createServerHealthPollURL '" + expected + "'
actual: '" + actual + "'")
+ }
+}
+
+func TestCreateServerHealthPollURLServerPortHTTPS(t *testing.T) {
+ tmpl :=
`hTTps://${hostname}/_astats?application=&inf.name=${interface_name}`
+ srv := tc.TrafficServer{IP: "192.0.2.42", Port: 5678, HTTPSPort: 910,
InterfaceName: "george"}
+
+ expected := `https://` + srv.IP + ":" + strconv.Itoa(srv.HTTPSPort) +
`/_astats?application=system&inf.name=` + srv.InterfaceName
+ actual := createServerHealthPollURL(tmpl, srv)
+
+ if expected != actual {
+ t.Errorf("expected createServerHealthPollURL '" + expected + "'
actual: '" + actual + "'")
+ }
+}
+
+func TestCreateServerHealthPollURLTemplateAndServerPort(t *testing.T) {
+
+ // if both template and server ports exist, template takes precedence
+
+ tmpl :=
`http://${hostname}:1234/_astats?application=&inf.name=${interface_name}`
+ srv := tc.TrafficServer{IP: "192.0.2.42", Port: 5678, HTTPSPort: 910,
InterfaceName: "george"}
+
+ expected := `http://` + srv.IP +
`:1234/_astats?application=system&inf.name=` + srv.InterfaceName
+ actual := createServerHealthPollURL(tmpl, srv)
+
+ if expected != actual {
+ t.Errorf("expected createServerHealthPollURL '" + expected + "'
actual: '" + actual + "'")
+ }
+}
+
+func TestCreateServerStatPollURL(t *testing.T) {
+ tmpl :=
`http://${hostname}/_astats?application=&inf.name=${interface_name}`
+ srv := tc.TrafficServer{IP: "192.0.2.42", InterfaceName: "george"}
+
+ expected := `http://` + srv.IP + `/_astats?application=&inf.name=` +
srv.InterfaceName
+ actual := createServerStatPollURL(createServerHealthPollURL(tmpl, srv))
+
+ if expected != actual {
+ t.Errorf("expected createServerStatPollURL '" + expected + "'
actual: '" + actual + "'")
+ }
+}
diff --git a/traffic_monitor/towrap/towrap.go b/traffic_monitor/towrap/towrap.go
index 55e80e3..76dbedf 100644
--- a/traffic_monitor/towrap/towrap.go
+++ b/traffic_monitor/towrap/towrap.go
@@ -351,6 +351,11 @@ func CreateMonitorConfig(crConfig tc.CRConfig, mc
*tc.TrafficMonitorConfigMap) (
} else {
log.Warnf("Creating monitor config: CRConfig server %s
missing HashId field\n", name)
}
+ if srv.HttpsPort != nil {
+ s.HTTPSPort = *srv.HttpsPort
+ } else {
+ log.Warnf("Creating monitor config: CRConfig server %s
missing HttpsPort field\n", name)
+ }
mc.TrafficServer[name] = s
}