This is an automated email from the ASF dual-hosted git repository.
dgelinas 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 3871f80 Fix TM polling urls with ports (#3605)
3871f80 is described below
commit 3871f80bba888bcca535d84d8638cd20e8633fe7
Author: Robert Butts <[email protected]>
AuthorDate: Wed May 29 10:55:37 2019 -0600
Fix TM polling urls with ports (#3605)
* Fix TM polling urls with ports
* Add Changelog issue number '#'
* Add Docs terms for monitor poll url info
---
CHANGELOG.md | 2 +-
docs/source/admin/traffic_monitor.rst | 21 ++++++
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, 177 insertions(+), 18 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a14f8b7..97dedc2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -48,7 +48,7 @@ The format is based on [Keep a
Changelog](http://keepachangelog.com/en/1.0.0/).
- Issue 3476: Traffic Router returns partial result for CLIENT_STEERING
Delivery Services when Regional Geoblocking or Anonymous Blocking is enabled.
- Upgraded Traffic Portal to AngularJS 1.7.8
- Issue 3275: Improved the snapshot diff performance and experience.
-
+- Issue #3605: Fixed Traffic Monitor custom ports in health polling URL.
## [3.0.0] - 2018-10-30
### Added
diff --git a/docs/source/admin/traffic_monitor.rst
b/docs/source/admin/traffic_monitor.rst
index 85dab8c..046350a 100755
--- a/docs/source/admin/traffic_monitor.rst
+++ b/docs/source/admin/traffic_monitor.rst
@@ -52,6 +52,27 @@ Configuration Overview
----------------------
Traffic Monitor is configured via two JSON configuration files,
:file:`traffic_ops.cfg` and :file:`traffic_monitor.cfg`, by default located in
the ``conf`` directory in the install location. :file:`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. :file:`traffic_monitor.cfg` contains log file locations, as well as
detailed application configuration variables such [...]
+
+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.
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 8b3b82f..87139f0 100644
--- a/traffic_monitor/towrap/towrap.go
+++ b/traffic_monitor/towrap/towrap.go
@@ -470,6 +470,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
}