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

neuman 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 4de0a00  Fix ORT atstccfg to allow using new features in the latest 
Traffic Ops (#4534)
4de0a00 is described below

commit 4de0a001a5b03d066ebf69e8ef0725c14244ef76
Author: Robert O Butts <[email protected]>
AuthorDate: Tue Mar 31 09:36:23 2020 -0600

    Fix ORT atstccfg to allow using new features in the latest Traffic Ops 
(#4534)
    
    * Add ORT atstccfg TO latest version client
    
    Adds a client of the latest Traffic Ops version, and refactors the
    existing vendored client, so both can be used at once.
    
    Includes an idiom of using the latest and falling back to vendored.
    
    Also includes an example of the latest client getting Delivery
    Services, and falling back to the vendored if the TO isn't the latest.
    This isn't actually necessary right now, but it's likely to be very
    shortly, and it serves as an example of the idiom for future dev.
    
    * Add ORT/atstcfg script,readme for updating client
---
 traffic_ops/ort/atstccfg/README.md                 |   8 +
 traffic_ops/ort/atstccfg/atstccfg.go               |   7 +-
 traffic_ops/ort/atstccfg/cfgfile/cfgfile.go        |  41 +--
 traffic_ops/ort/atstccfg/config/config.go          |  12 +-
 traffic_ops/ort/atstccfg/getdata/getdata.go        |  20 +-
 traffic_ops/ort/atstccfg/toreq/toreq.go            | 198 +++++++-------
 traffic_ops/ort/atstccfg/toreq/trafficops.go       | 210 ---------------
 .../github.com/apache/trafficcontrol/LICENSE       |   0
 .../github.com/apache/trafficcontrol/VERSION       |   0
 .../github.com/apache/trafficcontrol/changeset.txt |   0
 .../trafficcontrol/traffic_ops/client/README.md    |   0
 .../trafficcontrol/traffic_ops/client/about.go     |   0
 .../trafficcontrol/traffic_ops/client/asn.go       |   0
 .../trafficcontrol/traffic_ops/client/atsconfig.go |   0
 .../traffic_ops/client/cachegroup.go               |   0
 .../traffic_ops/client/cachegroup_parameters.go    |   0
 .../trafficcontrol/traffic_ops/client/cdn.go       |   0
 .../traffic_ops/client/cdn_domains.go              |   0
 .../traffic_ops/client/cdnfederations.go           |   0
 .../traffic_ops/client/coordinate.go               |   0
 .../trafficcontrol/traffic_ops/client/crconfig.go  |   0
 .../traffic_ops/client/deliveryservice.go          |   0
 .../client/deliveryservice_endpoints.go            |   0
 .../client/deliveryservice_request_comments.go     |   0
 .../traffic_ops/client/deliveryservice_requests.go |   0
 .../deliveryservices_required_capabilities.go      |   0
 .../traffic_ops/client/deliveryserviceserver.go    |   0
 .../trafficcontrol/traffic_ops/client/division.go  |   0
 .../trafficcontrol/traffic_ops/client/dsuser.go    |   0
 .../trafficcontrol/traffic_ops/client/endpoints.go |   0
 .../traffic_ops/client/federation.go               |   0
 .../traffic_ops/client/federation_resolver.go      |   0
 .../trafficcontrol/traffic_ops/client/hardware.go  |   0
 .../trafficcontrol/traffic_ops/client/iso.go       |   0
 .../trafficcontrol/traffic_ops/client/job.go       |   0
 .../trafficcontrol/traffic_ops/client/log.go       |   0
 .../trafficcontrol/traffic_ops/client/origin.go    |   0
 .../trafficcontrol/traffic_ops/client/parameter.go |   0
 .../traffic_ops/client/phys_location.go            |   0
 .../trafficcontrol/traffic_ops/client/ping.go      |   0
 .../trafficcontrol/traffic_ops/client/profile.go   |   0
 .../traffic_ops/client/profile_parameter.go        |   0
 .../trafficcontrol/traffic_ops/client/region.go    |   0
 .../trafficcontrol/traffic_ops/client/role.go      |   0
 .../trafficcontrol/traffic_ops/client/server.go    |   0
 .../client/server_server_capabilities.go           |   0
 .../traffic_ops/client/server_update_status.go     |   0
 .../traffic_ops/client/servercapability.go         |   0
 .../traffic_ops/client/servercheck.go              |   0
 .../traffic_ops/client/serversstatus.go            |   0
 .../trafficcontrol/traffic_ops/client/session.go   |   0
 .../traffic_ops/client/staticdnsentry.go           |   0
 .../traffic_ops/client/stats_summary.go            |   0
 .../trafficcontrol/traffic_ops/client/status.go    |   0
 .../trafficcontrol/traffic_ops/client/steering.go  |   0
 .../traffic_ops/client/steeringtarget.go           |   0
 .../trafficcontrol/traffic_ops/client/tenant.go    |   0
 .../traffic_ops/client/tenant_endpoints.go         |   0
 .../traffic_ops/client/toextension.go              |   0
 .../traffic_ops/client/traffic_monitor.go          |   0
 .../traffic_ops/client/traffic_stats.go            |   0
 .../trafficcontrol/traffic_ops/client/type.go      |   0
 .../trafficcontrol/traffic_ops/client/update.go    |   0
 .../trafficcontrol/traffic_ops/client/user.go      |   0
 .../trafficcontrol/traffic_ops/client/util.go      |   0
 traffic_ops/ort/atstccfg/toreqnew/toreqnew.go      |  97 +++++++
 traffic_ops/ort/atstccfg/torequtil/torequtil.go    |  90 +++++++
 .../ort/atstccfg/torequtil/torequtil_test.go       |  70 +++++
 .../atstccfg/update-to-client/update-to-client.go  | 290 +++++++++++++++++++++
 69 files changed, 706 insertions(+), 337 deletions(-)

diff --git a/traffic_ops/ort/atstccfg/README.md 
b/traffic_ops/ort/atstccfg/README.md
index ddaada3..ccecdc0 100644
--- a/traffic_ops/ort/atstccfg/README.md
+++ b/traffic_ops/ort/atstccfg/README.md
@@ -45,3 +45,11 @@ The available options are:
 -w WARNING_LOCATION, --log-location-warning WARNING_LOCATION    The file 
location to which to log warnings. Respects the special string constants of 
github.com/apache/trafficcontrol/lib/go-log. Default: 'stderr'
 ```
 atstccfg caches generated files in /tmp/atstccfg_cache/ for re-use.
+
+# Development
+
+## Updating for new Traffic Control Versions
+
+After a new Traffic Control release, the Traffic Ops client from the new 
release branch should be vendored at `toreq/vendor`, and all usages of 
`config.TOClientNew` should be changed to `config.TOClient`.
+
+There's a script to do this at 
`ort/atstccfg/update-to-client/update-to-client.go`. Run the script with no 
arguments for usage information.
diff --git a/traffic_ops/ort/atstccfg/atstccfg.go 
b/traffic_ops/ort/atstccfg/atstccfg.go
index 4246aea..ee9ab87 100644
--- a/traffic_ops/ort/atstccfg/atstccfg.go
+++ b/traffic_ops/ort/atstccfg/atstccfg.go
@@ -58,6 +58,7 @@ import (
        "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/getdata"
        "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/plugin"
        "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/toreq"
+       "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/toreqnew"
 )
 
 func main() {
@@ -75,12 +76,16 @@ func main() {
        plugins := plugin.Get(cfg)
        plugins.OnStartup(plugin.StartupData{Cfg: cfg})
 
-       tccfg, err := toreq.GetTCCfg(cfg)
+       toClient, err := toreq.New(cfg.TOURL, cfg.TOUser, cfg.TOPass, 
cfg.TOInsecure, cfg.TOTimeout, config.UserAgent)
        if err != nil {
                log.Errorln(err)
                os.Exit(config.ExitCodeErrGeneric)
        }
 
+       toClientNew, err := toreqnew.New(toClient.Cookies(cfg.TOURL), 
cfg.TOURL, cfg.TOUser, cfg.TOPass, cfg.TOInsecure, cfg.TOTimeout, 
config.UserAgent)
+
+       tccfg := config.TCCfg{Cfg: cfg, TOClient: toClient, TOClientNew: 
toClientNew}
+
        if tccfg.GetData != "" {
                if err := getdata.WriteData(tccfg); err != nil {
                        log.Errorln("writing data: " + err.Error())
diff --git a/traffic_ops/ort/atstccfg/cfgfile/cfgfile.go 
b/traffic_ops/ort/atstccfg/cfgfile/cfgfile.go
index f825301..40b1aaa 100644
--- a/traffic_ops/ort/atstccfg/cfgfile/cfgfile.go
+++ b/traffic_ops/ort/atstccfg/cfgfile/cfgfile.go
@@ -47,7 +47,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
        serversF := func() error {
                defer func(start time.Time) { log.Infof("serversF took %v\n", 
time.Since(start)) }(time.Now())
                // TODO TOAPI add /servers?cdn=1 query param
-               servers, err := toreq.GetServers(cfg)
+               servers, err := cfg.TOClient.GetServers()
                if err != nil {
                        return errors.New("getting servers: " + err.Error())
                }
@@ -69,7 +69,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
 
                sslF := func() error {
                        defer func(start time.Time) { log.Infof("sslF took 
%v\n", time.Since(start)) }(time.Now())
-                       keys, err := toreq.GetCDNSSLKeys(cfg, 
tc.CDNName(server.CDNName))
+                       keys, err := 
cfg.TOClient.GetCDNSSLKeys(tc.CDNName(server.CDNName))
                        if err != nil {
                                return errors.New("getting cdn '" + 
server.CDNName + "': " + err.Error())
                        }
@@ -78,7 +78,12 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
                }
                dsF := func() error {
                        defer func(start time.Time) { log.Infof("dsF took 
%v\n", time.Since(start)) }(time.Now())
-                       dses, err := toreq.GetCDNDeliveryServices(cfg, 
server.CDNID)
+
+                       dses, unsupported, err := 
cfg.TOClientNew.GetCDNDeliveryServices(server.CDNID)
+                       if err == nil && unsupported {
+                               log.Warnln("Traffic Ops newer than ORT, falling 
back to previous API Delivery Services!")
+                               dses, err = 
cfg.TOClient.GetCDNDeliveryServices(server.CDNID)
+                       }
                        if err != nil {
                                return errors.New("getting delivery services: " 
+ err.Error())
                        }
@@ -95,7 +100,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
                                        if ds.SigningAlgorithm == nil || 
*ds.SigningAlgorithm != tc.SigningAlgorithmURISigning {
                                                continue
                                        }
-                                       keys, err := 
toreq.GetURISigningKeys(cfg, *ds.XMLID)
+                                       keys, err := 
cfg.TOClient.GetURISigningKeys(*ds.XMLID)
                                        if err != nil {
                                                if 
strings.Contains(strings.ToLower(err.Error()), "not found") {
                                                        log.Errorln("Delivery 
service '" + *ds.XMLID + "' is uri_signing, but keys were not found! Skipping!")
@@ -121,7 +126,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
                                        if ds.SigningAlgorithm == nil || 
*ds.SigningAlgorithm != tc.SigningAlgorithmURLSig {
                                                continue
                                        }
-                                       keys, err := toreq.GetURLSigKeys(cfg, 
*ds.XMLID)
+                                       keys, err := 
cfg.TOClient.GetURLSigKeys(*ds.XMLID)
                                        if err != nil {
                                                if 
strings.Contains(strings.ToLower(err.Error()), "not found") {
                                                        log.Errorln("Delivery 
service '" + *ds.XMLID + "' is url_sig, but keys were not found! Skipping!: " + 
err.Error())
@@ -144,7 +149,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
                }
                serverParamsF := func() error {
                        defer func(start time.Time) { log.Infof("serverParamsF 
took %v\n", time.Since(start)) }(time.Now())
-                       params, err := toreq.GetServerProfileParameters(cfg, 
server.Profile)
+                       params, err := 
cfg.TOClient.GetServerProfileParameters(server.Profile)
                        if err != nil {
                                return errors.New("getting server profile '" + 
server.Profile + "' parameters: " + err.Error())
                        } else if len(params) == 0 {
@@ -155,7 +160,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
                }
                cdnF := func() error {
                        defer func(start time.Time) { log.Infof("cdnF took 
%v\n", time.Since(start)) }(time.Now())
-                       cdn, err := toreq.GetCDN(cfg, 
tc.CDNName(server.CDNName))
+                       cdn, err := 
cfg.TOClient.GetCDN(tc.CDNName(server.CDNName))
                        if err != nil {
                                return errors.New("getting cdn '" + 
server.CDNName + "': " + err.Error())
                        }
@@ -164,7 +169,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
                }
                profileF := func() error {
                        defer func(start time.Time) { log.Infof("profileF took 
%v\n", time.Since(start)) }(time.Now())
-                       profile, err := toreq.GetProfileByName(cfg, 
server.Profile)
+                       profile, err := 
cfg.TOClient.GetProfileByName(server.Profile)
                        if err != nil {
                                return errors.New("getting profile '" + 
server.Profile + "': " + err.Error())
                        }
@@ -180,7 +185,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
 
        cgF := func() error {
                defer func(start time.Time) { log.Infof("cfF took %v\n", 
time.Since(start)) }(time.Now())
-               cacheGroups, err := toreq.GetCacheGroups(cfg)
+               cacheGroups, err := cfg.TOClient.GetCacheGroups()
                if err != nil {
                        return errors.New("getting cachegroups: " + err.Error())
                }
@@ -189,7 +194,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
        }
        globalParamsF := func() error {
                defer func(start time.Time) { log.Infof("globalParamsF took 
%v\n", time.Since(start)) }(time.Now())
-               globalParams, err := toreq.GetGlobalParameters(cfg)
+               globalParams, err := cfg.TOClient.GetGlobalParameters()
                if err != nil {
                        return errors.New("getting global parameters: " + 
err.Error())
                }
@@ -199,7 +204,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
        }
        scopeParamsF := func() error {
                defer func(start time.Time) { log.Infof("scopeParamsF took 
%v\n", time.Since(start)) }(time.Now())
-               scopeParams, err := toreq.GetParametersByName(cfg, "scope")
+               scopeParams, err := cfg.TOClient.GetParametersByName("scope")
                if err != nil {
                        return errors.New("getting scope parameters: " + 
err.Error())
                }
@@ -208,7 +213,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
        }
        dssF := func() error {
                defer func(start time.Time) { log.Infof("dssF took %v\n", 
time.Since(start)) }(time.Now())
-               dss, err := toreq.GetDeliveryServiceServers(cfg, nil, nil)
+               dss, err := cfg.TOClient.GetDeliveryServiceServers(nil, nil)
                if err != nil {
                        return errors.New("getting delivery service servers: " 
+ err.Error())
                }
@@ -217,7 +222,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
        }
        jobsF := func() error {
                defer func(start time.Time) { log.Infof("jobsF took %v\n", 
time.Since(start)) }(time.Now())
-               jobs, err := toreq.GetJobs(cfg) // TODO add cdn query param to 
jobs endpoint
+               jobs, err := cfg.TOClient.GetJobs() // TODO add cdn query param 
to jobs endpoint
                if err != nil {
                        return errors.New("getting jobs: " + err.Error())
                }
@@ -226,7 +231,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
        }
        capsF := func() error {
                defer func(start time.Time) { log.Infof("capsF took %v\n", 
time.Since(start)) }(time.Now())
-               caps, err := toreq.GetServerCapabilitiesByID(cfg, nil) // TODO 
change to not take a param; it doesn't use it to request TO anyway.
+               caps, err := cfg.TOClient.GetServerCapabilitiesByID(nil) // 
TODO change to not take a param; it doesn't use it to request TO anyway.
                if err != nil {
                        log.Errorln("Server Capabilities error, skipping!")
                        // return errors.New("getting server caps from Traffic 
Ops: " + err.Error())
@@ -237,7 +242,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
        }
        dsCapsF := func() error {
                defer func(start time.Time) { log.Infof("dscapsF took %v\n", 
time.Since(start)) }(time.Now())
-               caps, err := 
toreq.GetDeliveryServiceRequiredCapabilitiesByID(cfg, nil)
+               caps, err := 
cfg.TOClient.GetDeliveryServiceRequiredCapabilitiesByID(nil)
                if err != nil {
                        log.Errorln("DS Required Capabilities error, skipping!")
                        // return errors.New("getting DS required capabilities: 
" + err.Error())
@@ -248,7 +253,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
        }
        dsrF := func() error {
                defer func(start time.Time) { log.Infof("dsrF took %v\n", 
time.Since(start)) }(time.Now())
-               dsr, err := toreq.GetDeliveryServiceRegexes(cfg)
+               dsr, err := cfg.TOClient.GetDeliveryServiceRegexes()
                if err != nil {
                        return errors.New("getting delivery service regexes: " 
+ err.Error())
                }
@@ -257,7 +262,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
        }
        cacheKeyParamsF := func() error {
                defer func(start time.Time) { log.Infof("cacheKeyParamsF took 
%v\n", time.Since(start)) }(time.Now())
-               params, err := toreq.GetConfigFileParameters(cfg, 
atscfg.CacheKeyParameterConfigFile)
+               params, err := 
cfg.TOClient.GetConfigFileParameters(atscfg.CacheKeyParameterConfigFile)
                if err != nil {
                        return errors.New("getting cache key parameters: " + 
err.Error())
                }
@@ -266,7 +271,7 @@ func GetTOData(cfg config.TCCfg) (*config.TOData, error) {
        }
        parentConfigParamsF := func() error {
                defer func(start time.Time) { log.Infof("parentConfigParamsF 
took %v\n", time.Since(start)) }(time.Now())
-               parentConfigParams, err := toreq.GetConfigFileParameters(cfg, 
"parent.config") // TODO make const in lib/go-atscfg
+               parentConfigParams, err := 
cfg.TOClient.GetConfigFileParameters("parent.config") // TODO make const in 
lib/go-atscfg
                if err != nil {
                        return errors.New("getting parent.config parameters: " 
+ err.Error())
                }
diff --git a/traffic_ops/ort/atstccfg/config/config.go 
b/traffic_ops/ort/atstccfg/config/config.go
index f6860cb..1265714 100644
--- a/traffic_ops/ort/atstccfg/config/config.go
+++ b/traffic_ops/ort/atstccfg/config/config.go
@@ -22,7 +22,6 @@ package config
 import (
        "errors"
        "fmt"
-       "math"
        "net/url"
        "os"
        "strings"
@@ -31,7 +30,8 @@ import (
        "github.com/apache/trafficcontrol/lib/go-atscfg"
        "github.com/apache/trafficcontrol/lib/go-log"
        "github.com/apache/trafficcontrol/lib/go-tc"
-       toclient "github.com/apache/trafficcontrol/traffic_ops/client"
+       "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/toreq"
+       "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/toreqnew"
 
        flag "github.com/ogier/pflag"
 )
@@ -68,7 +68,8 @@ type Cfg struct {
 
 type TCCfg struct {
        Cfg
-       TOClient **toclient.Session
+       TOClient    *toreq.TOClient
+       TOClientNew *toreqnew.TOClient
 }
 
 func (cfg Cfg) ErrorLog() log.LogLocation   { return 
log.LogLocation(cfg.LogLocationErr) }
@@ -194,11 +195,6 @@ func ValidateURL(u *url.URL) error {
        return nil
 }
 
-func RetryBackoffSeconds(currentRetry int) int {
-       // TODO make configurable?
-       return int(math.Pow(2.0, float64(currentRetry)))
-}
-
 type ATSConfigFile struct {
        tc.ATSConfigMetaDataConfigFile
        Text        string
diff --git a/traffic_ops/ort/atstccfg/getdata/getdata.go 
b/traffic_ops/ort/atstccfg/getdata/getdata.go
index cae65c3..3923e73 100644
--- a/traffic_ops/ort/atstccfg/getdata/getdata.go
+++ b/traffic_ops/ort/atstccfg/getdata/getdata.go
@@ -35,7 +35,6 @@ import (
        "github.com/apache/trafficcontrol/lib/go-log"
        "github.com/apache/trafficcontrol/lib/go-tc"
        "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/config"
-       "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/toreq"
 )
 
 func GetDataFuncs() map[string]func(config.TCCfg, io.Writer) error {
@@ -83,7 +82,7 @@ const SystemInfoParamConfigFile = `global`
 // This is identical to the /api/1.x/system/info endpoint, except it does not 
include a '{response: {parameters:' wrapper.
 //
 func WriteSystemInfo(cfg config.TCCfg, output io.Writer) error {
-       paramArr, err := toreq.GetConfigFileParameters(cfg, 
SystemInfoParamConfigFile)
+       paramArr, err := 
cfg.TOClient.GetConfigFileParameters(SystemInfoParamConfigFile)
        if err != nil {
                return errors.New("getting system info parameters: " + 
err.Error())
        }
@@ -100,7 +99,7 @@ func WriteSystemInfo(cfg config.TCCfg, output io.Writer) 
error {
 // WriteStatuses writes the Traffic Ops statuses to output.
 // Note this is identical to /api/1.x/statuses except it omits the 
'{response:' wrapper.
 func WriteStatuses(cfg config.TCCfg, output io.Writer) error {
-       statuses, err := toreq.GetStatuses(cfg)
+       statuses, err := cfg.TOClient.GetStatuses()
        if err != nil {
                return errors.New("getting statuses: " + err.Error())
        }
@@ -113,7 +112,7 @@ func WriteStatuses(cfg config.TCCfg, output io.Writer) 
error {
 // WriteUpdateStatus writes the Traffic Ops server update status to output.
 // Note this is identical to /api/1.x/servers/name/update_status except it 
omits the '[]' wrapper.
 func WriteServerUpdateStatus(cfg config.TCCfg, output io.Writer) error {
-       status, err := toreq.GetServerUpdateStatus(cfg)
+       status, err := 
cfg.TOClient.GetServerUpdateStatus(tc.CacheName(cfg.CacheHostName))
        if err != nil {
                return errors.New("getting server update status: " + 
err.Error())
        }
@@ -137,11 +136,11 @@ func WritePackages(cfg config.TCCfg, output io.Writer) 
error {
 }
 
 func GetPackages(cfg config.TCCfg) ([]atscfg.Package, error) {
-       server, err := toreq.GetServerByHostName(cfg, string(cfg.CacheHostName))
+       server, err := 
cfg.TOClient.GetServerByHostName(string(cfg.CacheHostName))
        if err != nil {
                return nil, errors.New("getting server: " + err.Error())
        }
-       params, err := toreq.GetServerProfileParameters(cfg, server.Profile)
+       params, err := cfg.TOClient.GetServerProfileParameters(server.Profile)
        if err != nil {
                return nil, errors.New("getting server profile '" + 
server.Profile + "' parameters: " + err.Error())
        }
@@ -169,11 +168,11 @@ func WriteChkconfig(cfg config.TCCfg, output io.Writer) 
error {
 }
 
 func GetChkconfig(cfg config.TCCfg) ([]atscfg.ChkConfigEntry, error) {
-       server, err := toreq.GetServerByHostName(cfg, string(cfg.CacheHostName))
+       server, err := 
cfg.TOClient.GetServerByHostName(string(cfg.CacheHostName))
        if err != nil {
                return nil, errors.New("getting server: " + err.Error())
        }
-       params, err := toreq.GetServerProfileParameters(cfg, server.Profile)
+       params, err := cfg.TOClient.GetServerProfileParameters(server.Profile)
        if err != nil {
                return nil, errors.New("getting server profile '" + 
server.Profile + "' parameters: " + err.Error())
        }
@@ -191,8 +190,9 @@ func GetChkconfig(cfg config.TCCfg) 
([]atscfg.ChkConfigEntry, error) {
 func SetUpdateStatus(cfg config.TCCfg, serverName tc.CacheName, queue bool, 
revalPending bool) error {
        // TODO change this to an API path, when one exists
        path := `/update/` + string(serverName) + `?updated=` + 
jsonBoolStr(queue) + `&reval_updated=` + jsonBoolStr(revalPending)
-       // RawRequest should generally never be used, but the alternatve here 
is to manually get the cookie and do an http.Get. We need to hit a non-API 
endpoint, no API endpoint exists for what we need.
-       resp, _, err := (*cfg.TOClient).RawRequest(http.MethodPost, path, nil)
+       // C and RawRequest should generally never be used, but the alternatve 
here is to manually get the cookie and do an http.Get. We need to hit a non-API 
endpoint, no API endpoint exists for what we need.
+       // TODO move to a func in TOClient?
+       resp, _, err := cfg.TOClient.C.RawRequest(http.MethodPost, path, nil)
        if err != nil {
                return errors.New("setting update statuses: " + err.Error())
        }
diff --git a/traffic_ops/ort/atstccfg/toreq/toreq.go 
b/traffic_ops/ort/atstccfg/toreq/toreq.go
index 7262dd8..69f74c4 100644
--- a/traffic_ops/ort/atstccfg/toreq/toreq.go
+++ b/traffic_ops/ort/atstccfg/toreq/toreq.go
@@ -1,3 +1,9 @@
+// toreqnew implements a Traffic Ops client vendored one version back.
+//
+// This should be used for all requests, unless they require an endpoint or 
field added in the latest version.
+//
+// If a feature in the latest Traffic Ops is required, toreqnew should be used 
with a fallback to this client if the Traffic Ops is not the latest (which can 
be determined by the bool returned by all toreqnew.TOClient funcs).
+//
 package toreq
 
 /*
@@ -22,22 +28,61 @@ package toreq
 import (
        "encoding/base64"
        "errors"
+       "net"
+       "net/url"
        "strconv"
-       "strings"
        "time"
 
        "github.com/apache/trafficcontrol/lib/go-atscfg"
        "github.com/apache/trafficcontrol/lib/go-log"
        "github.com/apache/trafficcontrol/lib/go-tc"
        "github.com/apache/trafficcontrol/lib/go-util"
-       "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/config"
+       toclient "github.com/apache/trafficcontrol/traffic_ops/client"
+       "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/torequtil"
 )
 
-func GetProfileByName(cfg config.TCCfg, profileName string) (tc.Profile, 
error) {
+type TOClient struct {
+       C          *toclient.Session
+       NumRetries int
+}
+
+// New logs into Traffic Ops, returning the TOClient which contains the 
logged-in client.
+func New(url *url.URL, user string, pass string, insecure bool, timeout 
time.Duration, userAgent string) (*TOClient, error) {
+       log.Infoln("URL: '" + url.String() + "' User: '" + user + "' Pass len: 
'" + strconv.Itoa(len(pass)) + "'")
+
+       toFQDN := url.Scheme + "://" + url.Host
+       log.Infoln("TO FQDN: '" + toFQDN + "'")
+       log.Infoln("TO URL: '" + url.String() + "'")
+
+       toClient, toIP, err := toclient.LoginWithAgent(toFQDN, user, pass, 
insecure, userAgent, false, timeout)
+       if err != nil {
+               return nil, errors.New("Logging in to Traffic Ops '" + 
MaybeIPStr(toIP) + "': " + err.Error())
+       }
+
+       return &TOClient{C: toClient}, nil
+}
+
+// Cookies returns the HTTP session cookies from the client.
+// It does not do any kind of validation, but assumes the HTTP cookies exist 
from a prior login and are valid for a Traffic Ops session.
+// The url is the Traffic Ops URL, and should match this client's Traffic Ops 
URL, and the URL of the new client this session cookie is presumably being 
fetched for.
+func (cl *TOClient) Cookies(url *url.URL) string {
+       return torequtil.CookiesToString(cl.C.Client.Jar.Cookies(url))
+}
+
+// MaybeIPStr returns the addr string if it isn't nil, or the empty string if 
it is.
+// This is intended for logging, to allow logging with one line, whether addr 
is nil or not.
+func MaybeIPStr(addr net.Addr) string {
+       if addr != nil {
+               return addr.String()
+       }
+       return ""
+}
+
+func (cl *TOClient) GetProfileByName(profileName string) (tc.Profile, error) {
        profile := tc.Profile{}
 
-       err := GetRetry(cfg, "profile_"+profileName, &profile, func(obj 
interface{}) error {
-               toProfiles, reqInf, err := 
(*cfg.TOClient).GetProfileByName(profileName)
+       err := torequtil.GetRetry(cl.NumRetries, "profile_"+profileName, 
&profile, func(obj interface{}) error {
+               toProfiles, reqInf, err := cl.C.GetProfileByName(profileName)
                if err != nil {
                        return errors.New("getting profile '" + profileName + 
"' from Traffic Ops '" + MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -56,10 +101,10 @@ func GetProfileByName(cfg config.TCCfg, profileName 
string) (tc.Profile, error)
        return profile, nil
 }
 
-func GetGlobalParameters(cfg config.TCCfg) ([]tc.Parameter, error) {
+func (cl *TOClient) GetGlobalParameters() ([]tc.Parameter, error) {
        globalParams := []tc.Parameter{}
-       err := GetRetry(cfg, "profile_global_parameters", &globalParams, 
func(obj interface{}) error {
-               toParams, reqInf, err := 
(*cfg.TOClient).GetParametersByProfileName(tc.GlobalProfileName)
+       err := torequtil.GetRetry(cl.NumRetries, "profile_global_parameters", 
&globalParams, func(obj interface{}) error {
+               toParams, reqInf, err := 
cl.C.GetParametersByProfileName(tc.GlobalProfileName)
                if err != nil {
                        return errors.New("getting global profile '" + 
tc.GlobalProfileName + "' parameters from Traffic Ops '" + 
MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -74,6 +119,7 @@ func GetGlobalParameters(cfg config.TCCfg) ([]tc.Parameter, 
error) {
 }
 
 func GetTOToolNameAndURL(globalParams []tc.Parameter) (string, string) {
+       // TODO move somewhere generic
        toToolName := ""
        toURL := ""
        for _, param := range globalParams {
@@ -96,10 +142,10 @@ func GetTOToolNameAndURL(globalParams []tc.Parameter) 
(string, string) {
        return toToolName, toURL
 }
 
-func GetServers(cfg config.TCCfg) ([]tc.Server, error) {
+func (cl *TOClient) GetServers() ([]tc.Server, error) {
        servers := []tc.Server{}
-       err := GetRetry(cfg, "servers", &servers, func(obj interface{}) error {
-               toServers, reqInf, err := (*cfg.TOClient).GetServers()
+       err := torequtil.GetRetry(cl.NumRetries, "servers", &servers, func(obj 
interface{}) error {
+               toServers, reqInf, err := cl.C.GetServers()
                if err != nil {
                        return errors.New("getting servers from Traffic Ops '" 
+ MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -113,10 +159,10 @@ func GetServers(cfg config.TCCfg) ([]tc.Server, error) {
        return servers, nil
 }
 
-func GetServerByHostName(cfg config.TCCfg, serverHostName string) (tc.Server, 
error) {
+func (cl *TOClient) GetServerByHostName(serverHostName string) (tc.Server, 
error) {
        server := tc.Server{}
-       err := GetRetry(cfg, "server-name-"+serverHostName, &server, func(obj 
interface{}) error {
-               toServers, reqInf, err := 
(*cfg.TOClient).GetServerByHostName(serverHostName)
+       err := torequtil.GetRetry(cl.NumRetries, "server-name-"+serverHostName, 
&server, func(obj interface{}) error {
+               toServers, reqInf, err := 
cl.C.GetServerByHostName(serverHostName)
                if err != nil {
                        return errors.New("getting server name '" + 
serverHostName + "' from Traffic Ops '" + MaybeIPStr(reqInf.RemoteAddr) + "': " 
+ err.Error())
                } else if len(toServers) < 1 {
@@ -132,10 +178,10 @@ func GetServerByHostName(cfg config.TCCfg, serverHostName 
string) (tc.Server, er
        return server, nil
 }
 
-func GetCacheGroups(cfg config.TCCfg) ([]tc.CacheGroupNullable, error) {
+func (cl *TOClient) GetCacheGroups() ([]tc.CacheGroupNullable, error) {
        cacheGroups := []tc.CacheGroupNullable{}
-       err := GetRetry(cfg, "cachegroups", &cacheGroups, func(obj interface{}) 
error {
-               toCacheGroups, reqInf, err := 
(*cfg.TOClient).GetCacheGroupsNullable()
+       err := torequtil.GetRetry(cl.NumRetries, "cachegroups", &cacheGroups, 
func(obj interface{}) error {
+               toCacheGroups, reqInf, err := cl.C.GetCacheGroupsNullable()
                if err != nil {
                        return errors.New("getting cachegroups from Traffic Ops 
'" + MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -154,7 +200,7 @@ func GetCacheGroups(cfg config.TCCfg) 
([]tc.CacheGroupNullable, error) {
 // If your use case is more efficient to only get the needed objects, for 
example if you're frequently requesting one file, set this false to get and 
cache the specific needed delivery services and servers.
 const DeliveryServiceServersAlwaysGetAll = true
 
-func GetDeliveryServiceServers(cfg config.TCCfg, dsIDs []int, serverIDs []int) 
([]tc.DeliveryServiceServer, error) {
+func (cl *TOClient) GetDeliveryServiceServers(dsIDs []int, serverIDs []int) 
([]tc.DeliveryServiceServer, error) {
        const sortIDsInHash = true
 
        serverIDsStr := ""
@@ -173,9 +219,9 @@ func GetDeliveryServiceServers(cfg config.TCCfg, dsIDs 
[]int, serverIDs []int) (
        }
 
        dsServers := []tc.DeliveryServiceServer{}
-       err := GetRetry(cfg, 
"deliveryservice_servers_s"+serverIDsStr+"_d_"+dsIDsStr, &dsServers, func(obj 
interface{}) error {
+       err := torequtil.GetRetry(cl.NumRetries, 
"deliveryservice_servers_s"+serverIDsStr+"_d_"+dsIDsStr, &dsServers, func(obj 
interface{}) error {
                const noLimit = 999999 // TODO add "no limit" param to DSS 
endpoint
-               toDSS, reqInf, err := 
(*cfg.TOClient).GetDeliveryServiceServersWithLimits(noLimit, dsIDsToFetch, 
sIDsToFetch)
+               toDSS, reqInf, err := 
cl.C.GetDeliveryServiceServersWithLimits(noLimit, dsIDsToFetch, sIDsToFetch)
                if err != nil {
                        return errors.New("getting delivery service servers 
from Traffic Ops '" + MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -219,10 +265,10 @@ func GetDeliveryServiceServers(cfg config.TCCfg, dsIDs 
[]int, serverIDs []int) (
        return filteredDSServers, nil
 }
 
-func GetServerProfileParameters(cfg config.TCCfg, profileName string) 
([]tc.Parameter, error) {
+func (cl *TOClient) GetServerProfileParameters(profileName string) 
([]tc.Parameter, error) {
        serverProfileParameters := []tc.Parameter{}
-       err := GetRetry(cfg, "profile_"+profileName+"_parameters", 
&serverProfileParameters, func(obj interface{}) error {
-               toParams, reqInf, err := 
(*cfg.TOClient).GetParametersByProfileName(profileName)
+       err := torequtil.GetRetry(cl.NumRetries, 
"profile_"+profileName+"_parameters", &serverProfileParameters, func(obj 
interface{}) error {
+               toParams, reqInf, err := 
cl.C.GetParametersByProfileName(profileName)
                if err != nil {
                        return errors.New("getting server profile '" + 
profileName + "' parameters from Traffic Ops '" + MaybeIPStr(reqInf.RemoteAddr) 
+ "': " + err.Error())
                }
@@ -236,10 +282,10 @@ func GetServerProfileParameters(cfg config.TCCfg, 
profileName string) ([]tc.Para
        return serverProfileParameters, nil
 }
 
-func GetCDNDeliveryServices(cfg config.TCCfg, cdnID int) 
([]tc.DeliveryServiceNullable, error) {
+func (cl *TOClient) GetCDNDeliveryServices(cdnID int) 
([]tc.DeliveryServiceNullable, error) {
        deliveryServices := []tc.DeliveryServiceNullable{}
-       err := GetRetry(cfg, "cdn_"+strconv.Itoa(cdnID)+"_deliveryservices", 
&deliveryServices, func(obj interface{}) error {
-               toDSes, reqInf, err := 
(*cfg.TOClient).GetDeliveryServicesByCDNID(cdnID)
+       err := torequtil.GetRetry(cl.NumRetries, 
"cdn_"+strconv.Itoa(cdnID)+"_deliveryservices", &deliveryServices, func(obj 
interface{}) error {
+               toDSes, reqInf, err := cl.C.GetDeliveryServicesByCDNID(cdnID)
                if err != nil {
                        return errors.New("getting delivery services from 
Traffic Ops '" + MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -253,10 +299,10 @@ func GetCDNDeliveryServices(cfg config.TCCfg, cdnID int) 
([]tc.DeliveryServiceNu
        return deliveryServices, nil
 }
 
-func GetConfigFileParameters(cfg config.TCCfg, configFile string) 
([]tc.Parameter, error) {
+func (cl *TOClient) GetConfigFileParameters(configFile string) 
([]tc.Parameter, error) {
        params := []tc.Parameter{}
-       err := GetRetry(cfg, "config_file_"+configFile+"_parameters", &params, 
func(obj interface{}) error {
-               toParams, reqInf, err := 
(*cfg.TOClient).GetParameterByConfigFile(configFile)
+       err := torequtil.GetRetry(cl.NumRetries, 
"config_file_"+configFile+"_parameters", &params, func(obj interface{}) error {
+               toParams, reqInf, err := 
cl.C.GetParameterByConfigFile(configFile)
                if err != nil {
                        return errors.New("getting delivery services from 
Traffic Ops '" + MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -270,10 +316,10 @@ func GetConfigFileParameters(cfg config.TCCfg, configFile 
string) ([]tc.Paramete
        return params, nil
 }
 
-func GetCDN(cfg config.TCCfg, cdnName tc.CDNName) (tc.CDN, error) {
+func (cl *TOClient) GetCDN(cdnName tc.CDNName) (tc.CDN, error) {
        cdn := tc.CDN{}
-       err := GetRetry(cfg, "cdn_"+string(cdnName), &cdn, func(obj 
interface{}) error {
-               toCDNs, reqInf, err := 
(*cfg.TOClient).GetCDNByName(string(cdnName))
+       err := torequtil.GetRetry(cl.NumRetries, "cdn_"+string(cdnName), &cdn, 
func(obj interface{}) error {
+               toCDNs, reqInf, err := cl.C.GetCDNByName(string(cdnName))
                if err != nil {
                        return errors.New("getting cdn from Traffic Ops '" + 
MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -290,10 +336,10 @@ func GetCDN(cfg config.TCCfg, cdnName tc.CDNName) 
(tc.CDN, error) {
        return cdn, nil
 }
 
-func GetURLSigKeys(cfg config.TCCfg, dsName string) (tc.URLSigKeys, error) {
+func (cl *TOClient) GetURLSigKeys(dsName string) (tc.URLSigKeys, error) {
        keys := tc.URLSigKeys{}
-       err := GetRetry(cfg, "urlsigkeys_"+string(dsName), &keys, func(obj 
interface{}) error {
-               toKeys, reqInf, err := 
(*cfg.TOClient).GetDeliveryServiceURLSigKeys(dsName)
+       err := torequtil.GetRetry(cl.NumRetries, "urlsigkeys_"+string(dsName), 
&keys, func(obj interface{}) error {
+               toKeys, reqInf, err := cl.C.GetDeliveryServiceURLSigKeys(dsName)
                if err != nil {
                        return errors.New("getting url sig keys from Traffic 
Ops '" + MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -307,10 +353,10 @@ func GetURLSigKeys(cfg config.TCCfg, dsName string) 
(tc.URLSigKeys, error) {
        return keys, nil
 }
 
-func GetURISigningKeys(cfg config.TCCfg, dsName string) ([]byte, error) {
+func (cl *TOClient) GetURISigningKeys(dsName string) ([]byte, error) {
        keys := []byte{}
-       err := GetRetry(cfg, "urisigningkeys_"+string(dsName), &keys, func(obj 
interface{}) error {
-               toKeys, reqInf, err := 
(*cfg.TOClient).GetDeliveryServiceURISigningKeys(dsName)
+       err := torequtil.GetRetry(cl.NumRetries, 
"urisigningkeys_"+string(dsName), &keys, func(obj interface{}) error {
+               toKeys, reqInf, err := 
cl.C.GetDeliveryServiceURISigningKeys(dsName)
                if err != nil {
                        return errors.New("getting url sig keys from Traffic 
Ops '" + MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -325,10 +371,10 @@ func GetURISigningKeys(cfg config.TCCfg, dsName string) 
([]byte, error) {
        return keys, nil
 }
 
-func GetParametersByName(cfg config.TCCfg, paramName string) ([]tc.Parameter, 
error) {
+func (cl *TOClient) GetParametersByName(paramName string) ([]tc.Parameter, 
error) {
        params := []tc.Parameter{}
-       err := GetRetry(cfg, "parameters_name_"+paramName, &params, func(obj 
interface{}) error {
-               toParams, reqInf, err := 
(*cfg.TOClient).GetParameterByName(paramName)
+       err := torequtil.GetRetry(cl.NumRetries, "parameters_name_"+paramName, 
&params, func(obj interface{}) error {
+               toParams, reqInf, err := cl.C.GetParameterByName(paramName)
                if err != nil {
                        return errors.New("getting parameters name '" + 
paramName + "' from Traffic Ops '" + MaybeIPStr(reqInf.RemoteAddr) + "': " + 
err.Error())
                }
@@ -342,10 +388,10 @@ func GetParametersByName(cfg config.TCCfg, paramName 
string) ([]tc.Parameter, er
        return params, nil
 }
 
-func GetDeliveryServiceRegexes(cfg config.TCCfg) ([]tc.DeliveryServiceRegexes, 
error) {
+func (cl *TOClient) GetDeliveryServiceRegexes() ([]tc.DeliveryServiceRegexes, 
error) {
        regexes := []tc.DeliveryServiceRegexes{}
-       err := GetRetry(cfg, "ds_regexes", &regexes, func(obj interface{}) 
error {
-               toRegexes, reqInf, err := 
(*cfg.TOClient).GetDeliveryServiceRegexes()
+       err := torequtil.GetRetry(cl.NumRetries, "ds_regexes", &regexes, 
func(obj interface{}) error {
+               toRegexes, reqInf, err := cl.C.GetDeliveryServiceRegexes()
                if err != nil {
                        return errors.New("getting ds regexes from Traffic Ops 
'" + MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -359,10 +405,10 @@ func GetDeliveryServiceRegexes(cfg config.TCCfg) 
([]tc.DeliveryServiceRegexes, e
        return regexes, nil
 }
 
-func GetJobs(cfg config.TCCfg) ([]tc.Job, error) {
+func (cl *TOClient) GetJobs() ([]tc.Job, error) {
        jobs := []tc.Job{}
-       err := GetRetry(cfg, "jobs", &jobs, func(obj interface{}) error {
-               toJobs, reqInf, err := (*cfg.TOClient).GetJobs(nil, nil)
+       err := torequtil.GetRetry(cl.NumRetries, "jobs", &jobs, func(obj 
interface{}) error {
+               toJobs, reqInf, err := cl.C.GetJobs(nil, nil)
                if err != nil {
                        return errors.New("getting jobs from Traffic Ops '" + 
MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -376,7 +422,7 @@ func GetJobs(cfg config.TCCfg) ([]tc.Job, error) {
        return jobs, nil
 }
 
-func GetServerCapabilitiesByID(cfg config.TCCfg, serverIDs []int) 
(map[int]map[atscfg.ServerCapability]struct{}, error) {
+func (cl *TOClient) GetServerCapabilitiesByID(serverIDs []int) 
(map[int]map[atscfg.ServerCapability]struct{}, error) {
        serverIDsStr := ""
        if len(serverIDs) > 0 {
                sortIDsInHash := true
@@ -384,9 +430,9 @@ func GetServerCapabilitiesByID(cfg config.TCCfg, serverIDs 
[]int) (map[int]map[a
        }
 
        serverCaps := map[int]map[atscfg.ServerCapability]struct{}{}
-       err := GetRetry(cfg, "server_capabilities_s_"+serverIDsStr, 
&serverCaps, func(obj interface{}) error {
+       err := torequtil.GetRetry(cl.NumRetries, 
"server_capabilities_s_"+serverIDsStr, &serverCaps, func(obj interface{}) error 
{
                // TODO add list of IDs to API+Client
-               toServerCaps, reqInf, err := 
(*cfg.TOClient).GetServerServerCapabilities(nil, nil, nil)
+               toServerCaps, reqInf, err := 
cl.C.GetServerServerCapabilities(nil, nil, nil)
                if err != nil {
                        return errors.New("getting server caps from Traffic Ops 
'" + MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -412,7 +458,7 @@ func GetServerCapabilitiesByID(cfg config.TCCfg, serverIDs 
[]int) (map[int]map[a
        return serverCaps, nil
 }
 
-func GetDeliveryServiceRequiredCapabilitiesByID(cfg config.TCCfg, dsIDs []int) 
(map[int]map[atscfg.ServerCapability]struct{}, error) {
+func (cl *TOClient) GetDeliveryServiceRequiredCapabilitiesByID(dsIDs []int) 
(map[int]map[atscfg.ServerCapability]struct{}, error) {
        dsIDsStr := ""
        if len(dsIDs) > 0 {
                sortIDsInHash := true
@@ -420,9 +466,9 @@ func GetDeliveryServiceRequiredCapabilitiesByID(cfg 
config.TCCfg, dsIDs []int) (
        }
 
        dsCaps := map[int]map[atscfg.ServerCapability]struct{}{}
-       err := GetRetry(cfg, "ds_capabilities_d_"+dsIDsStr, &dsCaps, func(obj 
interface{}) error {
+       err := torequtil.GetRetry(cl.NumRetries, "ds_capabilities_d_"+dsIDsStr, 
&dsCaps, func(obj interface{}) error {
                // TODO add list of IDs to API+Client
-               toDSCaps, reqInf, err := 
(*cfg.TOClient).GetDeliveryServicesRequiredCapabilities(nil, nil, nil)
+               toDSCaps, reqInf, err := 
cl.C.GetDeliveryServicesRequiredCapabilities(nil, nil, nil)
                if err != nil {
                        return errors.New("getting ds caps from Traffic Ops '" 
+ MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -448,10 +494,10 @@ func GetDeliveryServiceRequiredCapabilitiesByID(cfg 
config.TCCfg, dsIDs []int) (
        return dsCaps, nil
 }
 
-func GetCDNSSLKeys(cfg config.TCCfg, cdnName tc.CDNName) ([]tc.CDNSSLKeys, 
error) {
+func (cl *TOClient) GetCDNSSLKeys(cdnName tc.CDNName) ([]tc.CDNSSLKeys, error) 
{
        keys := []tc.CDNSSLKeys{}
-       err := GetRetry(cfg, "cdn_sslkeys_"+string(cdnName), &keys, func(obj 
interface{}) error {
-               toKeys, reqInf, err := 
(*cfg.TOClient).GetCDNSSLKeys(string(cdnName))
+       err := torequtil.GetRetry(cl.NumRetries, 
"cdn_sslkeys_"+string(cdnName), &keys, func(obj interface{}) error {
+               toKeys, reqInf, err := cl.C.GetCDNSSLKeys(string(cdnName))
                if err != nil {
                        return errors.New("getting cdn ssl keys from Traffic 
Ops '" + MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -465,10 +511,10 @@ func GetCDNSSLKeys(cfg config.TCCfg, cdnName tc.CDNName) 
([]tc.CDNSSLKeys, error
        return keys, nil
 }
 
-func GetStatuses(cfg config.TCCfg) ([]tc.Status, error) {
+func (cl *TOClient) GetStatuses() ([]tc.Status, error) {
        statuses := []tc.Status{}
-       err := GetRetry(cfg, "statuses", &statuses, func(obj interface{}) error 
{
-               toStatus, reqInf, err := (*cfg.TOClient).GetStatuses()
+       err := torequtil.GetRetry(cl.NumRetries, "statuses", &statuses, 
func(obj interface{}) error {
+               toStatus, reqInf, err := cl.C.GetStatuses()
                if err != nil {
                        return errors.New("getting server update status from 
Traffic Ops '" + MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -482,10 +528,10 @@ func GetStatuses(cfg config.TCCfg) ([]tc.Status, error) {
        return statuses, nil
 }
 
-func GetServerUpdateStatus(cfg config.TCCfg) (tc.ServerUpdateStatus, error) {
+func (cl *TOClient) GetServerUpdateStatus(cacheHostName tc.CacheName) 
(tc.ServerUpdateStatus, error) {
        status := tc.ServerUpdateStatus{}
-       err := GetRetry(cfg, "server_update_status_"+string(cfg.CacheHostName), 
&status, func(obj interface{}) error {
-               toStatus, reqInf, err := 
(*cfg.TOClient).GetServerUpdateStatus(string(cfg.CacheHostName))
+       err := torequtil.GetRetry(cl.NumRetries, 
"server_update_status_"+string(cacheHostName), &status, func(obj interface{}) 
error {
+               toStatus, reqInf, err := 
cl.C.GetServerUpdateStatus(string(cacheHostName))
                if err != nil {
                        return errors.New("getting server update status from 
Traffic Ops '" + MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
                }
@@ -498,31 +544,3 @@ func GetServerUpdateStatus(cfg config.TCCfg) 
(tc.ServerUpdateStatus, error) {
        }
        return status, nil
 }
-
-// GetRetry attempts to get the given object from tempDir/cacheFileName, 
retrying with exponential backoff up to cfg.NumRetries.
-// The cacheFileName is not used in actual fetching or logic, but only for 
logging. It can be any printable string, but should be unique and reflect the 
object being fetched.
-func GetRetry(cfg config.TCCfg, cacheFileName string, obj interface{}, getter 
func(obj interface{}) error) error {
-       start := time.Now()
-       currentRetry := 0
-       for {
-               err := getter(obj)
-               if err == nil {
-                       break
-               }
-               if strings.Contains(strings.ToLower(err.Error()), "not found") {
-                       // if the server returned a 404, retrying won't help
-                       return errors.New("getting uncached: " + err.Error())
-               }
-               if currentRetry == cfg.NumRetries {
-                       return errors.New("getting uncached: " + err.Error())
-               }
-
-               sleepSeconds := config.RetryBackoffSeconds(currentRetry)
-               log.Warnf("getting '%v', sleeping for %v seconds: %v\n", 
cacheFileName, sleepSeconds, err)
-               currentRetry++
-               time.Sleep(time.Second * time.Duration(sleepSeconds)) // TODO 
make backoff configurable?
-       }
-
-       log.Infof("GetRetry %v retries %v took %v\n", cacheFileName, 
currentRetry, time.Since(start).Round(time.Millisecond))
-       return nil
-}
diff --git a/traffic_ops/ort/atstccfg/toreq/trafficops.go 
b/traffic_ops/ort/atstccfg/toreq/trafficops.go
deleted file mode 100644
index 983a901..0000000
--- a/traffic_ops/ort/atstccfg/toreq/trafficops.go
+++ /dev/null
@@ -1,210 +0,0 @@
-package toreq
-
-/*
- * 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 (
-       "bytes"
-       "crypto/sha512"
-       "encoding/base64"
-       "errors"
-       "io"
-       "io/ioutil"
-       "net"
-       "net/http"
-       "net/http/httptrace"
-       "strconv"
-       "time"
-
-       "github.com/apache/trafficcontrol/lib/go-log"
-       toclient "github.com/apache/trafficcontrol/traffic_ops/client"
-       "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/config"
-)
-
-// GetTCCfg takes the config.Cfg and logs into Traffic Ops, returning the 
TCCfg which contains the logged-in client.
-func GetTCCfg(cfg config.Cfg) (config.TCCfg, error) {
-       log.Infoln("URL: '" + cfg.TOURL.String() + "' User: '" + cfg.TOUser + 
"' Pass len: '" + strconv.Itoa(len(cfg.TOPass)) + "'")
-
-       toFQDN := cfg.TOURL.Scheme + "://" + cfg.TOURL.Host
-       log.Infoln("TO FQDN: '" + toFQDN + "'")
-       log.Infoln("TO URL: '" + cfg.TOURL.String() + "'")
-
-       toClient, toIP, err := toclient.LoginWithAgent(toFQDN, cfg.TOUser, 
cfg.TOPass, cfg.TOInsecure, config.UserAgent, false, cfg.TOTimeout)
-       if err != nil {
-               return config.TCCfg{}, errors.New("Logging in to Traffic Ops '" 
+ MaybeIPStr(toIP) + "': " + err.Error())
-       }
-
-       return config.TCCfg{Cfg: cfg, TOClient: &toClient}, nil
-}
-
-// TrafficOpsRequest makes a request to Traffic Ops for the given method, url, 
and body.
-// If it gets an Unauthorized or Forbidden, it tries to log in again and makes 
the request again.
-func TrafficOpsRequest(cfg config.TCCfg, method string, url string, body 
[]byte) (string, int, error) {
-       return trafficOpsRequestWithRetry(cfg, method, url, body, 
cfg.NumRetries)
-}
-
-func trafficOpsRequestWithRetry(
-       cfg config.TCCfg,
-       method string,
-       url string,
-       body []byte,
-       retryNum int,
-) (string, int, error) {
-       currentRetry := 0
-       for {
-               body, code, err := trafficOpsRequestWithLogin(cfg, method, url, 
body)
-               if err == nil || currentRetry == retryNum {
-                       return body, code, err
-               }
-
-               sleepSeconds := config.RetryBackoffSeconds(currentRetry)
-               log.Errorf("getting '%v' '%v', sleeping for %v seconds: %v\n", 
method, url, sleepSeconds, err)
-               currentRetry++
-               time.Sleep(time.Second * time.Duration(sleepSeconds))
-       }
-}
-
-func trafficOpsRequestWithLogin(
-       cfg config.TCCfg,
-       method string,
-       url string,
-       body []byte,
-) (string, int, error) {
-       resp, toIP, err := rawTrafficOpsRequest(*cfg.TOClient, method, url, 
body)
-       if err != nil {
-               toIPStr := ""
-               if toIP != nil {
-                       toIPStr = toIP.String()
-               }
-               return "", 1, errors.New("requesting from Traffic Ops '" + 
toIPStr + "': " + err.Error())
-       }
-
-       if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == 
http.StatusForbidden {
-               resp.Body.Close()
-
-               log.Infoln("TrafficOpsRequest got unauthorized/forbidden, 
logging in again")
-               log.Infof("TrafficOpsRequest url '%v' user '%v' pass '%v'\n", 
(*cfg.TOClient).URL, (*cfg.TOClient).UserName, (*cfg.TOClient).Password)
-
-               useCache := false
-               newTOClient, toIP, err := 
toclient.LoginWithAgent((*cfg.TOClient).URL, (*cfg.TOClient).UserName, 
(*cfg.TOClient).Password, cfg.TOInsecure, config.UserAgent, useCache, 
cfg.TOTimeout)
-               if err != nil {
-                       toIPStr := ""
-                       if toIP != nil {
-                               toIPStr = toIP.String()
-                       }
-                       return "", 1, errors.New("logging in to Traffic Ops IP 
'" + toIPStr + "': " + err.Error())
-               }
-               *cfg.TOClient = newTOClient
-
-               resp, toIP, err = rawTrafficOpsRequest(*cfg.TOClient, method, 
url, body)
-               if err != nil {
-                       toIPStr := ""
-                       if toIP != nil {
-                               toIPStr = toIP.String()
-                       }
-                       return "", 1, errors.New("requesting from Traffic Ops 
'" + toIPStr + "': " + err.Error())
-               }
-       }
-       defer resp.Body.Close()
-
-       if resp.StatusCode != http.StatusOK {
-               bts, err := ioutil.ReadAll(resp.Body)
-               if err != nil {
-                       bts = []byte("(read failure)") // if it's a non-200 and 
the body read fails, don't error, just note the read fail in the error
-               }
-               return "", resp.StatusCode, errors.New("Traffic Ops returned 
non-200 code '" + strconv.Itoa(resp.StatusCode) + "' body '" + string(bts) + 
"'")
-       }
-
-       bts, err := ioutil.ReadAll(resp.Body)
-       if err != nil {
-               toIPStr := ""
-               if toIP != nil {
-                       toIPStr = toIP.String()
-               }
-               return "", resp.StatusCode, errors.New("reading body from 
Traffic Ops '" + toIPStr + "': " + err.Error())
-       }
-
-       if err := IntegrityCheck(resp.Header, bts, url); err != nil {
-               return "", resp.StatusCode, errors.New("integrity check failed 
for url '" + url + "': " + err.Error())
-       }
-
-       return string(bts), http.StatusOK, nil
-}
-
-func IntegrityCheck(hdr http.Header, body []byte, url string) error {
-       if hdrSHA := hdr.Get("Whole-Content-SHA512"); hdrSHA != "" {
-               realSHA := sha512.Sum512(body)
-               realSHAStr := base64.StdEncoding.EncodeToString(realSHA[:])
-               if realSHAStr != hdrSHA {
-                       return errors.New("Body does not match header 
Whole-Content-SHA512")
-               }
-               log.Infoln("Integrity check for url '" + url + "' passed (sha 
match)")
-               return nil
-       }
-       if hdrLenStr := hdr.Get("Content-Length"); hdrLenStr != "" {
-               hdrLen, err := strconv.Atoi(hdrLenStr)
-               if err != nil {
-                       return errors.New("No Whole-Content-SHA512, and 
Content-Length '" + hdrLenStr + "' is not an integer")
-               }
-               if hdrLen != len(body) {
-                       return errors.New("No Whole-Content-SHA512, and 
Content-Length '" + hdrLenStr + "' does not match body length")
-               }
-               log.Infoln("Integrity check for url '" + url + "' passed 
(length match)\n")
-               return nil
-       }
-       return errors.New("No Whole-Content-SHA512, and no Content-Length, 
cannot verify content")
-}
-
-// rawTrafficOpsRequest makes a request to Traffic Ops for the given method, 
url, and body.
-// If it gets an Unauthorized or Forbidden, it tries to log in again and makes 
the request again.
-func rawTrafficOpsRequest(toClient *toclient.Session, method string, url 
string, body []byte) (*http.Response, net.Addr, error) {
-       bodyReader := io.Reader(nil)
-       if len(body) > 0 {
-               bodyReader = bytes.NewBuffer(body)
-       }
-
-       remoteAddr := net.Addr(nil)
-       req, err := http.NewRequest(method, url, bodyReader)
-       if err != nil {
-               return nil, remoteAddr, err
-       }
-
-       req = req.WithContext(httptrace.WithClientTrace(req.Context(), 
&httptrace.ClientTrace{
-               GotConn: func(connInfo httptrace.GotConnInfo) {
-                       remoteAddr = connInfo.Conn.RemoteAddr()
-               },
-       }))
-
-       req.Header.Set("User-Agent", toClient.UserAgentStr)
-
-       resp, err := toClient.Client.Do(req)
-       if err != nil {
-               return nil, remoteAddr, err
-       }
-
-       return resp, remoteAddr, nil
-}
-
-// MaybeIPStr returns the Traffic Ops IP string if it isn't nil, or the empty 
string if it is.
-func MaybeIPStr(addr net.Addr) string {
-       if addr != nil {
-               return addr.String()
-       }
-       return ""
-}
diff --git a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/LICENSE 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/LICENSE
similarity index 100%
rename from traffic_ops/ort/vendor/github.com/apache/trafficcontrol/LICENSE
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/LICENSE
diff --git a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/VERSION 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/VERSION
similarity index 100%
rename from traffic_ops/ort/vendor/github.com/apache/trafficcontrol/VERSION
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/VERSION
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/changeset.txt 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/changeset.txt
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/changeset.txt
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/changeset.txt
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/README.md
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/README.md
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/README.md
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/README.md
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/about.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/about.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/about.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/about.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/asn.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/asn.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/asn.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/asn.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/atsconfig.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/atsconfig.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/atsconfig.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/atsconfig.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cachegroup.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cachegroup.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cachegroup.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cachegroup.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cachegroup_parameters.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cachegroup_parameters.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cachegroup_parameters.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cachegroup_parameters.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cdn.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cdn.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cdn.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cdn.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cdn_domains.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cdn_domains.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cdn_domains.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cdn_domains.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cdnfederations.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cdnfederations.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cdnfederations.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/cdnfederations.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/coordinate.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/coordinate.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/coordinate.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/coordinate.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/crconfig.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/crconfig.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/crconfig.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/crconfig.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice_endpoints.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice_endpoints.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice_endpoints.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice_endpoints.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice_request_comments.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice_request_comments.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice_request_comments.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice_request_comments.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice_requests.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice_requests.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice_requests.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservice_requests.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservices_required_capabilities.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservices_required_capabilities.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservices_required_capabilities.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryservices_required_capabilities.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryserviceserver.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryserviceserver.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryserviceserver.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/deliveryserviceserver.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/division.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/division.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/division.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/division.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/dsuser.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/dsuser.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/dsuser.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/dsuser.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/endpoints.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/endpoints.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/endpoints.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/endpoints.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/federation.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/federation.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/federation.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/federation.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/federation_resolver.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/federation_resolver.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/federation_resolver.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/federation_resolver.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/hardware.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/hardware.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/hardware.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/hardware.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/iso.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/iso.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/iso.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/iso.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/job.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/job.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/job.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/job.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/log.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/log.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/log.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/log.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/origin.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/origin.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/origin.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/origin.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/parameter.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/parameter.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/parameter.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/parameter.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/phys_location.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/phys_location.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/phys_location.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/phys_location.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/ping.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/ping.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/ping.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/ping.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/profile.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/profile.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/profile.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/profile.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/profile_parameter.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/profile_parameter.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/profile_parameter.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/profile_parameter.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/region.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/region.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/region.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/region.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/role.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/role.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/role.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/role.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/server.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/server.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/server.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/server.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/server_server_capabilities.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/server_server_capabilities.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/server_server_capabilities.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/server_server_capabilities.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/server_update_status.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/server_update_status.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/server_update_status.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/server_update_status.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/servercapability.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/servercapability.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/servercapability.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/servercapability.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/servercheck.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/servercheck.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/servercheck.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/servercheck.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/serversstatus.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/serversstatus.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/serversstatus.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/serversstatus.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/session.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/session.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/session.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/session.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/staticdnsentry.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/staticdnsentry.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/staticdnsentry.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/staticdnsentry.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/stats_summary.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/stats_summary.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/stats_summary.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/stats_summary.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/status.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/status.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/status.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/status.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/steering.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/steering.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/steering.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/steering.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/steeringtarget.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/steeringtarget.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/steeringtarget.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/steeringtarget.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/tenant.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/tenant.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/tenant.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/tenant.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/tenant_endpoints.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/tenant_endpoints.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/tenant_endpoints.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/tenant_endpoints.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/toextension.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/toextension.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/toextension.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/toextension.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/traffic_monitor.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/traffic_monitor.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/traffic_monitor.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/traffic_monitor.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/traffic_stats.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/traffic_stats.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/traffic_stats.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/traffic_stats.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/type.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/type.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/type.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/type.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/update.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/update.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/update.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/update.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/user.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/user.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/user.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/user.go
diff --git 
a/traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/util.go
 
b/traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/util.go
similarity index 100%
rename from 
traffic_ops/ort/vendor/github.com/apache/trafficcontrol/traffic_ops/client/util.go
rename to 
traffic_ops/ort/atstccfg/toreq/vendor/github.com/apache/trafficcontrol/traffic_ops/client/util.go
diff --git a/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go 
b/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go
new file mode 100644
index 0000000..e7141f3
--- /dev/null
+++ b/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go
@@ -0,0 +1,97 @@
+// toreqnew implements a Traffic Ops client for features in the latest version.
+//
+// This should only be used if an endpoint or field needed for config gen is 
in the latest.
+//
+// Users should always check the returned bool, and if it's false, call the 
vendored toreq client and set the proper defaults for the new feature(s).
+//
+// All TOClient functions should check for 404 or 503 and return a bool false 
if so.
+//
+package toreqnew
+
+/*
+ * 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"
+       "net/http/cookiejar"
+       "net/url"
+       "strconv"
+       "strings"
+       "time"
+
+       "golang.org/x/net/publicsuffix"
+
+       "github.com/apache/trafficcontrol/lib/go-log"
+       "github.com/apache/trafficcontrol/lib/go-tc"
+       toclient "github.com/apache/trafficcontrol/traffic_ops/client"
+       "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/torequtil"
+)
+
+type TOClient struct {
+       C          *toclient.Session
+       NumRetries int
+}
+
+// New returns a TOClient with the given credentials.
+// Note it does not actually log in or try to make a request. Rather, it 
assumes the cookies are valid for a session. No external communication is made.
+func New(cookies string, url *url.URL, user string, pass string, insecure 
bool, timeout time.Duration, userAgent string) (*TOClient, error) {
+       log.Infoln("URL: '" + url.String() + "' User: '" + user + "' Pass len: 
'" + strconv.Itoa(len(pass)) + "'")
+
+       useCache := false
+       toClient := toclient.NewNoAuthSession(url.String(), insecure, 
userAgent, useCache, timeout)
+       toClient.UserName = user
+       toClient.Password = pass
+
+       jar, err := cookiejar.New(&cookiejar.Options{PublicSuffixList: 
publicsuffix.List})
+       if err != nil {
+               return nil, errors.New("making cookie jar: " + err.Error())
+       }
+       toClient.Client.Jar = jar
+       toClient.Client.Jar.SetCookies(url, torequtil.StringToCookies(cookies))
+
+       return &TOClient{C: toClient}, nil
+}
+
+// GetCDNDeliveryServices returns the deliveryservices, whether this client's 
version is unsupported by the server, and any error.
+// Note if the server returns a 404 or 503, this returns false and a nil error.
+// Users should check the "not supported" bool, and use the vendored TOClient 
if it's set, and set proper defaults for the new feature(s).
+func (cl *TOClient) GetCDNDeliveryServices(cdnID int) 
([]tc.DeliveryServiceNullable, bool, error) {
+       deliveryServices := []tc.DeliveryServiceNullable{}
+       unsupported := false
+       err := torequtil.GetRetry(cl.NumRetries, 
"cdn_"+strconv.Itoa(cdnID)+"_deliveryservices", &deliveryServices, func(obj 
interface{}) error {
+               toDSes, reqInf, err := cl.C.GetDeliveryServicesByCDNID(cdnID)
+               if err != nil {
+                       if errStr := strings.ToLower(err.Error()); 
strings.Contains(errStr, "not found") || strings.Contains(errStr, "not impl") {
+                               unsupported = true
+                               return nil
+                       }
+                       return errors.New("getting delivery services from 
Traffic Ops '" + torequtil.MaybeIPStr(reqInf.RemoteAddr) + "': " + err.Error())
+               }
+               dses := obj.(*[]tc.DeliveryServiceNullable)
+               *dses = toDSes
+               return nil
+       })
+       if unsupported {
+               return nil, true, nil
+       }
+       if err != nil {
+               return nil, false, errors.New("getting delivery services: " + 
err.Error())
+       }
+       return deliveryServices, false, nil
+}
diff --git a/traffic_ops/ort/atstccfg/torequtil/torequtil.go 
b/traffic_ops/ort/atstccfg/torequtil/torequtil.go
new file mode 100644
index 0000000..726858f
--- /dev/null
+++ b/traffic_ops/ort/atstccfg/torequtil/torequtil.go
@@ -0,0 +1,90 @@
+// torequtil has utility functions used by toreq and toreqnew
+// which don't require the Traffic Ops client, and thus can be shared.
+package torequtil
+
+/*
+ * 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"
+       "math"
+       "net"
+       "net/http"
+       "strings"
+       "time"
+
+       "github.com/apache/trafficcontrol/lib/go-log"
+)
+
+// GetRetry attempts to get the given object, retrying with exponential 
backoff up to cfg.NumRetries.
+// The objName is not used in actual fetching or logic, but only for logging. 
It can be any printable string, but should be unique and reflect the object 
being fetched.
+func GetRetry(numRetries int, objName string, obj interface{}, getter func(obj 
interface{}) error) error {
+       start := time.Now()
+       currentRetry := 0
+       for {
+               err := getter(obj)
+               if err == nil {
+                       break
+               }
+               if strings.Contains(strings.ToLower(err.Error()), "not found") {
+                       // if the server returned a 404, retrying won't help
+                       return errors.New("getting uncached: " + err.Error())
+               }
+               if currentRetry == numRetries {
+                       return errors.New("getting uncached: " + err.Error())
+               }
+
+               sleepSeconds := RetryBackoffSeconds(currentRetry)
+               log.Warnf("getting '%v', sleeping for %v seconds: %v\n", 
objName, sleepSeconds, err)
+               currentRetry++
+               time.Sleep(time.Second * time.Duration(sleepSeconds)) // TODO 
make backoff configurable?
+       }
+
+       log.Infof("GetRetry %v retries %v took %v\n", objName, currentRetry, 
time.Since(start).Round(time.Millisecond))
+       return nil
+}
+
+func RetryBackoffSeconds(currentRetry int) int {
+       // TODO make configurable?
+       return int(math.Pow(2.0, float64(currentRetry)))
+}
+
+// MaybeIPStr returns the addr string if it isn't nil, or the empty string if 
it is.
+// This is intended for logging, to allow logging with one line, whether addr 
is nil or not.
+func MaybeIPStr(addr net.Addr) string {
+       if addr != nil {
+               return addr.String()
+       }
+       return ""
+}
+
+func StringToCookies(cookiesStr string) []*http.Cookie {
+       hdr := http.Header{}
+       hdr.Add("Cookie", cookiesStr)
+       req := http.Request{Header: hdr}
+       return req.Cookies()
+}
+
+func CookiesToString(cookies []*http.Cookie) string {
+       strs := []string{}
+       for _, cookie := range cookies {
+               strs = append(strs, cookie.String())
+       }
+       return strings.Join(strs, "; ")
+}
diff --git a/traffic_ops/ort/atstccfg/torequtil/torequtil_test.go 
b/traffic_ops/ort/atstccfg/torequtil/torequtil_test.go
new file mode 100644
index 0000000..533a0db
--- /dev/null
+++ b/traffic_ops/ort/atstccfg/torequtil/torequtil_test.go
@@ -0,0 +1,70 @@
+package torequtil
+
+/*
+ * 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"
+       "net"
+       "strings"
+       "testing"
+)
+
+func TestGetRetry(t *testing.T) {
+       getterCalled := 0
+       getter := func(obj interface{}) error {
+               getterCalled++
+               return errors.New("something")
+       }
+
+       numRetries := 2
+       err := GetRetry(numRetries, "foo", nil, getter)
+       if err == nil {
+               t.Fatal("GetRetry expected error from f, actual nil")
+       }
+       if errStr := err.Error(); !strings.Contains(errStr, "something") {
+               t.Errorf("GetRetry expected error from getter 'something', 
actual '" + errStr + "'")
+       }
+       if getterCalled != numRetries+1 { // +1 because the first call isn't a 
retry.
+               t.Errorf("GetRetry expected to call getter numRetries %v +1 
times, actual %v\n", numRetries, getterCalled)
+       }
+}
+
+func TestRetryBackoffSeconds(t *testing.T) {
+       // Just test that it's greater. We don't want a brittle test that tests 
exactly how we know the function increases.
+       currentRetry := 0
+       newRetry := RetryBackoffSeconds(currentRetry)
+       if newRetry <= currentRetry {
+               t.Errorf("RetryBackoffSeconds expected greater than current 
retry %v actual %v", currentRetry, newRetry)
+       }
+       newerRetry := RetryBackoffSeconds(newRetry)
+       if newerRetry <= newRetry {
+               t.Errorf("RetryBackoffSeconds expected greater than new retry 
%v actual %v", currentRetry, newRetry)
+       }
+}
+
+func TestMaybeIPStr(t *testing.T) {
+       if is := MaybeIPStr(nil); is != "" {
+               t.Errorf("MaybeIPStr(nil) expected '', actual '%v'", is)
+       }
+       addr := &net.IPAddr{IP: net.ParseIP("192.0.2.1")}
+       if is := MaybeIPStr(addr); is != "192.0.2.1" {
+               t.Errorf("MaybeIPStr(nil) expected '192.0.2.1', actual '%v'", 
is)
+       }
+}
diff --git a/traffic_ops/ort/atstccfg/update-to-client/update-to-client.go 
b/traffic_ops/ort/atstccfg/update-to-client/update-to-client.go
new file mode 100644
index 0000000..99855df
--- /dev/null
+++ b/traffic_ops/ort/atstccfg/update-to-client/update-to-client.go
@@ -0,0 +1,290 @@
+package main
+
+/*
+ * 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"
+       "fmt"
+       "io/ioutil"
+       "os"
+       "os/exec"
+       "path/filepath"
+       "regexp"
+       "strings"
+)
+
+func main() {
+       if len(os.Args) < 3 {
+               fmt.Fprintf(os.Stdout, usageStr())
+               os.Exit(0)
+       }
+       dir := os.Args[1]
+       branch := os.Args[2]
+
+       workingDir, err := os.Getwd()
+       if err != nil {
+               fmt.Fprintf(os.Stderr, "Error getting working directory: 
"+err.Error()+"\n")
+               os.Exit(1)
+       }
+
+       dir = filepath.Join(workingDir, dir) // make the given directory 
absolute
+
+       if err := updateVendoredTOClient(dir, branch); err != nil {
+               fmt.Fprintf(os.Stderr, "Error updating vendored client: 
"+err.Error()+"\n")
+               os.Exit(1)
+       }
+       if err := updateNewClientUsage(dir); err != nil {
+               fmt.Fprintf(os.Stderr, "Error updating new client usage: 
"+err.Error()+"\n")
+               os.Exit(1)
+       }
+       os.Exit(0)
+}
+
+func usageStr() string {
+       return `usage: go run update-to-client.go 
/path/to/traffic_ops/ort/atstccfg branch-to-vendor
+
+Example: go run update-to-client/update-to-client.go . 5.0.x
+
+This script updates traffic_ops/ort/atstccfg after a Traffic Ops release is 
made.
+
+Be aware! It can and will modify all .go files in the given directory! Back up 
any uncommitted changes!
+
+Also be aware! This is very specific to the current code. If symbols or 
patterns are changed around how the master vs vendored client are used, this 
script will have to be updated.
+
+Expecations:
+- atstccfg is at github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg
+- The master TO client is at 
github.com/apache/trafficcontrol/traffic_ops/client
+- The previous major version client is vendored at atstccfg/toreq/vendor
+- The master client wrapper for atstccfg is at atstccfg/toreqnew
+- The clients are stored in config.TCCfg.TOClient and config.TCCfg.TOClientNew
+- Every func in toreqnew.TOClient has a corresponding func with the same name 
in toreq.TOClient
+- Every func in toreqnew.TOClient returns 3 variables: the object, boolean 
whether the request was unsupported, and an error.
+- Every func in toreq.TOClient returns 2 variables: the object, and an error.
+- Every usage of config.TOClientNew is immediately followed by a check 'if err 
== nil && unsupported', whose block calls the old client and sets defaults for 
the unsupported new feature.
+- The script is running on a POSIX-like environment. Namely, cp and gofmt 
exist.
+
+The arguments are the atstccfg directory, and the name of the branch to vendor 
from.
+
+This script should always be called from 
trafficcontrol/traffic_ops/ort/atstccfg.
+
+It copies the traffic_ops/client from that branch into toreq/vendor,
+and then updates all references to cfg.TOClientNew to cfg.TOClient.
+
+This must be done as soon as a release is made, before any new features are 
added to ort/atstccfg.
+Thus, all existing toreqnew.TOClient function calls should exist in master.
+
+If any new features were added after a release, before you ran this script,
+you'll have to go back and fix compile errors for new client functions.
+
+Further, if the new features were fields on existing functions, being moved
+from toreqnew to toreq will make them still compile, but the fields will be 
nil!
+
+It will also run gofmt on all go files in the directory (because it's much 
easier to manipulate code guaranteed to be gofmt'd).
+
+Double check the results before you commit!
+`
+}
+
+func updateNewClientUsage(appDir string) error {
+       paths := []string{}
+       err := filepath.Walk(appDir,
+               func(path string, info os.FileInfo, err error) error {
+                       if err != nil {
+                               return err
+                       }
+                       if !strings.HasSuffix(path, `.go`) {
+                               return nil // skip anything not a go file.
+                       }
+                       if strings.Contains(path, `/vendor/`) {
+                               return nil // skip vendored code
+                       }
+                       if strings.HasPrefix(filepath.Base(path), `.`) {
+                               return nil // skip .files (usually created by 
editors)
+                       }
+                       if strings.Contains(path, `update-to-client.go`) {
+                               return nil // skip this file
+                       }
+
+                       paths = append(paths, path)
+                       return nil
+               })
+       if err != nil {
+               return errors.New("reading directory: " + err.Error() + "\n")
+       }
+
+       toClientNewRe := regexp.MustCompile(`(\s+)([^\s]+), (.+), (.+) := 
(.+).TOClientNew.(.+)$`)
+
+       for _, path := range paths {
+               // gofmt the file, because the parsing relies on things being 
in that exact format.
+               if err := exec.Command(`gofmt`, `-w`, path).Run(); err != nil {
+                       return errors.New("running gofmt on '" + path + ": " + 
err.Error() + "\n")
+               }
+
+               bts, err := ioutil.ReadFile(path)
+               if err != nil {
+                       return errors.New("reading file '" + path + "': " + 
err.Error() + "\n")
+               }
+
+               lines := strings.Split(string(bts), "\n")
+               newLines := make([]string, 0, len(lines))
+
+               const stateStart = 0
+               const stateInFoundTOClientNew = 1
+               const stateInTOClientNewUnsupportedBlock = 2
+
+               state := stateStart
+               spacePrefix := ""
+               objVar := ""
+               unsupportedVar := ""
+               errVar := ""
+               for _, line := range lines {
+                       switch state {
+                       case stateStart:
+                               if strings.Contains(line, `.TOClientNew.`) {
+                                       matches := 
toClientNewRe.FindStringSubmatch(line)
+                                       if len(matches) != 7 {
+                                               // TODO is this really an 
error? Skip and continue?
+                                               return fmt.Errorf("parsing file 
'"+path+"': line contains TOClientNew, but is unexpected format (only %v 
matches): '"+line+"'\n", len(matches))
+                                       }
+                                       spacePrefix = matches[1]
+                                       objVar = matches[2]
+                                       unsupportedVar = matches[3]
+                                       errVar = matches[4]
+                                       cfg := matches[5]
+                                       funcStr := matches[6]
+                                       newLine := spacePrefix + objVar + `, ` 
+ errVar + ` := ` + cfg + `.TOClient.` + funcStr
+                                       newLines = append(newLines, newLine)
+                                       state = stateInFoundTOClientNew
+                                       continue
+                               }
+                               newLines = append(newLines, line)
+                       case stateInFoundTOClientNew:
+                               // if there's a newline between the call and 
the unsupported check, skip it.
+                               if strings.TrimSpace(line) == "" {
+                                       continue
+                               }
+                               if line == spacePrefix+`if `+errVar+` == nil && 
`+unsupportedVar+` {` ||
+                                       line == spacePrefix+`if 
`+unsupportedVar+` && `+errVar+` == nil `+` {` ||
+                                       line == spacePrefix+`if 
`+unsupportedVar+` {` ||
+                                       line == spacePrefix+`if 
`+unsupportedVar+` {` {
+                                       state = 
stateInTOClientNewUnsupportedBlock
+                                       continue // continue without adding 
this line - we want to remove the check-and-fallback
+                               }
+                               return errors.New("parsing file '" + path + "': 
line contains TOClientNew, but is unexpected format: not followed by a check 
for the unsupported bool (or the parser failed to understand it)\n")
+                       case stateInTOClientNewUnsupportedBlock:
+                               // This is why we have to gofmt - if we didn't, 
we couldn't be guarnateed the block closing would be prefixed by exactly this 
many spaces. Then we'd have to parse the AST to find it. Ick.
+                               if line == spacePrefix+`}` {
+                                       state = stateStart
+                               }
+                               // Whether or not we find the closing block, 
don't add it to the lines to output.
+                               // We want to remove the TOClientNew 
check-and-fallback block from the output.
+                       }
+               }
+               if state != stateStart {
+                       return errors.New("parsing modified file '" + path + 
"': appeared to be malformed (or maybe our parser is just broken, sorry)\n")
+               }
+
+               newFile := strings.Join(newLines, "\n")
+
+               if err := ioutil.WriteFile(path, []byte(newFile), 0644); err != 
nil {
+                       return errors.New("writing modified file '" + path + 
"': " + err.Error() + "\n")
+               }
+       }
+       return nil
+}
+
+func updateVendoredTOClient(appDir string, branch string) error {
+       vendorDir := filepath.Join(appDir, `toreq`, `vendor`)
+       vendorTCDir := filepath.Join(vendorDir, `github.com`, `apache`, 
`trafficcontrol`)
+       vendorClientDir := filepath.Join(vendorTCDir, `traffic_ops`, `client`)
+
+       vendorFileInfo, err := os.Stat(vendorClientDir)
+       if err != nil {
+               return errors.New("getting vendor dir '" + vendorDir + "' info: 
" + err.Error())
+       }
+       if !vendorFileInfo.IsDir() {
+               return errors.New("getting vendor dir '" + vendorDir + "' info: 
not a directory")
+       }
+       if err := os.RemoveAll(vendorClientDir); err != nil {
+               return errors.New("removing vendor dir '" + vendorDir + "': " + 
err.Error())
+       }
+       if err := os.Mkdir(vendorClientDir, 0755); err != nil {
+               return errors.New("creating vendor dir '" + vendorDir + "': " + 
err.Error())
+       }
+
+       cmd := exec.Command(`git`, `show`, branch+`:../../client`)
+       cmd.Dir = appDir
+       clientFileListBts, err := cmd.Output()
+       if err != nil {
+               return errors.New("getting files from git: " + err.Error())
+       }
+       clientFileListStr := string(clientFileListBts)
+       clientFileList := strings.Split(clientFileListStr, "\n")
+       if len(clientFileList) < 2 {
+               return errors.New("getting files from git: got no files")
+       }
+       clientFileList = clientFileList[1:] // first line is a header, remove 
it.
+       // fmt.Printf("DEBUG got client file list '''%+v'''\n", 
clientFileListStr)
+
+       for _, clientFile := range clientFileList {
+               clientFile = strings.TrimSpace(clientFile)
+               if clientFile == "" {
+                       continue
+               }
+               cmd := exec.Command(`git`, `show`, 
branch+`:../../client`+`/`+clientFile)
+               cmd.Dir = appDir
+               fileBts, err := cmd.Output()
+               if err != nil {
+                       return errors.New("getting client file '" + clientFile 
+ "' from git: " + err.Error())
+               }
+               if err := ioutil.WriteFile(vendorClientDir+`/`+clientFile, 
fileBts, 0644); err != nil {
+                       return errors.New("Error writing vendored file '" + 
clientFile + "': " + err.Error())
+               }
+       }
+
+       // update VERSION in vendored dir
+       cmd = exec.Command(`git`, `show`, branch+`:VERSION`)
+       cmd.Dir = appDir
+       versionBts, err := cmd.Output()
+       if err != nil {
+               return errors.New("getting VERSION file from git: " + 
err.Error())
+       }
+
+       versionPath := filepath.Join(vendorTCDir, `VERSION`)
+       if err := ioutil.WriteFile(versionPath, versionBts, 0644); err != nil {
+               return errors.New("Error writing vendored VERSION file '" + 
versionPath + "': " + err.Error())
+       }
+
+       cmd = exec.Command(`git`, `rev-parse`, branch)
+       cmd.Dir = appDir
+       changesetBts, err := cmd.Output()
+       if err != nil {
+               return errors.New("getting VERSION file from git: " + 
err.Error())
+       }
+
+       changesetTxt := branch + "\n" + string(changesetBts)
+
+       changesetTxtPath := filepath.Join(vendorTCDir, `changeset.txt`)
+       if err := ioutil.WriteFile(changesetTxtPath, []byte(changesetTxt), 
0644); err != nil {
+               return errors.New("Error writing vendored changeset.txt file '" 
+ changesetTxtPath + "': " + err.Error())
+       }
+
+       return nil
+}

Reply via email to