This is an automated email from the ASF dual-hosted git repository.
rob 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 e3afacd Adds max origin connections to ds api endpoints (v14) and TP
and adds the value to hdr_rw_xml-id.config OR hdr_rw_mid_xml-id.config files
(#3422)
e3afacd is described below
commit e3afacdbcc271ecdf0fb0effd30232096128a6b5
Author: Jeremy Mitchell <[email protected]>
AuthorDate: Tue Apr 16 11:36:56 2019 -0600
Adds max origin connections to ds api endpoints (v14) and TP and adds the
value to hdr_rw_xml-id.config OR hdr_rw_mid_xml-id.config files (#3422)
* adds max origin connections to ds api routes and TP
* adds hdr_rw_xml-id.config and hdr_rw_mid_xml-id.config to Go endpoints
and inserts a rule for max-origin-connections IF ds.max_origin_connections > 0
* adds hdr_rw_xml-id.config and hdr_rw_mid_xml-id.config to Go endpoints
and inserts a rule for max-origin-connections IF ds.max_origin_connections > 0
* formats file
* godoc fix
* uses the proper errors package
* defines the hdr_rewrite endpoints as 1.1. to completely override the perl
implementations
* some cleanup/simplification and minor changes like using constants, go
doc fixes, and returning a 404 when ds is not found
* adds maxoriginconnections to EnsureParams to ensure that the existence of
that value influences when location params are created for hdr rewrite files
---
CHANGELOG.md | 1 +
docs/source/api/deliveryservices.rst | 24 ++-
lib/go-tc/constants.go | 1 +
lib/go-tc/deliveryservices.go | 23 ++-
.../20190319000000_add_max_origin_connections.sql | 23 +++
.../app/lib/API/Configs/ApacheTrafficServer.pm | 2 +-
traffic_ops/bin/traffic_ops_ort.pl | 13 +-
.../testing/api/v14/deliveryservices_test.go | 5 +-
traffic_ops/testing/api/v14/tc-fixtures.json | 3 +
traffic_ops/traffic_ops_golang/ats/config.go | 77 ++++++++
.../traffic_ops_golang/ats/headerrewrite.go | 202 +++++++++++++++++++++
.../traffic_ops_golang/ats/regexrevalidate.go | 66 -------
.../deliveryservice/deliveryservicesv12.go | 15 +-
.../deliveryservice/deliveryservicesv13.go | 58 +++---
.../deliveryservice/deliveryservicesv14.go | 170 +++++++++++++++++
.../deliveryservice/request/requests_test.go | 20 +-
.../deliveryservice/servers/servers.go | 31 ++--
traffic_ops/traffic_ops_golang/routing/routes.go | 13 ++
traffic_ops/traffic_ops_golang/server/servers.go | 16 +-
.../form.deliveryService.DNS.tpl.html | 14 ++
.../form.deliveryService.HTTP.tpl.html | 14 ++
.../app/src/traffic_portal_properties.json | 2 +
22 files changed, 645 insertions(+), 148 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6615ded..16f7471 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ The format is based on [Keep a
Changelog](http://keepachangelog.com/en/1.0.0/).
The default certificate is used whenever a client attempts an SSL handshake
for an SNI host which does not match
any of the other certificates.
- Traffic Ops Golang Endpoints
+ - /api/1.4/deliveryservices `(GET,POST,PUT)`
- /api/1.4/users `(GET,POST,PUT)`
- /api/1.1/deliveryservices/xmlId/:xmlid/sslkeys `GET`
- /api/1.1/deliveryservices/hostname/:hostname/sslkeys `GET`
diff --git a/docs/source/api/deliveryservices.rst
b/docs/source/api/deliveryservices.rst
index 7cd66c5..57f73b2 100644
--- a/docs/source/api/deliveryservices.rst
+++ b/docs/source/api/deliveryservices.rst
@@ -61,9 +61,6 @@ Response Structure
:cdnName: Name of the CDN to which the :term:`Delivery
Service` belongs
:checkPath: The path portion of the URL to check connections to
this :term:`Delivery Service`'s origin server
:consistentHashRegex: If defined, this is a regex used for the
Pattern-Based Consistent Hashing feature. It is only applicable for HTTP and
Steering Delivery Services
-
- .. versionadded:: 1.5
-
:displayName: The display name of the :term:`Delivery Service`
:dnsBypassCname: Domain name to overflow requests for HTTP
:term:`Delivery Service`\ s - bypass starts when the traffic on this
:term:`Delivery Service` exceeds ``globalMaxMbps``, or when more than
``globalMaxTps`` is being exceeded within the :term:`Delivery Service`\ [4]_
:dnsBypassIp: The IPv4 IP to use for bypass on a DNS
:term:`Delivery Service` - bypass starts when the traffic on this
:term:`Delivery Service` exceeds ``globalMaxMbps``, or when more than
``globalMaxTps`` is being exceeded within the :term:`Delivery Service`\ [4]_
@@ -120,6 +117,10 @@ Response Structure
Use the :term:`Delivery Service` if ``pattern`` matches
the ``xml_id`` of one of this :term:`Delivery Service`'s "Steering" target
:term:`Delivery Service`\ s
:maxDnsAnswers: The maximum number of IPs to put in responses to A/AAAA DNS
record requests (0 means all available)\ [4]_
+:maxOriginConnections: The maximum number of connections allowed to the
origin (0 means no maximum).
+
+ .. versionadded:: 1.4
+
:midHeaderRewrite: Rewrite operations to be performed on TCP headers at the
Edge-tier cache level - used by the Header Rewrite Apache Trafficserver plugin
:missLat: The latitude to use when the client cannot be found in the
CZF or a geographic IP lookup
:missLong: The longitude to use when the client cannot be found in the
CZF or a geographic IP lookup
@@ -246,6 +247,7 @@ Response Structure
}
],
"maxDnsAnswers": null,
+ "maxOriginConnections": 0,
"midHeaderRewrite": null,
"missLat": 42,
"missLong": -88,
@@ -302,9 +304,6 @@ Request Structure
:cdnId: The integral, unique identifier for the CDN to
which this :term:`Delivery Service`\ shall be assigned
:checkPath: The path portion of the URL which will be used to
check connections to this :term:`Delivery Service`'s origin server
:consistentHashRegex: If defined, this is a regex used for the
Pattern-Based Consistent Hashing feature. It is only applicable for HTTP and
Steering Delivery Services
-
- .. versionadded:: 1.5
-
:deepCachingType: A string describing when to do Deep Caching for
this :term:`Delivery Service`:
NEVER
@@ -351,6 +350,10 @@ Request Structure
:longDesc1: An optional field used when more detailed information
that that provided by ``longDesc`` is desired
:longDesc2: An optional field used when even more detailed
information that that provided by either ``longDesc`` or ``longDesc1`` is
desired
:maxDnsAnswers: An optional field which, when present, specifies the
maximum number of IPs to put in responses to A/AAAA DNS record requests -
defaults to 0, meaning "no limit"\ [4]_
+:maxOriginConnections: The maximum number of connections allowed to the
origin (0 means no maximum).
+
+ .. versionadded:: 1.4
+
:midHeaderRewrite: An optional string containing rewrite operations to be
performed on TCP headers at the Edge-tier cache level - used by the Header
Rewrite Apache Trafficserver plugin
:missLat: The latitude to use when the client cannot be found in
the CZF or a geographic IP lookup\ [7]_
:missLong: The longitude to use when the client cannot be found in
the CZF or a geographic IP lookup\ [7]_
@@ -454,6 +457,7 @@ Request Structure
"longDesc": "A :term:`Delivery Service` created expressly for
API documentation examples",
"missLat": -1,
"missLong": -1,
+ "maxOriginConnections": 0,
"multiSiteOrigin": false,
"orgServerFqdn": "http://origin.infra.ciab.test",
"protocol": 0,
@@ -486,9 +490,6 @@ Response Structure
:cdnName: Name of the CDN to which the :term:`Delivery
Service` belongs
:checkPath: The path portion of the URL to check connections to
this :term:`Delivery Service`'s origin server
:consistentHashRegex: If defined, this is a regex used for the
Pattern-Based Consistent Hashing feature. It is only applicable for HTTP and
Steering Delivery Services
-
- .. versionadded:: 1.5
-
:displayName: The display name of the :term:`Delivery Service`
:dnsBypassCname: Domain name to overflow requests for HTTP
:term:`Delivery Service`\ s - bypass starts when the traffic on this
:term:`Delivery Service` exceeds ``globalMaxMbps``, or when more than
``globalMaxTps`` is being exceeded within the :term:`Delivery Service`\ [4]_
:dnsBypassIp: The IPv4 IP to use for bypass on a DNS
:term:`Delivery Service` - bypass starts when the traffic on this
:term:`Delivery Service` exceeds ``globalMaxMbps``, or when more than
``globalMaxTps`` is being exceeded within the :term:`Delivery Service`\ [4]_
@@ -545,6 +546,10 @@ Response Structure
Use the :term:`Delivery Service` if ``pattern`` matches
the ``xml_id`` of one of this :term:`Delivery Service`'s "Steering" target
:term:`Delivery Service`\ s
:maxDnsAnswers: The maximum number of IPs to put in responses to A/AAAA DNS
record requests (0 means all available)\ [4]_
+:maxOriginConnections: The maximum number of connections allowed to the
origin (0 means no maximum).
+
+ .. versionadded:: 1.4
+
:midHeaderRewrite: Rewrite operations to be performed on TCP headers at the
Edge-tier cache level - used by the Header Rewrite Apache Trafficserver plugin
:missLat: The latitude to use when the client cannot be found in the
CZF or a geographic IP lookup
:missLong: The longitude to use when the client cannot be found in the
CZF or a geographic IP lookup
@@ -677,6 +682,7 @@ Response Structure
}
],
"maxDnsAnswers": null,
+ "maxOriginConnections": 0,
"midHeaderRewrite": null,
"missLat": -1,
"missLong": -1,
diff --git a/lib/go-tc/constants.go b/lib/go-tc/constants.go
index 9f7cee8..539f139 100644
--- a/lib/go-tc/constants.go
+++ b/lib/go-tc/constants.go
@@ -32,6 +32,7 @@ const ApplicationJson = "application/json"
const Gzip = "gzip"
const ContentType = "Content-Type"
const ContentEncoding = "Content-Encoding"
+const ContentTypeTextPlain = "text/plain"
type AlertLevel int
diff --git a/lib/go-tc/deliveryservices.go b/lib/go-tc/deliveryservices.go
index cb3fdd3..7bc7865 100644
--- a/lib/go-tc/deliveryservices.go
+++ b/lib/go-tc/deliveryservices.go
@@ -73,6 +73,11 @@ type DeleteDeliveryServiceResponse struct {
}
type DeliveryService struct {
+ DeliveryServiceV13
+ MaxOriginConnections int `json:"maxOriginConnections"
db:"max_origin_connections"`
+}
+
+type DeliveryServiceV13 struct {
DeliveryServiceV12
DeepCachingType DeepCachingType `json:"deepCachingType"`
FQPacingRate int `json:"fqPacingRate,omitempty"`
@@ -146,6 +151,11 @@ type DeliveryServiceV11 struct {
}
type DeliveryServiceNullable struct {
+ DeliveryServiceNullableV13
+ MaxOriginConnections *int `json:"maxOriginConnections"
db:"max_origin_connections"`
+}
+
+type DeliveryServiceNullableV13 struct {
DeliveryServiceNullableV12
ConsistentHashRegex *string
`json:"consistentHashRegex,omitempty"`
DeepCachingType *DeepCachingType `json:"deepCachingType"
db:"deep_caching_type"`
@@ -225,7 +235,15 @@ type DeliveryServiceNullableV11 struct {
// NewDeliveryServiceNullableFromV12 creates a new V13 DS from a V12 DS,
filling new fields with appropriate defaults.
func NewDeliveryServiceNullableFromV12(ds DeliveryServiceNullableV12)
DeliveryServiceNullable {
- newDS := DeliveryServiceNullable{DeliveryServiceNullableV12: ds}
+ newDSv13 := DeliveryServiceNullableV13{DeliveryServiceNullableV12: ds}
+ newDS := DeliveryServiceNullable{DeliveryServiceNullableV13: newDSv13}
+ newDS.Sanitize()
+ return newDS
+}
+
+// NewDeliveryServiceNullableFromV13 creates a new V14 DS from a V13 DS,
filling new fields with appropriate defaults.
+func NewDeliveryServiceNullableFromV13(ds DeliveryServiceNullableV13)
DeliveryServiceNullable {
+ newDS := DeliveryServiceNullable{DeliveryServiceNullableV13: ds}
newDS.Sanitize()
return newDS
}
@@ -399,6 +417,9 @@ func (ds *DeliveryServiceNullable) Sanitize() {
if !ds.Signed && ds.SigningAlgorithm != nil && *ds.SigningAlgorithm ==
signedAlgorithm {
ds.Signed = true
}
+ if ds.MaxOriginConnections == nil || *ds.MaxOriginConnections < 0 {
+ ds.MaxOriginConnections = util.IntPtr(0)
+ }
if ds.DeepCachingType == nil {
s := DeepCachingType("")
ds.DeepCachingType = &s
diff --git
a/traffic_ops/app/db/migrations/20190319000000_add_max_origin_connections.sql
b/traffic_ops/app/db/migrations/20190319000000_add_max_origin_connections.sql
new file mode 100644
index 0000000..784d87b
--- /dev/null
+++
b/traffic_ops/app/db/migrations/20190319000000_add_max_origin_connections.sql
@@ -0,0 +1,23 @@
+/*
+
+ 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.
+*/
+
+-- +goose Up
+-- SQL in section 'Up' is executed when this migration is applied
+ALTER TABLE deliveryservice ADD COLUMN max_origin_connections bigint NOT NULL
DEFAULT 0 CHECK (max_origin_connections >= 0);
+
+-- +goose Down
+-- SQL section 'Down' is executed when this migration is rolled back
+ALTER TABLE deliveryservice DROP COLUMN max_origin_connections;
+
diff --git a/traffic_ops/app/lib/API/Configs/ApacheTrafficServer.pm
b/traffic_ops/app/lib/API/Configs/ApacheTrafficServer.pm
index e4a286c..b456396 100755
--- a/traffic_ops/app/lib/API/Configs/ApacheTrafficServer.pm
+++ b/traffic_ops/app/lib/API/Configs/ApacheTrafficServer.pm
@@ -153,7 +153,7 @@ sub get_config_metadata {
delete $config_file_obj->{$config_file}->{'apiUri'};
}
else {
- $config_file_obj->{$config_file}->{'apiUri'} =
"/api/1.2/" . $scope . "/" . $scope_id . "/configfiles/ats/" . $config_file;
+ $config_file_obj->{$config_file}->{'apiUri'} =
"/api/1.4/" . $scope . "/" . $scope_id . "/configfiles/ats/" . $config_file;
}
$config_file_obj->{$config_file}->{'scope'} = $scope;
}
diff --git a/traffic_ops/bin/traffic_ops_ort.pl
b/traffic_ops/bin/traffic_ops_ort.pl
index e62eb80..47a2a1f 100755
--- a/traffic_ops/bin/traffic_ops_ort.pl
+++ b/traffic_ops/bin/traffic_ops_ort.pl
@@ -797,7 +797,7 @@ sub get_update_status {
##Some versions of Traffic Ops had the 1.3 API but did not have the
use_reval_pending field. If this field is not present, exit.
if ( !defined( $upd_json->[0]->{'use_reval_pending'} ) ) {
- my $info_uri = "/api/1.2/system/info.json";
+ my $info_uri = "/api/1.4/system/info.json";
my $info_ref = &lwp_get($info_uri);
if ($info_ref eq '404') {
( $log_level >> $ERROR ) && printf("ERROR Unable to get
status of use_reval_pending parameter. Stopping.\n");
@@ -856,7 +856,7 @@ sub check_revalidate_state {
( $log_level >> $ERROR ) && print "ERROR Traffic Ops is
signaling that no revalidations are waiting to be applied.\n";
}
- my $stj = &lwp_get("/api/1.2/statuses");
+ my $stj = &lwp_get("/api/1.4/statuses");
if ( $stj =~ m/^\d{3}$/ ) {
( $log_level >> $ERROR ) && print "Statuses URL: $uri
returned $stj! Skipping creation of status file.\n";
}
@@ -973,8 +973,7 @@ sub check_syncds_state {
else {
( $log_level >> $ERROR ) && print "ERROR Traffic Ops is
signaling that no update is waiting to be applied.\n";
}
-
- my $stj = &lwp_get("/api/1.2/statuses");
+ my $stj = &lwp_get("/api/1.4/statuses");
if ( $stj =~ m/^\d{3}$/ ) {
( $log_level >> $ERROR ) && print "Statuses URL: $uri
returned $stj! Skipping creation of status file.\n";
}
@@ -1784,7 +1783,7 @@ sub get_cfg_file_list {
my $cfg_files;
my $profile_name;
my $cdn_name;
- my $uri = "/api/1.2/servers/$host_name/configfiles/ats";
+ my $uri = "/api/1.4/servers/$host_name/configfiles/ats";
my $result = &lwp_get($uri);
@@ -1895,7 +1894,7 @@ sub get_header_comment {
my $to_host = shift;
my $toolname;
- my $uri = "/api/1.2/system/info.json";
+ my $uri = "/api/1.4/system/info.json";
my $result = &lwp_get($uri);
my $result_ref = decode_json($result);
@@ -2983,7 +2982,7 @@ sub adv_processing_ssl {
my @db_file_lines = @{ $_[0] };
if (@db_file_lines > 1) { #header line is always present, so look for 2
lines or more
( $log_level >> $DEBUG ) && print "DEBUG Entering advanced
processing for ssl_multicert.config.\n";
- my $uri = "/api/1.2/cdns/name/$my_cdn_name/sslkeys.json";
+ my $uri = "/api/1.4/cdns/name/$my_cdn_name/sslkeys.json";
my $result = &lwp_get($uri);
if ( $result =~ m/^\d{3}$/ ) {
if ( $script_mode == $REPORT ) {
diff --git a/traffic_ops/testing/api/v14/deliveryservices_test.go
b/traffic_ops/testing/api/v14/deliveryservices_test.go
index 3aa6e0e..eec83e1 100644
--- a/traffic_ops/testing/api/v14/deliveryservices_test.go
+++ b/traffic_ops/testing/api/v14/deliveryservices_test.go
@@ -87,8 +87,10 @@ func UpdateTestDeliveryServices(t *testing.T) {
updatedLongDesc := "something different"
updatedMaxDNSAnswers := 164598
+ updatedMaxOriginConnections := 100
remoteDS.LongDesc = updatedLongDesc
remoteDS.MaxDNSAnswers = updatedMaxDNSAnswers
+ remoteDS.MaxOriginConnections = updatedMaxOriginConnections
remoteDS.MatchList = nil // verify that this field is optional in a PUT
request, doesn't cause nil dereference panic
if updateResp, err :=
TOSession.UpdateDeliveryService(strconv.Itoa(remoteDS.ID), &remoteDS); err !=
nil {
@@ -104,9 +106,10 @@ func UpdateTestDeliveryServices(t *testing.T) {
t.Errorf("cannot GET Delivery Service by ID: %v - nil\n",
remoteDS.XMLID)
}
- if resp.LongDesc != updatedLongDesc || resp.MaxDNSAnswers !=
updatedMaxDNSAnswers {
+ if resp.LongDesc != updatedLongDesc || resp.MaxDNSAnswers !=
updatedMaxDNSAnswers || resp.MaxOriginConnections !=
updatedMaxOriginConnections {
t.Errorf("results do not match actual: %s, expected: %s\n",
resp.LongDesc, updatedLongDesc)
t.Errorf("results do not match actual: %v, expected: %v\n",
resp.MaxDNSAnswers, updatedMaxDNSAnswers)
+ t.Errorf("results do not match actual: %v, expected: %v\n",
resp.MaxOriginConnections, updatedMaxOriginConnections)
}
}
diff --git a/traffic_ops/testing/api/v14/tc-fixtures.json
b/traffic_ops/testing/api/v14/tc-fixtures.json
index eb7be84..6fe45e4 100644
--- a/traffic_ops/testing/api/v14/tc-fixtures.json
+++ b/traffic_ops/testing/api/v14/tc-fixtures.json
@@ -338,6 +338,7 @@
}
],
"maxDnsAnswers": 0,
+ "maxOriginConnections": -1,
"midHeaderRewrite": "midRewrite2",
"missLat": 41.881944,
"missLong": -87.627778,
@@ -405,6 +406,7 @@
}
],
"maxDnsAnswers": 0,
+ "maxOriginConnections": 0,
"midHeaderRewrite": "midRewrite3",
"missLat": 41.881944,
"missLong": -87.627778,
@@ -462,6 +464,7 @@
"longDesc2": "",
"matchList": [],
"maxDnsAnswers": 0,
+ "maxOriginConnections": 1,
"midHeaderRewrite": "",
"missLat": 41.881944,
"missLong": -87.627778,
diff --git a/traffic_ops/traffic_ops_golang/ats/config.go
b/traffic_ops/traffic_ops_golang/ats/config.go
index ea6a521..06225d4 100644
--- a/traffic_ops/traffic_ops_golang/ats/config.go
+++ b/traffic_ops/traffic_ops_golang/ats/config.go
@@ -1,5 +1,16 @@
package ats
+import (
+ "database/sql"
+ "errors"
+ "fmt"
+ "net/http"
+ "strconv"
+ "time"
+
+
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
+)
+
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -27,6 +38,72 @@ const CacheUrlPrefix = "cacheurl_"
const RemapFile = "remap.config"
+const HeaderCommentDateFormat = "Mon Jan 2 15:04:05 MST 2006"
+
func GetConfigFile(prefix string, xmlId string) string {
return prefix + xmlId + configSuffix
}
+
+func GetNameVersionString(tx *sql.Tx) (string, error) {
+ qry := `
+SELECT
+ p.name,
+ p.value
+FROM
+ parameter p
+WHERE
+ (p.name = 'tm.toolname' OR p.name = 'tm.url') AND p.config_file = 'global'
+`
+ rows, err := tx.Query(qry)
+ if err != nil {
+ return "", errors.New("querying: " + err.Error())
+ }
+ defer rows.Close()
+ toolName := ""
+ url := ""
+ for rows.Next() {
+ name := ""
+ val := ""
+ if err := rows.Scan(&name, &val); err != nil {
+ return "", errors.New("scanning: " + err.Error())
+ }
+ if name == "tm.toolname" {
+ toolName = val
+ } else if name == "tm.url" {
+ url = val
+ }
+ }
+ return toolName + " (" + url + ")", nil
+}
+
+// getCDNNameFromNameOrID returns the CDN name from a parameter which may be
the name or ID.
+// This also checks and verifies the existence of the given CDN, and returns
an appropriate user error if it doesn't exist.
+// Returns the name, any user error, any system error, and any error code.
+func getCDNNameFromNameOrID(tx *sql.Tx, cdnNameOrID string) (string, error,
error, int) {
+ if cdnID, err := strconv.Atoi(cdnNameOrID); err == nil {
+ cdnName, ok, err := dbhelpers.GetCDNNameFromID(tx, int64(cdnID))
+ if err != nil {
+ return "", nil, fmt.Errorf("getting CDN name from id
%v: %v", cdnID, err), http.StatusInternalServerError
+ } else if !ok {
+ return "", errors.New("cdn not found"), nil,
http.StatusNotFound
+ }
+ return string(cdnName), nil, nil, http.StatusOK
+ }
+
+ cdnName := cdnNameOrID
+ if ok, err := dbhelpers.CDNExists(cdnName, tx); err != nil {
+ return "", nil, fmt.Errorf("checking CDN name '%v' existence:
%v", cdnName, err), http.StatusInternalServerError
+ } else if !ok {
+ return "", errors.New("cdn not found"), nil, http.StatusNotFound
+ }
+ return cdnName, nil, nil, http.StatusOK
+}
+
+func headerComment(tx *sql.Tx, name string) (string, error) {
+ nameVersionStr, err := GetNameVersionString(tx)
+ if err != nil {
+ return "", errors.New("getting name version string: " +
err.Error())
+ }
+ return "# DO NOT EDIT - Generated for " + name + " by " +
nameVersionStr + " on " + time.Now().Format(HeaderCommentDateFormat) + "\n", nil
+}
+
diff --git a/traffic_ops/traffic_ops_golang/ats/headerrewrite.go
b/traffic_ops/traffic_ops_golang/ats/headerrewrite.go
new file mode 100644
index 0000000..9c60437
--- /dev/null
+++ b/traffic_ops/traffic_ops_golang/ats/headerrewrite.go
@@ -0,0 +1,202 @@
+package ats
+
+/*
+ * 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 (
+ "errors"
+ "github.com/apache/trafficcontrol/lib/go-tc"
+ "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
+
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/deliveryservice"
+ "github.com/jmoiron/sqlx"
+ "math"
+ "net/http"
+ "regexp"
+ "strconv"
+)
+
+func GetEdgeHeaderRewriteDotConfig(w http.ResponseWriter, r *http.Request) {
+ inf, userErr, sysErr, errCode := api.NewInfo(r,
[]string{"cdn-name-or-id"}, nil)
+ if userErr != nil || sysErr != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+ return
+ }
+ defer inf.Close()
+
+ cdnName, userErr, sysErr, errCode := getCDNNameFromNameOrID(inf.Tx.Tx,
inf.Params["cdn-name-or-id"])
+ if userErr != nil || sysErr != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+ return
+ }
+
+ text, err := headerComment(inf.Tx.Tx, "CDN "+cdnName)
+ if err != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError,
nil, errors.New("getting hdr_rw_xml-id.config text: "+err.Error()))
+ return
+ }
+
+ ds, err := getDeliveryService(inf.Tx, inf.Params["xml-id"])
+ if err != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, http.StatusNotFound, nil,
errors.New("getting hdr_rw_mid_xml-id.config text: "+err.Error()))
+ return
+ }
+
+ maxOriginConnections := *ds.MaxOriginConnections
+
+ dsType, err := deliveryservice.GetDeliveryServiceType(*ds.ID, inf.Tx.Tx)
+ if err != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError,
nil, errors.New("getting hdr_rw_xml-id.config text: "+err.Error()))
+ return
+ }
+ usesMids := dsType.UsesMidCache()
+
+ // write a header rewrite rule if maxOriginConnections > 0 and the ds
does NOT use mids
+ if maxOriginConnections > 0 && !usesMids {
+ dsOnlineEdgeCount, err := getOnlineDSEdgeCount(inf.Tx, *ds.ID)
+ if err != nil {
+ api.HandleErr(w, r, inf.Tx.Tx,
http.StatusInternalServerError, nil, errors.New("getting ds server count:
"+err.Error()))
+ return
+ }
+ maxOriginConnectionsPerEdge :=
int(math.Round(float64(maxOriginConnections) / float64(dsOnlineEdgeCount)))
+ text += "cond %{REMAP_PSEUDO_HOOK}\nset-config
proxy.config.http.origin_max_connections " +
strconv.Itoa(maxOriginConnectionsPerEdge)
+ if ds.EdgeHeaderRewrite == nil {
+ text += " [L]"
+ } else {
+ text += "\n"
+ }
+ }
+
+ // write the contents of ds.EdgeHeaderRewrite to hdr_rw_xml-id.config
replacing any instances of __RETURN__ (surrounded by spaces or not) with \n
+ if ds.EdgeHeaderRewrite != nil {
+ var re = regexp.MustCompile(`\s*__RETURN__\s*`)
+ text += re.ReplaceAllString(*ds.EdgeHeaderRewrite, "\n")
+ }
+
+ text += "\n"
+
+ w.Header().Set(tc.ContentType, tc.ContentTypeTextPlain)
+ w.Write([]byte(text))
+}
+
+func GetMidHeaderRewriteDotConfig(w http.ResponseWriter, r *http.Request) {
+ inf, userErr, sysErr, errCode := api.NewInfo(r,
[]string{"cdn-name-or-id"}, nil)
+ if userErr != nil || sysErr != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+ return
+ }
+ defer inf.Close()
+
+ cdnName, userErr, sysErr, errCode := getCDNNameFromNameOrID(inf.Tx.Tx,
inf.Params["cdn-name-or-id"])
+ if userErr != nil || sysErr != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+ return
+ }
+
+ text, err := headerComment(inf.Tx.Tx, "CDN "+cdnName)
+ if err != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError,
nil, errors.New("getting hdr_rw_mid_xml-id.config text: "+err.Error()))
+ return
+ }
+
+ ds, err := getDeliveryService(inf.Tx, inf.Params["xml-id"])
+ if err != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, http.StatusNotFound, nil,
errors.New("getting hdr_rw_mid_xml-id.config text: "+err.Error()))
+ return
+ }
+
+ maxOriginConnections := *ds.MaxOriginConnections
+
+ dsType, err := deliveryservice.GetDeliveryServiceType(*ds.ID, inf.Tx.Tx)
+ if err != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError,
nil, errors.New("getting hdr_rw_mid_xml-id.config text: "+err.Error()))
+ return
+ }
+ usesMids := dsType.UsesMidCache()
+
+ // write a header rewrite rule if maxOriginConnections > 0 and the ds
DOES use mids
+ if maxOriginConnections > 0 && usesMids {
+ dsOnlineMidCount, err := getOnlineDSMidCount(inf.Tx, *ds.ID)
+ if err != nil {
+ api.HandleErr(w, r, inf.Tx.Tx,
http.StatusInternalServerError, nil, errors.New("getting ds server count:
"+err.Error()))
+ return
+ }
+ maxOriginConnectionsPerMid :=
int(math.Round(float64(maxOriginConnections) / float64(dsOnlineMidCount)))
+ text += "cond %{REMAP_PSEUDO_HOOK}\nset-config
proxy.config.http.origin_max_connections " +
strconv.Itoa(maxOriginConnectionsPerMid)
+ if ds.MidHeaderRewrite == nil {
+ text += " [L]"
+ } else {
+ text += "\n"
+ }
+ }
+
+ // write the contents of ds.MidHeaderRewrite to
hdr_rw_mid_xml-id.config replacing any instances of __RETURN__ (surrounded by
spaces or not) with \n
+ if ds.MidHeaderRewrite != nil {
+ var re = regexp.MustCompile(`\s*__RETURN__\s*`)
+ text += re.ReplaceAllString(*ds.MidHeaderRewrite, "\n")
+ }
+
+ text += "\n"
+
+ w.Header().Set(tc.ContentType, tc.ContentTypeTextPlain)
+ w.Write([]byte(text))
+}
+
+func getDeliveryService(tx *sqlx.Tx, xmlId string)
(tc.DeliveryServiceNullable, error) {
+ qry := `SELECT id, cdn_id, max_origin_connections, edge_header_rewrite,
mid_header_rewrite FROM deliveryservice WHERE xml_id = $1`
+ ds := tc.DeliveryServiceNullable{}
+ if err := tx.QueryRow(qry, xmlId).Scan(&ds.ID, &ds.CDNID,
&ds.MaxOriginConnections, &ds.EdgeHeaderRewrite, &ds.MidHeaderRewrite); err !=
nil {
+ return tc.DeliveryServiceNullable{}, err
+ }
+ return ds, nil
+}
+// getOnlineDSEdgeCount gets the count of online or reported edges assigned to
a delivery service
+func getOnlineDSEdgeCount(tx *sqlx.Tx, dsID int) (int, error) {
+ count := 0
+ qry := `SELECT count(1)
+ FROM deliveryservice_server
+ JOIN server ON deliveryservice_server.server = server.id
+ JOIN status ON server.status = status.id
+ WHERE deliveryservice_server.deliveryservice = $1 AND
status.name IN ('REPORTED', 'ONLINE')`
+ if err := tx.QueryRow(qry, dsID).Scan(&count); err != nil {
+ return 0, err
+ }
+ return count, nil
+}
+
+// getOnlineDSMidCount gets the count of online or reported mids employed by
the delivery service
+// 1. get the cache groups of the edges assigned to the ds
+// 2. get the parent cachegroups for those cachegroups (found in 1)
+// 3. get the servers that belong to those cachegroups that are a) mids and b)
online/reported
+func getOnlineDSMidCount(tx *sqlx.Tx, dsID int) (int, error) {
+ count := 0
+ qry := `SELECT COUNT(1)
+FROM server AS s
+JOIN type AS t ON s.type = t.id
+JOIN status AS st ON s.status = st.id
+WHERE t.name = 'MID' AND st.name IN ('ONLINE', 'REPORTED') AND s.cachegroup IN
(
+ SELECT cg.parent_cachegroup_id FROM cachegroup AS cg
+ WHERE cg.id IN (
+ SELECT s.cachegroup FROM server AS s
+ WHERE s.id IN (
+ SELECT server FROM deliveryservice_server WHERE deliveryservice =
$1)))`
+ if err := tx.QueryRow(qry, dsID).Scan(&count); err != nil {
+ return 0, err
+ }
+ return count, nil
+}
diff --git a/traffic_ops/traffic_ops_golang/ats/regexrevalidate.go
b/traffic_ops/traffic_ops_golang/ats/regexrevalidate.go
index 5cfe985..1dc424d 100644
--- a/traffic_ops/traffic_ops_golang/ats/regexrevalidate.go
+++ b/traffic_ops/traffic_ops_golang/ats/regexrevalidate.go
@@ -22,7 +22,6 @@ package ats
import (
"database/sql"
"errors"
- "fmt"
"net/http"
"sort"
"strconv"
@@ -31,12 +30,10 @@ import (
"github.com/apache/trafficcontrol/lib/go-log"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
-
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
)
const DefaultMaxRevalDurationDays = 90
const JobKeywordPurge = "PURGE"
-const HeaderCommentDateFormat = "Mon Jan 2 15:04:05 MST 2006"
func GetRegexRevalidateDotConfig(w http.ResponseWriter, r *http.Request) {
inf, userErr, sysErr, errCode := api.NewInfo(r,
[]string{"cdn-name-or-id"}, nil)
@@ -61,29 +58,6 @@ func GetRegexRevalidateDotConfig(w http.ResponseWriter, r
*http.Request) {
w.Write([]byte(regexRevalTxt))
}
-// getCDNNameFromNameOrID returns the CDN name from a parameter which may be
the name or ID.
-// This also checks and verifies the existence of the given CDN, and returns
an appropriate user error if it doesn't exist.
-// Returns the name, any user error, any system error, and any error code.
-func getCDNNameFromNameOrID(tx *sql.Tx, cdnNameOrID string) (string, error,
error, int) {
- if cdnID, err := strconv.Atoi(cdnNameOrID); err == nil {
- cdnName, ok, err := dbhelpers.GetCDNNameFromID(tx, int64(cdnID))
- if err != nil {
- return "", nil, fmt.Errorf("getting CDN name from id
%v: %v", cdnID, err), http.StatusInternalServerError
- } else if !ok {
- return "", errors.New("cdn not found"), nil,
http.StatusNotFound
- }
- return string(cdnName), nil, nil, http.StatusOK
- }
-
- cdnName := cdnNameOrID
- if ok, err := dbhelpers.CDNExists(cdnName, tx); err != nil {
- return "", nil, fmt.Errorf("checking CDN name '%v' existence:
%v", cdnName, err), http.StatusInternalServerError
- } else if !ok {
- return "", errors.New("cdn not found"), nil, http.StatusNotFound
- }
- return cdnName, nil, nil, http.StatusOK
-}
-
func getRegexRevalidate(tx *sql.Tx, cdnName string) (string, error) {
maxDays, ok, err := getMaxDays(tx)
if err != nil {
@@ -207,43 +181,3 @@ func getMaxDays(tx *sql.Tx) (int64, bool, error) {
}
return days, true, nil
}
-
-func headerComment(tx *sql.Tx, name string) (string, error) {
- nameVersionStr, err := GetNameVersionString(tx)
- if err != nil {
- return "", errors.New("getting name version string: " +
err.Error())
- }
- return "# DO NOT EDIT - Generated for " + name + " by " +
nameVersionStr + " on " + time.Now().Format(HeaderCommentDateFormat) + "\n", nil
-}
-
-func GetNameVersionString(tx *sql.Tx) (string, error) {
- qry := `
-SELECT
- p.name,
- p.value
-FROM
- parameter p
-WHERE
- (p.name = 'tm.toolname' OR p.name = 'tm.url') AND p.config_file = 'global'
-`
- rows, err := tx.Query(qry)
- if err != nil {
- return "", errors.New("querying: " + err.Error())
- }
- defer rows.Close()
- toolName := ""
- url := ""
- for rows.Next() {
- name := ""
- val := ""
- if err := rows.Scan(&name, &val); err != nil {
- return "", errors.New("scanning: " + err.Error())
- }
- if name == "tm.toolname" {
- toolName = val
- } else if name == "tm.url" {
- url = val
- }
- }
- return toolName + " (" + url + ")", nil
-}
diff --git
a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv12.go
b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv12.go
index 2e6e732..ad112da 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv12.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv12.go
@@ -24,6 +24,7 @@ import (
"errors"
"fmt"
"net/http"
+ "strconv"
"github.com/apache/trafficcontrol/lib/go-tc"
"github.com/apache/trafficcontrol/lib/go-util"
@@ -282,7 +283,7 @@ func (ds *TODeliveryServiceV12) Delete() (error, error,
int) {
return nil, nil, http.StatusOK
}
-// Update is unimplemented, needed to satisfy CRUDer, since the framework
doesn't allow an update to return an array of one
+// Update is unimplemented, needed to satisfy CRUDer, since the framework
doesn't allow an update to return an array of one.
func (ds *TODeliveryServiceV12) Update() (error, error, int) {
return nil, nil, http.StatusNotImplemented
}
@@ -309,3 +310,15 @@ func UpdateV12(w http.ResponseWriter, r *http.Request) {
}
api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice update
was successful.",
[]tc.DeliveryServiceNullableV12{dsv13.DeliveryServiceNullableV12})
}
+
+// GetDeliveryServiceType returns the type of the deliveryservice.
+func GetDeliveryServiceType(dsID int, tx *sql.Tx) (tc.DSType, error) {
+ var dsType tc.DSType
+ if err := tx.QueryRow(`SELECT t.name FROM deliveryservice as ds JOIN
type t ON ds.type = t.id WHERE ds.id=$1`, dsID).Scan(&dsType); err != nil {
+ if err == sql.ErrNoRows {
+ return tc.DSTypeInvalid, errors.New("a deliveryservice
with id '" + strconv.Itoa(dsID) + "' was not found")
+ }
+ return tc.DSTypeInvalid, errors.New("querying type from
delivery service: " + err.Error())
+ }
+ return dsType, nil
+}
diff --git
a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv13.go
b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv13.go
index 056c934..e81a980 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv13.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv13.go
@@ -46,7 +46,7 @@ import (
type TODeliveryServiceV13 struct {
api.APIInfoImpl
- tc.DeliveryServiceNullable
+ tc.DeliveryServiceNullableV13
}
func (ds *TODeliveryServiceV13) V12() *TODeliveryServiceV12 {
@@ -57,10 +57,10 @@ func (ds *TODeliveryServiceV13) V12() *TODeliveryServiceV12
{
}
func (ds TODeliveryServiceV13) MarshalJSON() ([]byte, error) {
- return json.Marshal(ds.DeliveryServiceNullable)
+ return json.Marshal(ds.DeliveryServiceNullableV13)
}
func (ds *TODeliveryServiceV13) UnmarshalJSON(data []byte) error {
- return json.Unmarshal(data, ds.DeliveryServiceNullable)
+ return json.Unmarshal(data, ds.DeliveryServiceNullableV13)
}
func (ds *TODeliveryServiceV13) APIInfo() *api.APIInfo { return ds.ReqInfo }
@@ -88,7 +88,7 @@ func (ds *TODeliveryServiceV13) GetType() string {
}
func (ds *TODeliveryServiceV13) Validate() error {
- return ds.DeliveryServiceNullable.Validate(ds.APIInfo().Tx.Tx)
+ return ds.DeliveryServiceNullableV13.Validate(ds.APIInfo().Tx.Tx)
}
// Create is unimplemented, needed to satisfy CRUDer, since the framework
doesn't allow a create to return an array of one
@@ -105,7 +105,7 @@ func CreateV13(w http.ResponseWriter, r *http.Request) {
}
defer inf.Close()
- ds := tc.DeliveryServiceNullable{}
+ ds := tc.DeliveryServiceNullableV13{}
if err := api.Parse(r.Body, inf.Tx.Tx, &ds); err != nil {
api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest,
errors.New("decoding: "+err.Error()), nil)
return
@@ -118,12 +118,13 @@ func CreateV13(w http.ResponseWriter, r *http.Request) {
api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest,
errors.New("invalid request: "+err.Error()), nil)
return
}
- ds, errCode, userErr, sysErr = create(inf.Tx.Tx, *inf.Config, inf.User,
ds)
+ dsv14 := tc.NewDeliveryServiceNullableFromV13(ds)
+ dsv14, errCode, userErr, sysErr = create(inf.Tx.Tx, *inf.Config,
inf.User, dsv14)
if userErr != nil || sysErr != nil {
api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
return
}
- api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice creation
was successful.", []tc.DeliveryServiceNullable{ds})
+ api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice creation
was successful.",
[]tc.DeliveryServiceNullableV13{dsv14.DeliveryServiceNullableV13})
}
// create creates the given ds in the database, and returns the DS with its id
and other fields created on insert set. On error, the HTTP status code, user
error, and system error are returned. The status code SHOULD NOT be used, if
both errors are nil.
@@ -140,7 +141,7 @@ func create(tx *sql.Tx, cfg config.Config, user
*auth.CurrentUser, ds tc.Deliver
deepCachingType = ds.DeepCachingType.String() // necessary,
because DeepCachingType's default needs to insert the string, not "", and Query
doesn't call .String().
}
- resultRows, err := tx.Query(insertQuery(), &ds.Active,
&ds.AnonymousBlockingEnabled, &ds.CacheURL, &ds.CCRDNSTTL, &ds.CDNID,
&ds.CheckPath, &ds.ConsistentHashRegex, &deepCachingType, &ds.DisplayName,
&ds.DNSBypassCNAME, &ds.DNSBypassIP, &ds.DNSBypassIP6, &ds.DNSBypassTTL,
&ds.DSCP, &ds.EdgeHeaderRewrite, &ds.GeoLimitRedirectURL, &ds.GeoLimit,
&ds.GeoLimitCountries, &ds.GeoProvider, &ds.GlobalMaxMBPS, &ds.GlobalMaxTPS,
&ds.FQPacingRate, &ds.HTTPBypassFQDN, &ds.InfoURL, &ds.InitialDispers [...]
+ resultRows, err := tx.Query(insertQuery(), &ds.Active,
&ds.AnonymousBlockingEnabled, &ds.CacheURL, &ds.CCRDNSTTL, &ds.CDNID,
&ds.CheckPath, &ds.ConsistentHashRegex, &deepCachingType, &ds.DisplayName,
&ds.DNSBypassCNAME, &ds.DNSBypassIP, &ds.DNSBypassIP6, &ds.DNSBypassTTL,
&ds.DSCP, &ds.EdgeHeaderRewrite, &ds.GeoLimitRedirectURL, &ds.GeoLimit,
&ds.GeoLimitCountries, &ds.GeoProvider, &ds.GlobalMaxMBPS, &ds.GlobalMaxTPS,
&ds.FQPacingRate, &ds.HTTPBypassFQDN, &ds.InfoURL, &ds.InitialDispers [...]
if err != nil {
usrErr, sysErr, code := api.ParseDBError(err)
return tc.DeliveryServiceNullable{}, code, usrErr, sysErr
@@ -196,7 +197,7 @@ func create(tx *sql.Tx, cfg config.Config, user
*auth.CurrentUser, ds tc.Deliver
ds.ExampleURLs = MakeExampleURLs(ds.Protocol, *ds.Type,
*ds.RoutingName, *ds.MatchList, cdnDomain)
- if err := EnsureParams(tx, *ds.ID, *ds.XMLID, ds.EdgeHeaderRewrite,
ds.MidHeaderRewrite, ds.RegexRemap, ds.CacheURL, ds.SigningAlgorithm, dsType);
err != nil {
+ if err := EnsureParams(tx, *ds.ID, *ds.XMLID, ds.EdgeHeaderRewrite,
ds.MidHeaderRewrite, ds.RegexRemap, ds.CacheURL, ds.SigningAlgorithm, dsType,
ds.MaxOriginConnections); err != nil {
return tc.DeliveryServiceNullable{},
http.StatusInternalServerError, nil, errors.New("ensuring ds parameters:: " +
err.Error())
}
@@ -230,7 +231,7 @@ func (ds *TODeliveryServiceV13) Read() ([]interface{},
error, error, int) {
}
for _, ds := range dses {
- returnable = append(returnable, ds)
+ returnable = append(returnable, ds.DeliveryServiceNullableV13)
}
return returnable, nil, nil, http.StatusOK
}
@@ -435,7 +436,7 @@ func update(tx *sql.Tx, cfg config.Config, user
*auth.CurrentUser, ds *tc.Delive
deepCachingType = ds.DeepCachingType.String() // necessary,
because DeepCachingType's default needs to insert the string, not "", and Query
doesn't call .String().
}
- resultRows, err := tx.Query(updateDSQuery(), &ds.Active, &ds.CacheURL,
&ds.CCRDNSTTL, &ds.CDNID, &ds.CheckPath, &deepCachingType, &ds.DisplayName,
&ds.DNSBypassCNAME, &ds.DNSBypassIP, &ds.DNSBypassIP6, &ds.DNSBypassTTL,
&ds.DSCP, &ds.EdgeHeaderRewrite, &ds.GeoLimitRedirectURL, &ds.GeoLimit,
&ds.GeoLimitCountries, &ds.GeoProvider, &ds.GlobalMaxMBPS, &ds.GlobalMaxTPS,
&ds.FQPacingRate, &ds.HTTPBypassFQDN, &ds.InfoURL, &ds.InitialDispersion,
&ds.IPV6RoutingEnabled, &ds.LogsEnabled, &ds.Lon [...]
+ resultRows, err := tx.Query(updateDSQuery(), &ds.Active, &ds.CacheURL,
&ds.CCRDNSTTL, &ds.CDNID, &ds.CheckPath, &deepCachingType, &ds.DisplayName,
&ds.DNSBypassCNAME, &ds.DNSBypassIP, &ds.DNSBypassIP6, &ds.DNSBypassTTL,
&ds.DSCP, &ds.EdgeHeaderRewrite, &ds.GeoLimitRedirectURL, &ds.GeoLimit,
&ds.GeoLimitCountries, &ds.GeoProvider, &ds.GlobalMaxMBPS, &ds.GlobalMaxTPS,
&ds.FQPacingRate, &ds.HTTPBypassFQDN, &ds.InfoURL, &ds.InitialDispersion,
&ds.IPV6RoutingEnabled, &ds.LogsEnabled, &ds.Lon [...]
if err != nil {
usrErr, sysErr, code := api.ParseDBError(err)
@@ -505,7 +506,7 @@ func update(tx *sql.Tx, cfg config.Config, user
*auth.CurrentUser, ds *tc.Delive
}
}
- if err := EnsureParams(tx, *ds.ID, *ds.XMLID, ds.EdgeHeaderRewrite,
ds.MidHeaderRewrite, ds.RegexRemap, ds.CacheURL, ds.SigningAlgorithm, dsType);
err != nil {
+ if err := EnsureParams(tx, *ds.ID, *ds.XMLID, ds.EdgeHeaderRewrite,
ds.MidHeaderRewrite, ds.RegexRemap, ds.CacheURL, ds.SigningAlgorithm,
newDSType, ds.MaxOriginConnections); err != nil {
return tc.DeliveryServiceNullable{},
http.StatusInternalServerError, nil, errors.New("ensuring ds parameters:: " +
err.Error())
}
@@ -594,7 +595,7 @@ func GetDeliveryServices(query string, queryValues
map[string]interface{}, tx *s
for rows.Next() {
ds := tc.DeliveryServiceNullable{}
cdnDomain := ""
- err := rows.Scan(&ds.Active, &ds.AnonymousBlockingEnabled,
&ds.CacheURL, &ds.CCRDNSTTL, &ds.CDNID, &ds.CDNName, &ds.CheckPath,
&ds.ConsistentHashRegex, &ds.DeepCachingType, &ds.DisplayName,
&ds.DNSBypassCNAME, &ds.DNSBypassIP, &ds.DNSBypassIP6, &ds.DNSBypassTTL,
&ds.DSCP, &ds.EdgeHeaderRewrite, &ds.GeoLimitRedirectURL, &ds.GeoLimit,
&ds.GeoLimitCountries, &ds.GeoProvider, &ds.GlobalMaxMBPS, &ds.GlobalMaxTPS,
&ds.FQPacingRate, &ds.HTTPBypassFQDN, &ds.ID, &ds.InfoURL, &ds.InitialDispersi
[...]
+ err := rows.Scan(&ds.Active, &ds.AnonymousBlockingEnabled,
&ds.CacheURL, &ds.CCRDNSTTL, &ds.CDNID, &ds.CDNName, &ds.CheckPath,
&ds.ConsistentHashRegex, &ds.DeepCachingType, &ds.DisplayName,
&ds.DNSBypassCNAME, &ds.DNSBypassIP, &ds.DNSBypassIP6, &ds.DNSBypassTTL,
&ds.DSCP, &ds.EdgeHeaderRewrite, &ds.GeoLimitRedirectURL, &ds.GeoLimit,
&ds.GeoLimitCountries, &ds.GeoProvider, &ds.GlobalMaxMBPS, &ds.GlobalMaxTPS,
&ds.FQPacingRate, &ds.HTTPBypassFQDN, &ds.ID, &ds.InfoURL, &ds.InitialDispersi
[...]
if err != nil {
return nil, []error{fmt.Errorf("getting delivery
services: %v", err)}, tc.SystemError
}
@@ -784,11 +785,11 @@ const (
// EnsureParams ensures the given delivery service's necessary parameters
exist on profiles of servers assigned to the delivery service.
// Note the edgeHeaderRewrite, midHeaderRewrite, regexRemap, and cacheURL may
be nil, if the delivery service does not have those values.
-func EnsureParams(tx *sql.Tx, dsID int, xmlID string, edgeHeaderRewrite
*string, midHeaderRewrite *string, regexRemap *string, cacheURL *string,
signingAlgorithm *string, dsType tc.DSType) error {
- if err := ensureHeaderRewriteParams(tx, dsID, xmlID, edgeHeaderRewrite,
edgeTier, dsType); err != nil {
+func EnsureParams(tx *sql.Tx, dsID int, xmlID string, edgeHeaderRewrite
*string, midHeaderRewrite *string, regexRemap *string, cacheURL *string,
signingAlgorithm *string, dsType tc.DSType, maxOriginConns *int) error {
+ if err := ensureHeaderRewriteParams(tx, dsID, xmlID, edgeHeaderRewrite,
edgeTier, dsType, maxOriginConns); err != nil {
return errors.New("creating edge header rewrite parameters: " +
err.Error())
}
- if err := ensureHeaderRewriteParams(tx, dsID, xmlID, midHeaderRewrite,
midTier, dsType); err != nil {
+ if err := ensureHeaderRewriteParams(tx, dsID, xmlID, midHeaderRewrite,
midTier, dsType, maxOriginConns); err != nil {
return errors.New("creating mid header rewrite parameters: " +
err.Error())
}
if err := ensureRegexRemapParams(tx, dsID, xmlID, regexRemap); err !=
nil {
@@ -803,15 +804,19 @@ func EnsureParams(tx *sql.Tx, dsID int, xmlID string,
edgeHeaderRewrite *string,
return nil
}
-func ensureHeaderRewriteParams(tx *sql.Tx, dsID int, xmlID string, hdrRW
*string, tier tierType, dsType tc.DSType) error {
- if tier == midTier && dsType.IsLive() && !dsType.IsNational() {
- return nil // live local DSes don't get remap rules
- }
+func ensureHeaderRewriteParams(tx *sql.Tx, dsID int, xmlID string, hdrRW
*string, tier tierType, dsType tc.DSType, maxOriginConns *int) error {
configFile := "hdr_rw_" + xmlID + ".config"
if tier == midTier {
configFile = "hdr_rw_mid_" + xmlID + ".config"
}
- if hdrRW == nil || *hdrRW == "" {
+
+ if tier == midTier && dsType.IsLive() && !dsType.IsNational() {
+ // live local DSes don't get header rewrite rules on the mid so
cleanup any location params related to mids
+ return deleteLocationParam(tx, configFile)
+ }
+
+ hasMaxOriginConns := *maxOriginConns > 0 && ((tier == midTier) ==
dsType.UsesMidCache())
+ if (hdrRW == nil || *hdrRW == "") && !hasMaxOriginConns {
return deleteLocationParam(tx, configFile)
}
locationParamID, err := ensureLocation(tx, configFile)
@@ -937,7 +942,7 @@ func deleteLocationParam(tx *sql.Tx, configFile string)
error {
return nil
}
-// export the selectQuery for the 'servers' package.
+// export the selectQuery for the 'deliveryservice' package.
func GetDSSelectQuery() string {
return selectQuery()
}
@@ -979,6 +984,7 @@ ds.long_desc,
ds.long_desc_1,
ds.long_desc_2,
ds.max_dns_answers,
+ds.max_origin_connections,
ds.mid_header_rewrite,
COALESCE(ds.miss_lat, 0.0),
COALESCE(ds.miss_long, 0.0),
@@ -1070,8 +1076,9 @@ tr_response_headers=$47,
type=$48,
xml_id=$49,
anonymous_blocking_enabled=$50,
-consistent_hash_regex=$51
-WHERE id=$52
+consistent_hash_regex=$51,
+max_origin_connections=$52
+WHERE id=$53
RETURNING last_updated
`
}
@@ -1110,6 +1117,7 @@ long_desc,
long_desc_1,
long_desc_2,
max_dns_answers,
+max_origin_connections,
mid_header_rewrite,
miss_lat,
miss_long,
@@ -1131,7 +1139,7 @@ tr_response_headers,
type,
xml_id
)
-VALUES
($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51)
+VALUES
($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$40,$41,$42,$43,$44,$45,$46,$47,$48,$49,$50,$51,$52)
RETURNING id, last_updated
`
}
diff --git
a/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv14.go
b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv14.go
new file mode 100644
index 0000000..98f3337
--- /dev/null
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/deliveryservicesv14.go
@@ -0,0 +1,170 @@
+package deliveryservice
+
+/*
+ * 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 (
+ "encoding/json"
+ "errors"
+ "net/http"
+
+ "github.com/apache/trafficcontrol/lib/go-tc"
+ "github.com/apache/trafficcontrol/lib/go-util"
+ "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
+ "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/auth"
+)
+
+//we need a type alias to define functions on
+
+type TODeliveryServiceV14 struct {
+ api.APIInfoImpl
+ tc.DeliveryServiceNullable
+}
+
+func (ds *TODeliveryServiceV14) V13() *TODeliveryServiceV13 {
+ v13 := &TODeliveryServiceV13{}
+ v13.DeliveryServiceNullableV13 = ds.DeliveryServiceNullableV13
+ v13.SetInfo(ds.ReqInfo)
+ return v13
+}
+
+func (ds TODeliveryServiceV14) MarshalJSON() ([]byte, error) {
+ return json.Marshal(ds.DeliveryServiceNullable)
+}
+
+func (ds *TODeliveryServiceV14) UnmarshalJSON(data []byte) error {
+ return json.Unmarshal(data, ds.DeliveryServiceNullable)
+}
+
+func (ds *TODeliveryServiceV14) APIInfo() *api.APIInfo { return ds.ReqInfo }
+
+func (ds TODeliveryServiceV14) GetKeyFieldsInfo() []api.KeyFieldInfo {
+ return ds.V13().GetKeyFieldsInfo()
+}
+
+//Implementation of the Identifier, Validator interface functions
+func (ds TODeliveryServiceV14) GetKeys() (map[string]interface{}, bool) {
+ return ds.V13().GetKeys()
+}
+
+func (ds *TODeliveryServiceV14) SetKeys(keys map[string]interface{}) {
+ i, _ := keys["id"].(int) //this utilizes the non panicking type
assertion, if the thrown away ok variable is false i will be the zero of the
type, 0 here.
+ ds.ID = &i
+}
+
+func (ds *TODeliveryServiceV14) GetAuditName() string {
+ return ds.V13().GetAuditName()
+}
+
+func (ds *TODeliveryServiceV14) GetType() string {
+ return ds.V13().GetType()
+}
+
+func (ds *TODeliveryServiceV14) Validate() error {
+ return ds.DeliveryServiceNullable.Validate(ds.APIInfo().Tx.Tx)
+}
+
+// TODO allow users to post names (type, cdn, etc) and get the IDs from
the names. This isn't trivial to do in a single query, without dynamically
building the entire insert query, and ideally inserting would be one query. But
it'd be much more convenient for users. Alternatively, remove IDs from the
database entirely and use real candidate keys.
+func CreateV14(w http.ResponseWriter, r *http.Request) {
+ inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+ if userErr != nil || sysErr != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+ return
+ }
+ defer inf.Close()
+
+ ds := tc.DeliveryServiceNullable{}
+ if err := api.Parse(r.Body, inf.Tx.Tx, &ds); err != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest,
errors.New("decoding: "+err.Error()), nil)
+ return
+ }
+
+ if ds.RoutingName == nil || *ds.RoutingName == "" {
+ ds.RoutingName = util.StrPtr("cdn")
+ }
+ if err := ds.Validate(inf.Tx.Tx); err != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest,
errors.New("invalid request: "+err.Error()), nil)
+ return
+ }
+ ds, errCode, userErr, sysErr = create(inf.Tx.Tx, *inf.Config, inf.User,
ds)
+ if userErr != nil || sysErr != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+ return
+ }
+ api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice creation
was successful.", []tc.DeliveryServiceNullable{ds})
+}
+
+func (ds *TODeliveryServiceV14) Read() ([]interface{}, error, error, int) {
+ returnable := []interface{}{}
+ dses, errs, _ := readGetDeliveryServices(ds.APIInfo().Params,
ds.APIInfo().Tx, ds.APIInfo().User)
+ if len(errs) > 0 {
+ for _, err := range errs {
+ if err.Error() == `id cannot parse to integer` { //
TODO create const for string
+ return nil, errors.New("Resource not found."),
nil, http.StatusNotFound //matches perl response
+ }
+ }
+ return nil, nil, errors.New("reading dses: " +
util.JoinErrsStr(errs)), http.StatusInternalServerError
+ }
+
+ for _, ds := range dses {
+ returnable = append(returnable, ds)
+ }
+ return returnable, nil, nil, http.StatusOK
+}
+
+func UpdateV14(w http.ResponseWriter, r *http.Request) {
+ inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"})
+ if userErr != nil || sysErr != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+ return
+ }
+ defer inf.Close()
+
+ id := inf.IntParams["id"]
+
+ ds := tc.DeliveryServiceNullable{}
+ if err := json.NewDecoder(r.Body).Decode(&ds); err != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest,
errors.New("malformed JSON: "+err.Error()), nil)
+ return
+ }
+ ds.ID = &id
+
+ if err := ds.Validate(inf.Tx.Tx); err != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, http.StatusBadRequest,
errors.New("invalid request: "+err.Error()), nil)
+ return
+ }
+
+ ds, errCode, userErr, sysErr = update(inf.Tx.Tx, *inf.Config, inf.User,
&ds)
+ if userErr != nil || sysErr != nil {
+ api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+ return
+ }
+ api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Deliveryservice update
was successful.", []tc.DeliveryServiceNullable{ds})
+}
+
+// Delete is the DeliveryService implementation of the Deleter interface
+//all implementations of Deleter should use transactions and return the proper
errorType
+func (ds *TODeliveryServiceV14) Delete() (error, error, int) {
+ return ds.V13().Delete()
+}
+
+// IsTenantAuthorized implements the Tenantable interface to ensure the user
is authorized on the deliveryservice tenant
+func (ds *TODeliveryServiceV14) IsTenantAuthorized(user *auth.CurrentUser)
(bool, error) {
+ return ds.V13().IsTenantAuthorized(user)
+}
diff --git
a/traffic_ops/traffic_ops_golang/deliveryservice/request/requests_test.go
b/traffic_ops/traffic_ops_golang/deliveryservice/request/requests_test.go
index 2ddd489..c745399 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/request/requests_test.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/request/requests_test.go
@@ -62,15 +62,17 @@ func TestGetDeliveryServiceRequest(t *testing.T) {
ChangeType: &u,
Status: &st,
DeliveryService: &tc.DeliveryServiceNullable{
- DeliveryServiceNullableV12:
tc.DeliveryServiceNullableV12{
- DeliveryServiceNullableV11:
tc.DeliveryServiceNullableV11{
- XMLID: &s,
- CDNID: &i,
- LogsEnabled: &b,
- DSCP: nil,
- GeoLimit: &i,
- Active: &b,
- TypeID: &i,
+ DeliveryServiceNullableV13:
tc.DeliveryServiceNullableV13{
+ DeliveryServiceNullableV12:
tc.DeliveryServiceNullableV12{
+ DeliveryServiceNullableV11:
tc.DeliveryServiceNullableV11{
+ XMLID: &s,
+ CDNID: &i,
+ LogsEnabled: &b,
+ DSCP: nil,
+ GeoLimit: &i,
+ Active: &b,
+ TypeID: &i,
+ },
},
},
},
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/servers/servers.go
b/traffic_ops/traffic_ops_golang/deliveryservice/servers/servers.go
index 2a57ff1..2a508ab 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/servers/servers.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/servers/servers.go
@@ -295,7 +295,7 @@ func GetReplaceHandler(w http.ResponseWriter, r
*http.Request) {
respServers = append(respServers, server)
}
- if err := deliveryservice.EnsureParams(inf.Tx.Tx, *dsId, ds.Name,
ds.EdgeHeaderRewrite, ds.MidHeaderRewrite, ds.RegexRemap, ds.CacheURL,
ds.SigningAlgorithm, ds.Type); err != nil {
+ if err := deliveryservice.EnsureParams(inf.Tx.Tx, *dsId, ds.Name,
ds.EdgeHeaderRewrite, ds.MidHeaderRewrite, ds.RegexRemap, ds.CacheURL,
ds.SigningAlgorithm, ds.Type, ds.MaxOriginConnections); err != nil {
api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError,
nil, errors.New("deliveryservice_server replace ensuring ds parameters:
"+err.Error()))
return
}
@@ -361,7 +361,7 @@ func GetCreateHandler(w http.ResponseWriter, r
*http.Request) {
return
}
- if err := deliveryservice.EnsureParams(inf.Tx.Tx, ds.ID, ds.Name,
ds.EdgeHeaderRewrite, ds.MidHeaderRewrite, ds.RegexRemap, ds.CacheURL,
ds.SigningAlgorithm, ds.Type); err != nil {
+ if err := deliveryservice.EnsureParams(inf.Tx.Tx, ds.ID, ds.Name,
ds.EdgeHeaderRewrite, ds.MidHeaderRewrite, ds.RegexRemap, ds.CacheURL,
ds.SigningAlgorithm, ds.Type, ds.MaxOriginConnections); err != nil {
api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError,
nil, errors.New("deliveryservice_server replace ensuring ds parameters:
"+err.Error()))
return
}
@@ -564,14 +564,15 @@ func updateQuery() string {
}
type DSInfo struct {
- ID int
- Name string
- Type tc.DSType
- EdgeHeaderRewrite *string
- MidHeaderRewrite *string
- RegexRemap *string
- SigningAlgorithm *string
- CacheURL *string
+ ID int
+ Name string
+ Type tc.DSType
+ EdgeHeaderRewrite *string
+ MidHeaderRewrite *string
+ RegexRemap *string
+ SigningAlgorithm *string
+ CacheURL *string
+ MaxOriginConnections *int
}
// GetDSInfo loads the DeliveryService fields needed by Delivery Service
Servers from the database, from the ID. Returns the data, whether the delivery
service was found, and any error.
@@ -584,7 +585,8 @@ SELECT
ds.mid_header_rewrite,
ds.regex_remap,
ds.signing_algorithm,
- ds.cacheurl
+ ds.cacheurl,
+ ds.max_origin_connections
FROM
deliveryservice ds
JOIN type tp ON ds.type = tp.id
@@ -592,7 +594,7 @@ WHERE
ds.id = $1
`
di := DSInfo{ID: id}
- if err := tx.QueryRow(qry, id).Scan(&di.Name, &di.Type,
&di.EdgeHeaderRewrite, &di.MidHeaderRewrite, &di.RegexRemap,
&di.SigningAlgorithm, &di.CacheURL); err != nil {
+ if err := tx.QueryRow(qry, id).Scan(&di.Name, &di.Type,
&di.EdgeHeaderRewrite, &di.MidHeaderRewrite, &di.RegexRemap,
&di.SigningAlgorithm, &di.CacheURL, &di.MaxOriginConnections); err != nil {
if err == sql.ErrNoRows {
return DSInfo{}, false, nil
}
@@ -612,7 +614,8 @@ SELECT
ds.mid_header_rewrite,
ds.regex_remap,
ds.signing_algorithm,
- ds.cacheurl
+ ds.cacheurl,
+ ds.max_origin_connections
FROM
deliveryservice ds
JOIN type tp ON ds.type = tp.id
@@ -620,7 +623,7 @@ WHERE
ds.xml_id = $1
`
di := DSInfo{Name: dsName}
- if err := tx.QueryRow(qry, dsName).Scan(&di.ID, &di.Type,
&di.EdgeHeaderRewrite, &di.MidHeaderRewrite, &di.RegexRemap,
&di.SigningAlgorithm, &di.CacheURL); err != nil {
+ if err := tx.QueryRow(qry, dsName).Scan(&di.ID, &di.Type,
&di.EdgeHeaderRewrite, &di.MidHeaderRewrite, &di.RegexRemap,
&di.SigningAlgorithm, &di.CacheURL, &di.MaxOriginConnections); err != nil {
if err == sql.ErrNoRows {
return DSInfo{}, false, nil
}
diff --git a/traffic_ops/traffic_ops_golang/routing/routes.go
b/traffic_ops/traffic_ops_golang/routing/routes.go
index 3b52b13..999ce4a 100644
--- a/traffic_ops/traffic_ops_golang/routing/routes.go
+++ b/traffic_ops/traffic_ops_golang/routing/routes.go
@@ -378,7 +378,10 @@ func Routes(d ServerData) ([]Route, []RawRoute,
http.Handler, error) {
{1.1, http.MethodPut, `cdns/{id}/snapshot/?$`,
crconfig.SnapshotHandler, auth.PrivLevelOperations, Authenticated, nil},
{1.1, http.MethodPut, `snapshot/{cdn}/?$`,
crconfig.SnapshotHandler, auth.PrivLevelOperations, Authenticated, nil},
+ // ATS config files
{1.1, http.MethodGet,
`cdns/{cdn-name-or-id}/configfiles/ats/regex_revalidate.config/?(\.json)?$`,
ats.GetRegexRevalidateDotConfig, auth.PrivLevelOperations, Authenticated, nil},
+ {1.1, http.MethodGet,
`cdns/{cdn-name-or-id}/configfiles/ats/hdr_rw_mid_{xml-id}.config/?(\.json)?$`,
ats.GetMidHeaderRewriteDotConfig, auth.PrivLevelOperations, Authenticated, nil},
+ {1.1, http.MethodGet,
`cdns/{cdn-name-or-id}/configfiles/ats/hdr_rw_{xml-id}.config/?(\.json)?$`,
ats.GetEdgeHeaderRewriteDotConfig, auth.PrivLevelOperations, Authenticated,
nil},
// Federations
{1.4, http.MethodGet, `federations/all/?(\.json)?$`,
federations.GetAll, auth.PrivLevelAdmin, Authenticated, nil},
@@ -386,16 +389,26 @@ func Routes(d ServerData) ([]Route, []RawRoute,
http.Handler, error) {
{1.1, http.MethodPost,
`federations/{id}/deliveryservices?(\.json)?$`, federations.PostDSes,
auth.PrivLevelAdmin, Authenticated, nil},
////DeliveryServices
+ {1.4, http.MethodGet, `deliveryservices/?(\.json)?$`,
api.ReadHandler(&deliveryservice.TODeliveryServiceV14{}),
auth.PrivLevelReadOnly, Authenticated, nil},
{1.3, http.MethodGet, `deliveryservices/?(\.json)?$`,
api.ReadHandler(&deliveryservice.TODeliveryServiceV13{}),
auth.PrivLevelReadOnly, Authenticated, nil},
{1.1, http.MethodGet, `deliveryservices/?(\.json)?$`,
api.ReadHandler(&deliveryservice.TODeliveryServiceV12{}),
auth.PrivLevelReadOnly, Authenticated, nil},
+
+ {1.4, http.MethodGet, `deliveryservices/{id}/?(\.json)?$`,
api.ReadHandler(&deliveryservice.TODeliveryServiceV14{}),
auth.PrivLevelReadOnly, Authenticated, nil},
{1.3, http.MethodGet, `deliveryservices/{id}/?(\.json)?$`,
api.ReadHandler(&deliveryservice.TODeliveryServiceV13{}),
auth.PrivLevelReadOnly, Authenticated, nil},
{1.1, http.MethodGet, `deliveryservices/{id}/?(\.json)?$`,
api.ReadHandler(&deliveryservice.TODeliveryServiceV12{}),
auth.PrivLevelReadOnly, Authenticated, nil},
+
+ {1.4, http.MethodPost, `deliveryservices/?(\.json)?$`,
deliveryservice.CreateV14, auth.PrivLevelOperations, Authenticated, nil},
{1.3, http.MethodPost, `deliveryservices/?(\.json)?$`,
deliveryservice.CreateV13, auth.PrivLevelOperations, Authenticated, nil},
{1.1, http.MethodPost, `deliveryservices/?(\.json)?$`,
deliveryservice.CreateV12, auth.PrivLevelOperations, Authenticated, nil},
+
+ {1.4, http.MethodPut, `deliveryservices/{id}/?(\.json)?$`,
deliveryservice.UpdateV14, auth.PrivLevelOperations, Authenticated, nil},
{1.3, http.MethodPut, `deliveryservices/{id}/?(\.json)?$`,
deliveryservice.UpdateV13, auth.PrivLevelOperations, Authenticated, nil},
{1.1, http.MethodPut, `deliveryservices/{id}/?(\.json)?$`,
deliveryservice.UpdateV12, auth.PrivLevelOperations, Authenticated, nil},
+
+ {1.4, http.MethodDelete, `deliveryservices/{id}/?(\.json)?$`,
api.DeleteHandler(&deliveryservice.TODeliveryServiceV14{}),
auth.PrivLevelOperations, Authenticated, nil},
{1.3, http.MethodDelete, `deliveryservices/{id}/?(\.json)?$`,
api.DeleteHandler(&deliveryservice.TODeliveryServiceV13{}),
auth.PrivLevelOperations, Authenticated, nil},
{1.1, http.MethodDelete, `deliveryservices/{id}/?(\.json)?$`,
api.DeleteHandler(&deliveryservice.TODeliveryServiceV12{}),
auth.PrivLevelOperations, Authenticated, nil},
+
{1.1, http.MethodGet,
`deliveryservices/{id}/servers/eligible/?(\.json)?$`,
deliveryservice.GetServersEligible, auth.PrivLevelReadOnly, Authenticated, nil},
{1.1, http.MethodGet,
`deliveryservices/xmlId/{xmlid}/sslkeys$`, deliveryservice.GetSSLKeysByXMLID,
auth.PrivLevelAdmin, Authenticated, nil},
diff --git a/traffic_ops/traffic_ops_golang/server/servers.go
b/traffic_ops/traffic_ops_golang/server/servers.go
index b05cf9b..7c564ca 100644
--- a/traffic_ops/traffic_ops_golang/server/servers.go
+++ b/traffic_ops/traffic_ops_golang/server/servers.go
@@ -20,7 +20,6 @@ package server
*/
import (
- "database/sql"
"errors"
"fmt"
"net/http"
@@ -35,6 +34,7 @@ import (
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/auth"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
+
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/deliveryservice"
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/tenant"
"github.com/go-ozzo/ozzo-validation"
"github.com/go-ozzo/ozzo-validation/is"
@@ -192,18 +192,6 @@ func (server *TOServer) Read() ([]interface{}, error,
error, int) {
return returnable, nil, nil, http.StatusOK
}
-// getDeliveryServiceType returns the type of the deliveryservice
-func getDeliveryServiceType(dsID int, tx *sql.Tx) (tc.DSType, error) {
- var dsType tc.DSType
- if err := tx.QueryRow(`SELECT t.name FROM deliveryservice as ds JOIN
type t ON ds.type = t.id WHERE ds.id=$1`, dsID).Scan(&dsType); err != nil {
- if err == sql.ErrNoRows {
- return tc.DSTypeInvalid, errors.New("a deliveryservice
with id '" + strconv.Itoa(dsID) + "' was not found")
- }
- return tc.DSTypeInvalid, errors.New("querying type from
delivery service: " + err.Error())
- }
- return dsType, nil
-}
-
func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser)
([]tc.ServerNullable, []error, tc.ApiErrorType) {
// Query Parameters to Database Query column mappings
// see the fields mapped in the SQL query
@@ -237,7 +225,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user
*auth.CurrentUser) (
FULL OUTER JOIN deliveryservice_server dss ON dss.server = s.id
`
// depending on ds type, also need to add mids
- dsType, err := getDeliveryServiceType(dsID, tx.Tx)
+ dsType, err := deliveryservice.GetDeliveryServiceType(dsID,
tx.Tx)
if err != nil {
return nil, []error{err}, tc.DataConflictError
}
diff --git
a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html
b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html
index 310dc04..a4eac81 100644
---
a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html
+++
b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.DNS.tpl.html
@@ -828,6 +828,20 @@ under the License.
</div>
</div>
+ <div class="form-group" ng-class="{'has-error':
hasError(deliveryServiceForm.maxOriginConnections), 'has-feedback':
hasError(deliveryServiceForm.maxOriginConnections)}">
+ <label class="has-tooltip control-label col-md-2 col-sm-2
col-xs-12" for="maxOriginConnections">Max Origin Connections<div
class="helptooltip">
+ <div class="helptext">
+ The maximum number of connections allowed to the
origin. Enter <code>0</code> to indicate no maximum.
+ </div>
+ </div>
+ </label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input id="maxOriginConnections"
name="maxOriginConnections" type="number" class="form-control"
ng-model="deliveryService.maxOriginConnections" step="1" min="0">
+ <small class="input-diff" ng-if="settings.isRequest"
ng-show="open() && deliveryService.maxOriginConnections !=
dsCurrent.maxOriginConnections">Current Value: [
{{dsCurrent.maxOriginConnections}} ]</small>
+ <span
ng-show="hasError(deliveryServiceForm.maxOriginConnections)"
class="form-control-feedback"><i class="fa fa-times"></i></span>
+ </div>
+ </div>
+
</div>
<div class="modal-footer">
diff --git
a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.HTTP.tpl.html
b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.HTTP.tpl.html
index 550fe67..a038615 100644
---
a/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.HTTP.tpl.html
+++
b/traffic_portal/app/src/common/modules/form/deliveryService/form.deliveryService.HTTP.tpl.html
@@ -856,6 +856,20 @@ under the License.
</div>
</div>
+ <div class="form-group" ng-class="{'has-error':
hasError(deliveryServiceForm.maxOriginConnections), 'has-feedback':
hasError(deliveryServiceForm.maxOriginConnections)}">
+ <label class="has-tooltip control-label col-md-2 col-sm-2
col-xs-12" for="maxOriginConnections">Max Origin Connections<div
class="helptooltip">
+ <div class="helptext">
+ The maximum number of connections allowed to the
origin. Enter <code>0</code> to indicate no maximum.
+ </div>
+ </div>
+ </label>
+ <div class="col-md-10 col-sm-10 col-xs-12">
+ <input id="maxOriginConnections"
name="maxOriginConnections" type="number" class="form-control"
ng-model="deliveryService.maxOriginConnections" step="1" min="0">
+ <small class="input-diff" ng-if="settings.isRequest"
ng-show="open() && deliveryService.maxOriginConnections !=
dsCurrent.maxOriginConnections">Current Value: [
{{dsCurrent.maxOriginConnections}} ]</small>
+ <span
ng-show="hasError(deliveryServiceForm.maxOriginConnections)"
class="form-control-feedback"><i class="fa fa-times"></i></span>
+ </div>
+ </div>
+
<div class="form-group" ng-class="{'has-error':
hasError(deliveryServiceForm.consistentHashRegex), 'has-feedback':
hasError(deliveryServiceForm.consistentHashRegex)}">
<label class="has-tooltip control-label col-md-2 col-sm-2
col-xs-12" for="consistentHashRegex">Consistent Hash Regex<div
class="helptooltip">
<div class="helptext">
diff --git a/traffic_portal/app/src/traffic_portal_properties.json
b/traffic_portal/app/src/traffic_portal_properties.json
index ad493e2..635d109 100644
--- a/traffic_portal/app/src/traffic_portal_properties.json
+++ b/traffic_portal/app/src/traffic_portal_properties.json
@@ -122,6 +122,7 @@
"ipv6RoutingEnabled": true,
"rangeRequestHandling": 0,
"qstringIgnore": 0,
+ "maxOriginConnections": 0,
"multiSiteOrigin": false,
"logsEnabled": false,
"geoProvider": 0,
@@ -140,6 +141,7 @@
"ipv6RoutingEnabled": true,
"rangeRequestHandling": 0,
"qstringIgnore": 0,
+ "maxOriginConnections": 0,
"multiSiteOrigin": false,
"logsEnabled": false,
"initialDispersion": 1,