You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@trafficcontrol.apache.org by GitBox <gi...@apache.org> on 2018/09/04 15:46:17 UTC

[GitHub] moltzaum closed pull request #2777: Versioning for TO Golang client and lib

moltzaum closed pull request #2777: Versioning for TO Golang client and lib
URL: https://github.com/apache/trafficcontrol/pull/2777
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/lib/go-tc/cachegroups.go b/lib/go-tc/cachegroups.go
new file mode 100644
index 000000000..522ee7e4c
--- /dev/null
+++ b/lib/go-tc/cachegroups.go
@@ -0,0 +1,84 @@
+package tc
+
+/*
+ * 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 (
+	"github.com/apache/trafficcontrol/lib/go-util"
+)
+
+// CacheGroupResponse ...
+type CacheGroupsResponse struct {
+	Response []CacheGroup `json:"response"`
+}
+
+type CacheGroupsNullableResponse struct {
+	Response []CacheGroupNullable `json:"response"`
+}
+
+// CacheGroupDetailResponse is the JSON object returned for a single CacheGroup
+type CacheGroupDetailResponse struct {
+	Response CacheGroupNullable `json:"response"`
+	Alerts
+}
+
+// CacheGroup contains information about a given Cachegroup in Traffic Ops.
+type CacheGroup struct {
+	ID                          int                  `json:"id" db:"id"`
+	Name                        string               `json:"name" db:"name"`
+	ShortName                   string               `json:"shortName" db:"short_name"`
+	Latitude                    float64              `json:"latitude" db:"latitude"`
+	Longitude                   float64              `json:"longitude" db:"longitude"`
+	ParentName                  string               `json:"parentCachegroupName" db:"parent_cachegroup_name"`
+	ParentCachegroupID          int                  `json:"parentCachegroupId" db:"parent_cachegroup_id"`
+	SecondaryParentName         string               `json:"secondaryParentCachegroupName" db:"secondary_parent_cachegroup_name"`
+	SecondaryParentCachegroupID int                  `json:"secondaryParentCachegroupId" db:"secondary_parent_cachegroup_id"`
+	FallbackToClosest           bool                 `json:"fallbackToClosest" db:"fallback_to_closest"`
+	LocalizationMethods         []LocalizationMethod `json:"localizationMethods" db:"localization_methods"`
+	Type                        string               `json:"typeName" db:"type_name"` // aliased to type_name to disambiguate struct scans due to join on 'type' table
+	TypeID                      int                  `json:"typeId" db:"type_id"`     // aliased to type_id to disambiguate struct scans due join on 'type' table
+	LastUpdated                 TimeNoMod            `json:"lastUpdated" db:"last_updated"`
+}
+
+type CacheGroupNullable struct {
+	ID                          *int                  `json:"id" db:"id"`
+	Name                        *string               `json:"name" db:"name"`
+	ShortName                   *string               `json:"shortName" db:"short_name"`
+	Latitude                    *float64              `json:"latitude" db:"latitude"`
+	Longitude                   *float64              `json:"longitude"db:"longitude"`
+	ParentName                  *string               `json:"parentCachegroupName" db:"parent_cachegroup_name"`
+	ParentCachegroupID          *int                  `json:"parentCachegroupId" db:"parent_cachegroup_id"`
+	SecondaryParentName         *string               `json:"secondaryParentCachegroupName" db:"secondary_parent_cachegroup_name"`
+	SecondaryParentCachegroupID *int                  `json:"secondaryParentCachegroupId" db:"secondary_parent_cachegroup_id"`
+	FallbackToClosest           *bool                 `json:"fallbackToClosest" db:"fallback_to_closest"`
+	LocalizationMethods         *[]LocalizationMethod `json:"localizationMethods" db:"localization_methods"`
+	Type                        *string               `json:"typeName" db:"type_name"` // aliased to type_name to disambiguate struct scans due to join on 'type' table
+	TypeID                      *int                  `json:"typeId" db:"type_id"`     // aliased to type_id to disambiguate struct scans due join on 'type' table
+	LastUpdated                 *TimeNoMod            `json:"lastUpdated" db:"last_updated"`
+}
+
+type CachegroupTrimmedName struct {
+	Name string `json:"name"`
+}
+
+type CachegroupQueueUpdatesRequest struct {
+	Action string           `json:"action"`
+	CDN    *CDNName         `json:"cdn"`
+	CDNID  *util.JSONIntStr `json:"cdnId"`
+}
diff --git a/lib/go-tc/cdns.go b/lib/go-tc/cdns.go
new file mode 100644
index 000000000..869008130
--- /dev/null
+++ b/lib/go-tc/cdns.go
@@ -0,0 +1,119 @@
+package tc
+
+/*
+ * 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.
+ */
+
+// A List of CDNs Response
+// swagger:response CDNsResponse
+// in: body
+type CDNsResponse struct {
+	// in: body
+	Response []CDN `json:"response"`
+}
+
+// A Single CDN Response for Update and Create to depict what changed
+// swagger:response CDNResponse
+// in: body
+type CDNResponse struct {
+	// in: body
+	Response CDN `json:"response"`
+}
+
+// CDN ...
+type CDN struct {
+
+	// The CDN to retrieve
+	//
+	// enables Domain Name Security Extensions on the specified CDN
+	//
+	// required: true
+	DNSSECEnabled bool `json:"dnssecEnabled" db:"dnssec_enabled"`
+
+	// DomainName of the CDN
+	//
+	// required: true
+	DomainName string `json:"domainName" db:"domain_name"`
+
+	// ID of the CDN
+	//
+	// required: true
+	ID int `json:"id" db:"id"`
+
+	// LastUpdated
+	//
+	LastUpdated TimeNoMod `json:"lastUpdated" db:"last_updated"`
+
+	// Name of the CDN
+	//
+	// required: true
+	Name string `json:"name" db:"name"`
+}
+
+// CDNNullable ...
+type CDNNullable struct {
+
+	// The CDN to retrieve
+	//
+	// enables Domain Name Security Extensions on the specified CDN
+	//
+	// required: true
+	DNSSECEnabled *bool `json:"dnssecEnabled" db:"dnssec_enabled"`
+
+	// DomainName of the CDN
+	//
+	// required: true
+	DomainName *string `json:"domainName" db:"domain_name"`
+
+	// ID of the CDN
+	//
+	// required: true
+	ID *int `json:"id" db:"id"`
+
+	// LastUpdated
+	//
+	LastUpdated *TimeNoMod `json:"lastUpdated" db:"last_updated"`
+
+	// Name of the CDN
+	//
+	// required: true
+	Name *string `json:"name" db:"name"`
+}
+
+// CDNSSLKeysResponse ...
+type CDNSSLKeysResponse struct {
+	Response []CDNSSLKeys `json:"response"`
+}
+
+// CDNSSLKeys ...
+type CDNSSLKeys struct {
+	DeliveryService string                `json:"deliveryservice"`
+	Certificate     CDNSSLKeysCertificate `json:"certificate"`
+	Hostname        string                `json:"hostname"`
+}
+
+// CDNSSLKeysCertificate ...
+type CDNSSLKeysCertificate struct {
+	Crt string `json:"crt"`
+	Key string `json:"key"`
+}
+
+type CDNConfig struct {
+	Name *string `json:"name"`
+	ID   *int    `json:"id"`
+}
diff --git a/lib/go-tc/coordinates.go b/lib/go-tc/coordinates.go
new file mode 100644
index 000000000..3cc74dc22
--- /dev/null
+++ b/lib/go-tc/coordinates.go
@@ -0,0 +1,96 @@
+package tc
+
+/*
+ * 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.
+ */
+
+// A List of Coordinates Response
+// swagger:response CoordinatesResponse
+// in: body
+type CoordinatesResponse struct {
+	// in: body
+	Response []Coordinate `json:"response"`
+}
+
+// A Single Coordinate Response for Update and Create to depict what changed
+// swagger:response CoordinateResponse
+// in: body
+type CoordinateResponse struct {
+	// in: body
+	Response Coordinate `json:"response"`
+}
+
+// Coordinate ...
+type Coordinate struct {
+
+	// The Coordinate to retrieve
+	//
+	// ID of the Coordinate
+	//
+	// required: true
+	ID int `json:"id" db:"id"`
+
+	// Name of the Coordinate
+	//
+	// required: true
+	Name string `json:"name" db:"name"`
+
+	// the latitude of the Coordinate
+	//
+	// required: true
+	Latitude float64 `json:"latitude" db:"latitude"`
+
+	// the latitude of the Coordinate
+	//
+	// required: true
+	Longitude float64 `json:"longitude" db:"longitude"`
+
+	// LastUpdated
+	//
+	LastUpdated TimeNoMod `json:"lastUpdated" db:"last_updated"`
+}
+
+// CoordinateNullable ...
+type CoordinateNullable struct {
+
+	// The Coordinate to retrieve
+	//
+	// ID of the Coordinate
+	//
+	// required: true
+	ID *int `json:"id" db:"id"`
+
+	// Name of the Coordinate
+	//
+	// required: true
+	Name *string `json:"name" db:"name"`
+
+	// the latitude of the Coordinate
+	//
+	// required: true
+	Latitude *float64 `json:"latitude" db:"latitude"`
+
+	// the latitude of the Coordinate
+	//
+	// required: true
+	Longitude *float64 `json:"longitude" db:"longitude"`
+
+	// LastUpdated
+	//
+	LastUpdated *TimeNoMod `json:"lastUpdated" db:"last_updated"`
+}
diff --git a/lib/go-tc/domains.go b/lib/go-tc/domains.go
new file mode 100644
index 000000000..29c4292ad
--- /dev/null
+++ b/lib/go-tc/domains.go
@@ -0,0 +1,46 @@
+package tc
+
+/*
+ * 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.
+ */
+
+type DomainsResponse struct {
+	Response []Domain `json:"response"`
+}
+
+type Domain struct {
+	ProfileID int `json:"profileId" db:"profile_id"`
+
+	ParameterID int `json:"parameterId" db:"parameter_id"`
+
+	ProfileName string `json:"profileName" db:"profile_name"`
+
+	ProfileDescription string `json:"profileDescription" db:"profile_description"`
+
+	// DomainName of the CDN
+	DomainName string `json:"domainName" db:"domain_name"`
+}
+
+// DomainNullable - a struct version that allows for all fields to be null, mostly used by the API side
+type DomainNullable struct {
+	ProfileID          *int    `json:"profileId" db:"profile_id"`
+	ParameterID        *int    `json:"parameterId" db:"parameter_id"`
+	ProfileName        *string `json:"profileName" db:"profile_name"`
+	ProfileDescription *string `json:"profileDescription" db:"profile_description"`
+	DomainName         *string `json:"domainName" db:"domain_name"`
+}
diff --git a/lib/go-tc/federations.go b/lib/go-tc/federations.go
new file mode 100644
index 000000000..1a6bfccf3
--- /dev/null
+++ b/lib/go-tc/federations.go
@@ -0,0 +1,54 @@
+package tc
+
+/*
+ * 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.
+ */
+
+type CDNFederationResponse struct {
+	Response []CDNFederation `json:"response"`
+}
+
+type CreateCDNFederationResponse struct {
+	Response CDNFederation `json:"response"`
+	Alerts
+}
+
+type UpdateCDNFederationResponse struct {
+	Response CDNFederation `json:"response"`
+	Alerts
+}
+
+type DeleteCDNFederationResponse struct {
+	Alerts
+}
+
+type CDNFederation struct {
+	ID          *int       `json:"id" db:"id"`
+	CName       *string    `json:"cname" db:"cname"`
+	TTL         *int       `json:"ttl" db:"ttl"`
+	Description *string    `json:"description" db:"description"`
+	LastUpdated *TimeNoMod `json:"lastUpdated" db:"last_updated"`
+
+	// omitempty only works with primitive types and pointers
+	*DeliveryServiceIDs `json:"deliveryService,omitempty"`
+}
+
+type DeliveryServiceIDs struct {
+	DsId  *int    `json:"id,omitempty" db:"ds_id"`
+	XmlId *string `json:"xmlId,omitempty" db:"xml_id"`
+}
diff --git a/lib/go-tc/origins.go b/lib/go-tc/origins.go
new file mode 100644
index 000000000..1fa2ebd52
--- /dev/null
+++ b/lib/go-tc/origins.go
@@ -0,0 +1,52 @@
+package tc
+
+/*
+ * 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.
+ */
+
+type OriginsResponse struct {
+	Response []Origin `json:"response"`
+}
+
+// OriginDetailResponse is the JSON object returned for a single origin
+type OriginDetailResponse struct {
+	Response Origin `json:"response"`
+	Alerts
+}
+
+type Origin struct {
+	Cachegroup        *string    `json:"cachegroup" db:"cachegroup"`
+	CachegroupID      *int       `json:"cachegroupId" db:"cachegroup_id"`
+	Coordinate        *string    `json:"coordinate" db:"coordinate"`
+	CoordinateID      *int       `json:"coordinateId" db:"coordinate_id"`
+	DeliveryService   *string    `json:"deliveryService" db:"deliveryservice"`
+	DeliveryServiceID *int       `json:"deliveryServiceId" db:"deliveryservice_id"`
+	FQDN              *string    `json:"fqdn" db:"fqdn"`
+	ID                *int       `json:"id" db:"id"`
+	IP6Address        *string    `json:"ip6Address" db:"ip6_address"`
+	IPAddress         *string    `json:"ipAddress" db:"ip_address"`
+	IsPrimary         *bool      `json:"isPrimary" db:"is_primary"`
+	LastUpdated       *TimeNoMod `json:"lastUpdated" db:"last_updated"`
+	Name              *string    `json:"name" db:"name"`
+	Port              *int       `json:"port" db:"port"`
+	Profile           *string    `json:"profile" db:"profile"`
+	ProfileID         *int       `json:"profileId" db:"profile_id"`
+	Protocol          *string    `json:"protocol" db:"protocol"`
+	Tenant            *string    `json:"tenant" db:"tenant"`
+	TenantID          *int       `json:"tenantId" db:"tenant_id"`
+}
diff --git a/lib/go-tc/profile_parameters.go b/lib/go-tc/profile_parameters.go
new file mode 100644
index 000000000..848a403bd
--- /dev/null
+++ b/lib/go-tc/profile_parameters.go
@@ -0,0 +1,51 @@
+package tc
+
+/*
+ * 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.
+ */
+
+// ProfileParametersResponse ...
+type ProfileParametersResponse struct {
+	Response []ProfileParameter `json:"response"`
+}
+
+// A Single ProfileParameter Response for Create to depict what changed
+// swagger:response ProfileParameterResponse
+// in: body
+type ProfileParameterResponse struct {
+	// in: body
+	Response ProfileParameter `json:"response"`
+}
+
+// ProfileParameter ...
+type ProfileParameter struct {
+	LastUpdated TimeNoMod `json:"lastUpdated"`
+	Profile     string    `json:"profile"`
+	ProfileID   int       `json:"profileId"`
+	Parameter   string    `json:"parameter"`
+	ParameterID int       `json:"parameterId"`
+}
+
+// ProfileParameterNullable ...
+type ProfileParameterNullable struct {
+	LastUpdated *TimeNoMod `json:"lastUpdated" db:"last_updated"`
+	Profile     *string    `json:"profile" db:"profile"`
+	ProfileID   *int       `json:"profileId" db:"profile_id"`
+	Parameter   *string    `json:"parameter" db:"parameter"`
+	ParameterID *int       `json:"parameterId" db:"parameter_id"`
+}
diff --git a/lib/go-tc/roles.go b/lib/go-tc/roles.go
new file mode 100644
index 000000000..2cce62046
--- /dev/null
+++ b/lib/go-tc/roles.go
@@ -0,0 +1,64 @@
+package tc
+
+/*
+ * 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.
+ */
+
+// A List of Roles Response
+// swagger:response RolesResponse
+// in: body
+type RolesResponse struct {
+	// in: body
+	Response []Role `json:"response"`
+}
+
+// A Single Role Response for Update and Create to depict what changed
+// swagger:response RoleResponse
+// in: body
+type RoleResponse struct {
+	// in: body
+	Response Role `json:"response"`
+}
+
+// Role ...
+type Role struct {
+	// ID of the Role
+	//
+	// required: true
+	ID *int `json:"id" db:"id"`
+
+	// Name of the Role
+	//
+	// required: true
+	Name *string `json:"name" db:"name"`
+
+	// Description of the Role
+	//
+	// required: true
+	Description *string `json:"description" db:"description"`
+
+	// Priv Level of the Role
+	//
+	// required: true
+	PrivLevel *int `json:"privLevel" db:"priv_level"`
+
+	// Capabilities associated with the Role
+	//
+	// required: true
+	Capabilities *[]string `json:"capabilities" db:"capabilities"`
+}
diff --git a/lib/go-tc/v14/README.md b/lib/go-tc/v14/README.md
new file mode 100644
index 000000000..4481f2df4
--- /dev/null
+++ b/lib/go-tc/v14/README.md
@@ -0,0 +1,5 @@
+
+#### Traffic Ops Data and Response Structs Version 1.4
+
+As new updates are being made for the next minor version for TO data, they will be put into this directory.
+
diff --git a/traffic_ops/client/about.go b/traffic_ops/client/about.go
new file mode 100644
index 000000000..bd4da31db
--- /dev/null
+++ b/traffic_ops/client/about.go
@@ -0,0 +1,43 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"net/http"
+)
+
+const (
+	API_ABOUT = apiBase + "/about"
+)
+
+// GetAbout gets data about the TO instance
+func (to *Session) GetAbout() (map[string]string, ReqInf, error) {
+	route := API_ABOUT
+	resp, remoteAddr, err := to.request(http.MethodGet, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data map[string]string
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data, reqInf, nil
+}
diff --git a/traffic_ops/client/asn.go b/traffic_ops/client/asn.go
new file mode 100644
index 000000000..5b145c6fe
--- /dev/null
+++ b/traffic_ops/client/asn.go
@@ -0,0 +1,132 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+	"net/http"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+const (
+	API_v2_ASNs = apiBase + "/asns"
+)
+
+// Create a ASN
+func (to *Session) CreateASN(entity tc.ASN) (tc.Alerts, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(entity)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	resp, remoteAddr, err := to.request(http.MethodPost, API_v2_ASNs, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// Update a ASN by ID
+func (to *Session) UpdateASNByID(id int, entity tc.ASN) (tc.Alerts, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(entity)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	route := fmt.Sprintf("%s/%d", API_v2_ASNs, id)
+	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// Returns a list of ASNs
+func (to *Session) GetASNs() ([]tc.ASN, ReqInf, error) {
+	resp, remoteAddr, err := to.request(http.MethodGet, API_v2_ASNs, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.ASNsResponse
+	err = json.NewDecoder(resp.Body).Decode(&data)
+	return data.Response, reqInf, nil
+}
+
+// GET a ASN by the id
+func (to *Session) GetASNByID(id int) ([]tc.ASN, ReqInf, error) {
+	route := fmt.Sprintf("%s/%d", API_v2_ASNs, id)
+	resp, remoteAddr, err := to.request(http.MethodGet, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.ASNsResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// GET an ASN by the asn number
+func (to *Session) GetASNByASN(asn int) ([]tc.ASN, ReqInf, error) {
+	url := fmt.Sprintf("%s?asn=%d", API_v2_ASNs, asn)
+	resp, remoteAddr, err := to.request(http.MethodGet, url, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.ASNsResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// DELETE an ASN by asn number
+func (to *Session) DeleteASNByASN(asn int) (tc.Alerts, ReqInf, error) {
+	route := fmt.Sprintf("%s/asn/%d", API_v2_ASNs, asn)
+	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
diff --git a/traffic_ops/client/cdn_domains.go b/traffic_ops/client/cdn_domains.go
new file mode 100644
index 000000000..ddf54fc8e
--- /dev/null
+++ b/traffic_ops/client/cdn_domains.go
@@ -0,0 +1,29 @@
+package client
+
+import (
+	"github.com/apache/trafficcontrol/lib/go-tc/"
+)
+
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+func (to *Session) GetDomains() ([]Domain, ReqInf, error) {
+	var data DomainsResponse
+	inf, err := get(to, apiBase+"/cdns/domains", &data)
+	if err != nil {
+		return nil, inf, err
+	}
+	return data.Response, inf, nil
+}
diff --git a/traffic_ops/client/cdnfederations.go b/traffic_ops/client/cdnfederations.go
new file mode 100644
index 000000000..08cbef077
--- /dev/null
+++ b/traffic_ops/client/cdnfederations.go
@@ -0,0 +1,73 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+/* Internally, the CDNName is only used in the GET method. The CDNName
+ * seems to primarily be used to differentiate between `/federations` and
+ * `/cdns/:name/federations`. Although the behavior is odd, it is kept to
+ * keep the same behavior from perl. */
+
+func (to *Session) CreateCDNFederationByName(f CDNFederation, CDNName string) (*CreateCDNFederationResponse, ReqInf, error) {
+	jsonReq, err := json.Marshal(f)
+	if err != nil { //There is no remoteAddr for ReqInf at this point
+		return nil, ReqInf{CacheHitStatus: CacheHitStatusMiss}, err
+	}
+
+	data := CreateCDNFederationResponse{}
+	url := fmt.Sprintf("%s/cdns/%s/federations", apiBase, CDNName)
+	inf, err := makeReq(to, "POST", url, jsonReq, &data)
+	return &data, inf, err
+}
+
+func (to *Session) GetCDNFederationsByName(CDNName string) (*CDNFederationResponse, ReqInf, error) {
+	data := CDNFederationResponse{}
+	url := fmt.Sprintf("%s/cdns/%s/federations", apiBase, CDNName)
+	inf, err := get(to, url, &data)
+	return &data, inf, err
+}
+
+func (to *Session) GetCDNFederationsByID(CDNName string, ID int) (*CDNFederationResponse, ReqInf, error) {
+	data := CDNFederationResponse{}
+	url := fmt.Sprintf("%s/cdns/%s/federations/%d", apiBase, CDNName, ID)
+	inf, err := get(to, url, &data)
+	return &data, inf, err
+}
+
+func (to *Session) UpdateCDNFederationsByID(f CDNFederation, CDNName string, ID int) (*UpdateCDNFederationResponse, ReqInf, error) {
+	jsonReq, err := json.Marshal(f)
+	if err != nil { //There is no remoteAddr for ReqInf at this point
+		return nil, ReqInf{CacheHitStatus: CacheHitStatusMiss}, err
+	}
+
+	data := UpdateCDNFederationResponse{}
+	url := fmt.Sprintf("%s/cdns/%s/federations/%d", apiBase, CDNName, ID)
+	inf, err := makeReq(to, "PUT", url, jsonReq, &data)
+	return &data, inf, err
+}
+
+func (to *Session) DeleteCDNFederationByID(CDNName string, ID int) (*DeleteCDNFederationResponse, ReqInf, error) {
+	data := DeleteCDNFederationResponse{}
+	url := fmt.Sprintf("%s/cdns/%s/federations/%d", apiBase, CDNName, ID)
+	inf, err := makeReq(to, "DELETE", url, nil, &data)
+	return &data, inf, err
+}
diff --git a/traffic_ops/client/coordinate.go b/traffic_ops/client/coordinate.go
new file mode 100644
index 000000000..7f36b2179
--- /dev/null
+++ b/traffic_ops/client/coordinate.go
@@ -0,0 +1,132 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+	"net/http"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+const (
+	API_Coordinates = apiBase + "/coordinates"
+)
+
+// Create a Coordinate
+func (to *Session) CreateCoordinate(coordinate Coordinate) (tc.Alerts, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(coordinate)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	resp, remoteAddr, err := to.request(http.MethodPost, API_Coordinates, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// Update a Coordinate by ID
+func (to *Session) UpdateCoordinateByID(id int, coordinate Coordinate) (tc.Alerts, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(coordinate)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	route := fmt.Sprintf("%s?id=%d", API_Coordinates, id)
+	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// Returns a list of Coordinates
+func (to *Session) GetCoordinates() ([]Coordinate, ReqInf, error) {
+	resp, remoteAddr, err := to.request(http.MethodGet, API_Coordinates, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data CoordinatesResponse
+	err = json.NewDecoder(resp.Body).Decode(&data)
+	return data.Response, reqInf, nil
+}
+
+// GET a Coordinate by the Coordinate id
+func (to *Session) GetCoordinateByID(id int) ([]Coordinate, ReqInf, error) {
+	route := fmt.Sprintf("%s?id=%d", API_Coordinates, id)
+	resp, remoteAddr, err := to.request(http.MethodGet, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data CoordinatesResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// GET a Coordinate by the Coordinate name
+func (to *Session) GetCoordinateByName(name string) ([]Coordinate, ReqInf, error) {
+	url := fmt.Sprintf("%s?name=%s", API_Coordinates, name)
+	resp, remoteAddr, err := to.request(http.MethodGet, url, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data CoordinatesResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// DELETE a Coordinate by ID
+func (to *Session) DeleteCoordinateByID(id int) (tc.Alerts, ReqInf, error) {
+	route := fmt.Sprintf("%s?id=%d", API_Coordinates, id)
+	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
diff --git a/traffic_ops/client/deliveryservice_request_comments.go b/traffic_ops/client/deliveryservice_request_comments.go
new file mode 100644
index 000000000..ffd321ff6
--- /dev/null
+++ b/traffic_ops/client/deliveryservice_request_comments.go
@@ -0,0 +1,115 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"net"
+	"net/http"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+
+	"fmt"
+)
+
+const (
+	API_DeliveryServiceRequestComments = apiBase + "/deliveryservice_request_comments"
+)
+
+// Create a delivery service request comment
+func (to *Session) CreateDeliveryServiceRequestComment(comment tc.DeliveryServiceRequestComment) (tc.Alerts, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(comment)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	resp, remoteAddr, err := to.request(http.MethodPost, API_DeliveryServiceRequestComments, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// Update a delivery service request by ID
+func (to *Session) UpdateDeliveryServiceRequestCommentByID(id int, comment tc.DeliveryServiceRequestComment) (tc.Alerts, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(comment)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	route := fmt.Sprintf("%s?id=%d", API_DeliveryServiceRequestComments, id)
+	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// Returns a list of delivery service request comments
+func (to *Session) GetDeliveryServiceRequestComments() ([]tc.DeliveryServiceRequestComment, ReqInf, error) {
+	resp, remoteAddr, err := to.request(http.MethodGet, API_DeliveryServiceRequestComments, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.DeliveryServiceRequestCommentsResponse
+	err = json.NewDecoder(resp.Body).Decode(&data)
+	return data.Response, reqInf, nil
+}
+
+// GET a delivery service request comment by ID
+func (to *Session) GetDeliveryServiceRequestCommentByID(id int) ([]tc.DeliveryServiceRequestComment, ReqInf, error) {
+	route := fmt.Sprintf("%s?id=%d", API_DeliveryServiceRequestComments, id)
+	resp, remoteAddr, err := to.request(http.MethodGet, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.DeliveryServiceRequestCommentsResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// DELETE a delivery service request comment by ID
+func (to *Session) DeleteDeliveryServiceRequestCommentByID(id int) (tc.Alerts, ReqInf, error) {
+	route := fmt.Sprintf("%s?id=%d", API_DeliveryServiceRequestComments, id)
+	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
diff --git a/traffic_ops/client/deliveryservice_requests.go b/traffic_ops/client/deliveryservice_requests.go
new file mode 100644
index 000000000..2847833c9
--- /dev/null
+++ b/traffic_ops/client/deliveryservice_requests.go
@@ -0,0 +1,188 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"io/ioutil"
+	"net"
+	"net/http"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+const (
+	API_DS_REQUESTS = apiBase + "/deliveryservice_requests"
+)
+
+// Create a Delivery Service Request
+func (to *Session) CreateDeliveryServiceRequest(dsr tc.DeliveryServiceRequest) (tc.Alerts, ReqInf, error) {
+
+	var alerts tc.Alerts
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(dsr)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return alerts, reqInf, err
+	}
+	resp, remoteAddr, err := to.rawRequest(http.MethodPost, API_DS_REQUESTS, reqBody)
+	defer resp.Body.Close()
+
+	if err == nil {
+		body, readErr := ioutil.ReadAll(resp.Body)
+		if readErr != nil {
+			return alerts, reqInf, readErr
+		}
+		if err = json.Unmarshal(body, &alerts); err != nil {
+			return alerts, reqInf, err
+		}
+	}
+
+	return alerts, reqInf, err
+}
+
+// GetDeliveryServiceRequests retrieves all deliveryservices available to session user.
+func (to *Session) GetDeliveryServiceRequests() ([]tc.DeliveryServiceRequest, ReqInf, error) {
+	resp, remoteAddr, err := to.request(http.MethodGet, API_DS_REQUESTS, nil)
+
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	data := struct {
+		Response []tc.DeliveryServiceRequest `json:"response"`
+	}{}
+	if err = json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// GET a DeliveryServiceRequest by the DeliveryServiceRequest XMLID
+func (to *Session) GetDeliveryServiceRequestByXMLID(XMLID string) ([]tc.DeliveryServiceRequest, ReqInf, error) {
+	route := fmt.Sprintf("%s?xmlId=%s", API_DS_REQUESTS, XMLID)
+	resp, remoteAddr, err := to.request(http.MethodGet, route, nil)
+
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	data := struct {
+		Response []tc.DeliveryServiceRequest `json:"response"`
+	}{}
+	if err = json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// GET a DeliveryServiceRequest by the DeliveryServiceRequest id
+func (to *Session) GetDeliveryServiceRequestByID(id int) ([]tc.DeliveryServiceRequest, ReqInf, error) {
+	route := fmt.Sprintf("%s?id=%d", API_DS_REQUESTS, id)
+	resp, remoteAddr, err := to.request(http.MethodGet, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	data := struct {
+		Response []tc.DeliveryServiceRequest `json:"response"`
+	}{}
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// Update a DeliveryServiceRequest by ID
+func (to *Session) UpdateDeliveryServiceRequestByID(id int, dsr tc.DeliveryServiceRequest) (tc.Alerts, ReqInf, error) {
+
+	route := fmt.Sprintf("%s?id=%d", API_DS_REQUESTS, id)
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(dsr)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// DELETE a DeliveryServiceRequest by DeliveryServiceRequest assignee
+func (to *Session) DeleteDeliveryServiceRequestByID(id int) (tc.Alerts, ReqInf, error) {
+	route := fmt.Sprintf("%s?id=%d", API_DS_REQUESTS, id)
+	resp, remoteAddr, err := to.rawRequest(http.MethodDelete, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+/*
+
+// Returns a list of DeliveryServiceRequests
+func (to *Session) GetDeliveryServiceRequests() ([]tc.DeliveryServiceRequest, ReqInf, error) {
+	resp, remoteAddr, err := to.request(http.MethodGet, API_DS_REQUESTS, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.DeliveryServiceRequestsResponse
+	err = json.NewDecoder(resp.Body).Decode(&data)
+	return data.Response, reqInf, nil
+}
+
+// GET a DeliveryServiceRequest by the DeliveryServiceRequest assignee
+func (to *Session) GetDeliveryServiceRequestByAssignee(assignee string) ([]tc.DeliveryServiceRequest, ReqInf, error) {
+	url := fmt.Sprintf("%s/assignee/%s", API_DS_REQUESTS, assignee)
+	resp, remoteAddr, err := to.request(http.MethodGet, url, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.DeliveryServiceRequestsResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+*/
diff --git a/traffic_ops/client/deliveryserviceserver.go b/traffic_ops/client/deliveryserviceserver.go
new file mode 100644
index 000000000..7f30d9bf9
--- /dev/null
+++ b/traffic_ops/client/deliveryserviceserver.go
@@ -0,0 +1,67 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"strconv"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+	"github.com/apache/trafficcontrol/lib/go-util"
+)
+
+func (to *Session) GetDeliveryServiceServers() ([]tc.DeliveryServiceServer, ReqInf, error) {
+	path := apiBase + `/deliveryserviceserver`
+	// deliveryService
+	resp := tc.DeliveryServiceServerResponse{}
+	reqInf, err := get(to, path, &resp)
+	if err != nil {
+		return nil, reqInf, err
+	}
+	return resp.Response, reqInf, nil
+}
+
+// CreateDeliveryServiceServers associates the given servers with the given delivery services. If replace is true, it deletes any existing associations for the given delivery service.
+func (to *Session) CreateDeliveryServiceServers(dsID int, serverIDs []int, replace bool) (*tc.DSServerIDs, error) {
+	path := apiBase + `/deliveryserviceserver`
+	req := tc.DSServerIDs{
+		DeliveryServiceID: util.IntPtr(dsID),
+		ServerIDs:         serverIDs,
+		Replace:           util.BoolPtr(replace),
+	}
+	jsonReq, err := json.Marshal(&req)
+	if err != nil {
+		return nil, err
+	}
+	resp := struct {
+		Response tc.DSServerIDs `json:"response"`
+	}{}
+	if err := post(to, path, jsonReq, &resp); err != nil {
+		return nil, err
+	}
+	return &resp.Response, nil
+}
+
+// DeleteDeliveryService deletes the given delivery service server association.
+func (to *Session) DeleteDeliveryServiceServer(dsID int, serverID int) error {
+	path := apiBase + `/deliveryservice_server/` + strconv.Itoa(dsID) + `/` + strconv.Itoa(serverID)
+	resp := struct{ tc.Alerts }{}
+	err := del(to, path, &resp)
+	if err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/traffic_ops/client/division.go b/traffic_ops/client/division.go
new file mode 100644
index 000000000..a720da284
--- /dev/null
+++ b/traffic_ops/client/division.go
@@ -0,0 +1,146 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+	"net/http"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+const (
+	API_v13_Divisions = apiBase + "/divisions"
+)
+
+// Create a Division
+func (to *Session) CreateDivision(division tc.Division) (tc.Alerts, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(division)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	resp, remoteAddr, err := to.request(http.MethodPost, API_v13_Divisions, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// Update a Division by ID
+func (to *Session) UpdateDivisionByID(id int, division tc.Division) (tc.Alerts, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(division)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	route := fmt.Sprintf("%s/%d", API_v13_Divisions, id)
+	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// Returns a list of Divisions
+func (to *Session) GetDivisions() ([]tc.Division, ReqInf, error) {
+	resp, remoteAddr, err := to.request(http.MethodGet, API_v13_Divisions, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.DivisionsResponse
+	err = json.NewDecoder(resp.Body).Decode(&data)
+	return data.Response, reqInf, nil
+}
+
+// GET a Division by the Division id
+func (to *Session) GetDivisionByID(id int) ([]tc.Division, ReqInf, error) {
+	route := fmt.Sprintf("%s/%d", API_v13_Divisions, id)
+	resp, remoteAddr, err := to.request(http.MethodGet, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.DivisionsResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// GET a Division by the Division name
+func (to *Session) GetDivisionByName(name string) ([]tc.Division, ReqInf, error) {
+	url := fmt.Sprintf("%s?name=%s", API_v13_Divisions, name)
+	resp, remoteAddr, err := to.request(http.MethodGet, url, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.DivisionsResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// DELETE a Division by Division id
+func (to *Session) DeleteDivisionByID(id int) (tc.Alerts, ReqInf, error) {
+	route := fmt.Sprintf("%s/%d", API_v13_Divisions, id)
+	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// DELETE a Division by Division name
+func (to *Session) DeleteDivisionByName(name string) (tc.Alerts, ReqInf, error) {
+	route := fmt.Sprintf("%s/name/%s", API_v13_Divisions, name)
+	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
diff --git a/traffic_ops/client/origin.go b/traffic_ops/client/origin.go
new file mode 100644
index 000000000..05a8ac3bb
--- /dev/null
+++ b/traffic_ops/client/origin.go
@@ -0,0 +1,126 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+	"net/http"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+const (
+	API_Origins = apiBase + "/origins"
+)
+
+// Create an Origin
+func (to *Session) CreateOrigin(origin Origin) (*OriginDetailResponse, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(origin)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	resp, remoteAddr, err := to.request(http.MethodPost, API_Origins, reqBody)
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+	var originResp OriginDetailResponse
+	if err = json.NewDecoder(resp.Body).Decode(&originResp); err != nil {
+		return nil, reqInf, err
+	}
+	return &originResp, reqInf, nil
+}
+
+// Update an Origin by ID
+func (to *Session) UpdateOriginByID(id int, origin Origin) (*OriginDetailResponse, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(origin)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	route := fmt.Sprintf("%s?id=%d", API_Origins, id)
+	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody)
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+	var originResp OriginDetailResponse
+	if err = json.NewDecoder(resp.Body).Decode(&originResp); err != nil {
+		return nil, reqInf, err
+	}
+	return &originResp, reqInf, nil
+}
+
+// GET a list of Origins by a query parameter string
+func (to *Session) GetOriginsByQueryParams(queryParams string) ([]Origin, ReqInf, error) {
+	URI := API_Origins + queryParams
+	resp, remoteAddr, err := to.request(http.MethodGet, URI, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data OriginsResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// Returns a list of Origins
+func (to *Session) GetOrigins() ([]Origin, ReqInf, error) {
+	return to.GetOriginsByQueryParams("")
+}
+
+// GET an Origin by the Origin ID
+func (to *Session) GetOriginByID(id int) ([]Origin, ReqInf, error) {
+	return to.GetOriginsByQueryParams(fmt.Sprintf("?id=%d", id))
+}
+
+// GET an Origin by the Origin name
+func (to *Session) GetOriginByName(name string) ([]Origin, ReqInf, error) {
+	return to.GetOriginsByQueryParams(fmt.Sprintf("?name=%s", name))
+}
+
+// GET a list of Origins by Delivery Service ID
+func (to *Session) GetOriginsByDeliveryServiceID(id int) ([]Origin, ReqInf, error) {
+	return to.GetOriginsByQueryParams(fmt.Sprintf("?deliveryservice=%d", id))
+}
+
+// DELETE an Origin by ID
+func (to *Session) DeleteOriginByID(id int) (tc.Alerts, ReqInf, error) {
+	route := fmt.Sprintf("%s?id=%d", API_Origins, id)
+	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	return alerts, reqInf, nil
+}
diff --git a/traffic_ops/client/phys_location.go b/traffic_ops/client/phys_location.go
index e15a467e3..e0664ec2e 100644
--- a/traffic_ops/client/phys_location.go
+++ b/traffic_ops/client/phys_location.go
@@ -25,7 +25,7 @@ import (
 )
 
 const (
-	API_v13_PHYS_LOCATIONS = "/api/1.3/phys_locations"
+	API_v13_PHYS_LOCATIONS = apiBase + "/phys_locations"
 )
 
 // Create a PhysLocation
diff --git a/traffic_ops/client/ping.go b/traffic_ops/client/ping.go
new file mode 100644
index 000000000..db38b52b2
--- /dev/null
+++ b/traffic_ops/client/ping.go
@@ -0,0 +1,39 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"net/http"
+)
+
+const (
+	API_PING = apiBase + "/ping"
+)
+
+// Ping returns a static json object to show that traffic_ops is responsive
+func (to *Session) Ping() (map[string]string, ReqInf, error) {
+	resp, remoteAddr, err := to.request(http.MethodGet, API_PING, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data map[string]string
+	err = json.NewDecoder(resp.Body).Decode(&data)
+	return data, reqInf, nil
+}
diff --git a/traffic_ops/client/profile_parameter.go b/traffic_ops/client/profile_parameter.go
new file mode 100644
index 000000000..c261295f0
--- /dev/null
+++ b/traffic_ops/client/profile_parameter.go
@@ -0,0 +1,96 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+	"net/http"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+const (
+	API_Profile_Parameters = apiBase + "/profileparameters"
+	ProfileIdQueryParam    = "profileId"
+	ParameterIdQueryParam  = "parameterId"
+)
+
+// Create a ProfileParameter
+func (to *Session) CreateProfileParameter(pp ProfileParameter) (tc.Alerts, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(pp)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	resp, remoteAddr, err := to.request(http.MethodPost, API_Profile_Parameters, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// Returns a list of Profile Parameters
+func (to *Session) GetProfileParameters() ([]ProfileParameter, ReqInf, error) {
+	resp, remoteAddr, err := to.request(http.MethodGet, API_Profile_Parameters, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data ProfileParametersResponse
+	err = json.NewDecoder(resp.Body).Decode(&data)
+	return data.Response, reqInf, nil
+}
+
+// GET a Profile Parameter by the Parameter
+func (to *Session) GetProfileParameterByQueryParams(queryParams string) ([]ProfileParameter, ReqInf, error) {
+	URI := API_Profile_Parameters + queryParams
+	resp, remoteAddr, err := to.request(http.MethodGet, URI, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data ProfileParametersResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// DELETE a Parameter by Parameter
+func (to *Session) DeleteParameterByProfileParameter(profile int, parameter int) (tc.Alerts, ReqInf, error) {
+	URI := fmt.Sprintf("%s/profile/%d/parameter/%d", API_Profile_Parameters, profile, parameter)
+	resp, remoteAddr, err := to.request(http.MethodDelete, URI, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
diff --git a/traffic_ops/client/region.go b/traffic_ops/client/region.go
new file mode 100644
index 000000000..d6a016b40
--- /dev/null
+++ b/traffic_ops/client/region.go
@@ -0,0 +1,149 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+	"net/http"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+const (
+	API_REGIONS = apiBase + "/regions"
+)
+
+// Create a Region
+func (to *Session) CreateRegion(region tc.Region) (tc.Alerts, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(region)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	resp, remoteAddr, err := to.request(http.MethodPost, API_REGIONS, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// Update a Region by ID
+func (to *Session) UpdateRegionByID(id int, region tc.Region) (tc.Alerts, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(region)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	route := fmt.Sprintf("%s/%d", API_REGIONS, id)
+	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// Returns a list of regions
+func (to *Session) GetRegions() ([]tc.Region, ReqInf, error) {
+	resp, remoteAddr, err := to.request(http.MethodGet, API_REGIONS, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.RegionsResponse
+	err = json.NewDecoder(resp.Body).Decode(&data)
+	return data.Response, reqInf, nil
+}
+
+// GET a Region by the Region id
+func (to *Session) GetRegionByID(id int) ([]tc.Region, ReqInf, error) {
+	route := fmt.Sprintf("%s/%d", API_REGIONS, id)
+	resp, remoteAddr, err := to.request(http.MethodGet, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.RegionsResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// GET a Region by the Region name
+func (to *Session) GetRegionByName(name string) ([]tc.Region, ReqInf, error) {
+	url := fmt.Sprintf("%s?name=%s", API_REGIONS, name)
+	resp, remoteAddr, err := to.request(http.MethodGet, url, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.RegionsResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// DELETE a Region by ID
+func (to *Session) DeleteRegionByID(id int) (tc.Alerts, ReqInf, error) {
+	route := fmt.Sprintf("%s/%d", API_REGIONS, id)
+	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// GetRegionByNamePath gets a region by name, using the /api/version/region/name path. This gets the same data as GetRegionByName, but uses a different API path to get the same data, and returns a slightly different format.
+func (to *Session) GetRegionByNamePath(name string) ([]tc.RegionName, ReqInf, error) {
+	url := apiBase + `/regions/name/` + name
+	reqResp, remoteAddr, err := to.request(http.MethodGet, url, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer reqResp.Body.Close()
+
+	resp := tc.RegionNameResponse{}
+	if err := json.NewDecoder(reqResp.Body).Decode(&resp); err != nil {
+		return nil, reqInf, err
+	}
+	return resp.Response, reqInf, nil
+}
diff --git a/traffic_ops/client/role.go b/traffic_ops/client/role.go
new file mode 100644
index 000000000..1d18628f4
--- /dev/null
+++ b/traffic_ops/client/role.go
@@ -0,0 +1,139 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+	"net/http"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+const (
+	API_ROLES = apiBase + "/roles"
+)
+
+// Create a Role
+func (to *Session) CreateRole(region Role) (tc.Alerts, ReqInf, int, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(region)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, 0, err
+	}
+	resp, remoteAddr, errClient := to.rawRequest(http.MethodPost, API_ROLES, reqBody)
+	if resp != nil {
+		defer resp.Body.Close()
+		var alerts tc.Alerts
+		if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
+			return alerts, reqInf, resp.StatusCode, err
+		}
+		return alerts, reqInf, resp.StatusCode, errClient
+	}
+	return tc.Alerts{}, reqInf, 0, errClient
+}
+
+// Update a Role by ID
+func (to *Session) UpdateRoleByID(id int, region Role) (tc.Alerts, ReqInf, int, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(region)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, 0, err
+	}
+	route := fmt.Sprintf("%s/?id=%d", API_ROLES, id)
+	resp, remoteAddr, errClient := to.rawRequest(http.MethodPut, route, reqBody)
+	if resp != nil {
+		defer resp.Body.Close()
+		var alerts tc.Alerts
+		if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
+			return alerts, reqInf, resp.StatusCode, err
+		}
+		return alerts, reqInf, resp.StatusCode, errClient
+	}
+	return tc.Alerts{}, reqInf, 0, errClient
+}
+
+// Returns a list of roles
+func (to *Session) GetRoles() ([]Role, ReqInf, int, error) {
+	resp, remoteAddr, errClient := to.rawRequest(http.MethodGet, API_ROLES, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if resp != nil {
+		defer resp.Body.Close()
+
+		var data RolesResponse
+		if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+			return data.Response, reqInf, resp.StatusCode, err
+		}
+		return data.Response, reqInf, resp.StatusCode, errClient
+	}
+	return []Role{}, reqInf, 0, errClient
+}
+
+// GET a Role by the Role id
+func (to *Session) GetRoleByID(id int) ([]Role, ReqInf, int, error) {
+	route := fmt.Sprintf("%s/?id=%d", API_ROLES, id)
+	resp, remoteAddr, errClient := to.rawRequest(http.MethodGet, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if resp != nil {
+		defer resp.Body.Close()
+
+		var data RolesResponse
+		if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+			return data.Response, reqInf, resp.StatusCode, err
+		}
+		return data.Response, reqInf, resp.StatusCode, errClient
+	}
+	return []Role{}, reqInf, 0, errClient
+}
+
+// GET a Role by the Role name
+func (to *Session) GetRoleByName(name string) ([]Role, ReqInf, int, error) {
+	url := fmt.Sprintf("%s?name=%s", API_ROLES, name)
+	resp, remoteAddr, errClient := to.rawRequest(http.MethodGet, url, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if resp != nil {
+		defer resp.Body.Close()
+
+		var data RolesResponse
+		if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+			return data.Response, reqInf, resp.StatusCode, err
+		}
+		return data.Response, reqInf, resp.StatusCode, errClient
+	}
+	return []Role{}, reqInf, 0, errClient
+}
+
+// DELETE a Role by ID
+func (to *Session) DeleteRoleByID(id int) (tc.Alerts, ReqInf, int, error) {
+	route := fmt.Sprintf("%s/?id=%d", API_ROLES, id)
+	resp, remoteAddr, errClient := to.rawRequest(http.MethodDelete, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if resp != nil {
+		defer resp.Body.Close()
+
+		var alerts tc.Alerts
+		if err := json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
+			return alerts, reqInf, resp.StatusCode, err
+		}
+		return alerts, reqInf, resp.StatusCode, errClient
+	}
+	return tc.Alerts{}, reqInf, 0, errClient
+}
diff --git a/traffic_ops/client/staticdnsentry.go b/traffic_ops/client/staticdnsentry.go
new file mode 100644
index 000000000..7a6a5fd27
--- /dev/null
+++ b/traffic_ops/client/staticdnsentry.go
@@ -0,0 +1,134 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+	"net/http"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+const (
+	API_StaticDNSEntries = apiBase + "/staticdnsentries"
+)
+
+// Create a StaticDNSEntry
+func (to *Session) CreateStaticDNSEntry(cdn StaticDNSEntry) (tc.Alerts, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(cdn)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	resp, remoteAddr, err := to.request(http.MethodPost, API_StaticDNSEntries, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// Update a StaticDNSEntry by ID
+func (to *Session) UpdateStaticDNSEntryByID(id int, cdn StaticDNSEntry) (tc.Alerts, ReqInf, int, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(cdn)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, 0, err
+	}
+	route := fmt.Sprintf("%s?id=%d", API_StaticDNSEntries, id)
+	resp, remoteAddr, errClient := to.rawRequest(http.MethodPut, route, reqBody)
+	if resp != nil {
+		defer resp.Body.Close()
+		var alerts tc.Alerts
+		if err = json.NewDecoder(resp.Body).Decode(&alerts); err != nil {
+			return alerts, reqInf, resp.StatusCode, err
+		}
+		return alerts, reqInf, resp.StatusCode, errClient
+	}
+	return tc.Alerts{}, reqInf, 0, errClient
+}
+
+// Returns a list of StaticDNSEntrys
+func (to *Session) GetStaticDNSEntries() ([]StaticDNSEntry, ReqInf, error) {
+	resp, remoteAddr, err := to.request(http.MethodGet, API_StaticDNSEntries, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data StaticDNSEntriesResponse
+	err = json.NewDecoder(resp.Body).Decode(&data)
+	return data.Response, reqInf, nil
+}
+
+// GET a StaticDNSEntry by the StaticDNSEntry ID
+func (to *Session) GetStaticDNSEntryByID(id int) ([]StaticDNSEntry, ReqInf, error) {
+	route := fmt.Sprintf("%s?id=%d", API_StaticDNSEntries, id)
+	resp, remoteAddr, err := to.request(http.MethodGet, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data StaticDNSEntriesResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// GET a StaticDNSEntry by the StaticDNSEntry hsot
+func (to *Session) GetStaticDNSEntriesByHost(host string) ([]StaticDNSEntry, ReqInf, error) {
+	url := fmt.Sprintf("%s?host=%s", API_StaticDNSEntries, host)
+	resp, remoteAddr, err := to.request(http.MethodGet, url, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data StaticDNSEntriesResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// DELETE a StaticDNSEntry by ID
+func (to *Session) DeleteStaticDNSEntryByID(id int) (tc.Alerts, ReqInf, error) {
+	route := fmt.Sprintf("%s?id=%d", API_StaticDNSEntries, id)
+	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
diff --git a/traffic_ops/client/status.go b/traffic_ops/client/status.go
new file mode 100644
index 000000000..e625f3029
--- /dev/null
+++ b/traffic_ops/client/status.go
@@ -0,0 +1,132 @@
+/*
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package client
+
+import (
+	"encoding/json"
+	"fmt"
+	"net"
+	"net/http"
+
+	"github.com/apache/trafficcontrol/lib/go-tc"
+)
+
+const (
+	API_STATUSES = apiBase + "/statuses"
+)
+
+// Create a Status
+func (to *Session) CreateStatus(status tc.Status) (tc.Alerts, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(status)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	resp, remoteAddr, err := to.request(http.MethodPost, API_STATUSES, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// Update a Status by ID
+func (to *Session) UpdateStatusByID(id int, status tc.Status) (tc.Alerts, ReqInf, error) {
+
+	var remoteAddr net.Addr
+	reqBody, err := json.Marshal(status)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	route := fmt.Sprintf("%s/%d", API_STATUSES, id)
+	resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody)
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
+
+// Returns a list of Statuses
+func (to *Session) GetStatuses() ([]tc.Status, ReqInf, error) {
+	resp, remoteAddr, err := to.request(http.MethodGet, API_STATUSES, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.StatusesResponse
+	err = json.NewDecoder(resp.Body).Decode(&data)
+	return data.Response, reqInf, nil
+}
+
+// GET a Status by the Status id
+func (to *Session) GetStatusByID(id int) ([]tc.Status, ReqInf, error) {
+	route := fmt.Sprintf("%s/%d", API_STATUSES, id)
+	resp, remoteAddr, err := to.request(http.MethodGet, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.StatusesResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// GET a Status by the Status name
+func (to *Session) GetStatusByName(name string) ([]tc.Status, ReqInf, error) {
+	url := fmt.Sprintf("%s?name=%s", API_STATUSES, name)
+	resp, remoteAddr, err := to.request(http.MethodGet, url, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return nil, reqInf, err
+	}
+	defer resp.Body.Close()
+
+	var data tc.StatusesResponse
+	if err := json.NewDecoder(resp.Body).Decode(&data); err != nil {
+		return nil, reqInf, err
+	}
+
+	return data.Response, reqInf, nil
+}
+
+// DELETE a Status by id
+func (to *Session) DeleteStatusByID(id int) (tc.Alerts, ReqInf, error) {
+	route := fmt.Sprintf("%s/%d", API_STATUSES, id)
+	resp, remoteAddr, err := to.request(http.MethodDelete, route, nil)
+	reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr}
+	if err != nil {
+		return tc.Alerts{}, reqInf, err
+	}
+	defer resp.Body.Close()
+	var alerts tc.Alerts
+	err = json.NewDecoder(resp.Body).Decode(&alerts)
+	return alerts, reqInf, nil
+}
diff --git a/traffic_ops/client/v14/README.md b/traffic_ops/client/v14/README.md
new file mode 100644
index 000000000..9f84b01a6
--- /dev/null
+++ b/traffic_ops/client/v14/README.md
@@ -0,0 +1,4 @@
+
+#### Traffic Ops Client Version 1.4
+
+As new updates are being made for the next minor version for the TO client, they will be put into this directory.
diff --git a/traffic_ops/testing/api/tc-fixtures.json b/traffic_ops/testing/api/tc-fixtures.json
new file mode 100644
index 000000000..870021a08
--- /dev/null
+++ b/traffic_ops/testing/api/tc-fixtures.json
@@ -0,0 +1,1440 @@
+{
+    "asns": [
+        {
+            "asn": 8888,
+            "cachegroupName": "mid-northeast-group"
+        },
+        {
+            "asn": 9999,
+            "cachegroupName": "edge_cg4"
+        }
+    ],
+    "cachegroups": [
+        {
+            "latitude": 0,
+            "longitude": 0,
+            "name": "originCachegroup",
+            "shortName": "og1",
+            "typeName": "ORG_LOC"
+        },
+        {
+            "latitude": 0,
+            "longitude": 0,
+            "name": "parentCachegroup",
+            "shortName": "pg1",
+            "typeName": "MID_LOC"
+        },
+        {
+            "latitude": 0,
+            "longitude": 0,
+            "name": "secondaryCachegroup",
+            "shortName": "sg1",
+            "typeName": "MID_LOC"
+        },
+        {
+            "latitude": 0,
+            "longitude": 0,
+            "name": "cachegroup1",
+            "parentCachegroupName": "parentCachegroup",
+            "secondaryParentCachegroupName": "secondaryCachegroup",
+            "shortName": "cg1",
+            "localizationMethods": [
+                "CZ",
+                "DEEP_CZ",
+                "GEO"
+            ],
+            "typeName": "EDGE_LOC"
+        },
+        {
+            "latitude": 24.1234,
+            "longitude": -121.1234,
+            "name": "cachegroup2",
+            "parentCachegroupName": "parentCachegroup",
+            "secondaryParentCachegroupName": "secondaryCachegroup",
+            "shortName": "cg2",
+            "typeName": "EDGE_LOC"
+        }
+    ],
+    "cdns": [
+        {
+            "dnssecEnabled": false,
+            "domainName": "test.cdn1.net",
+            "name": "cdn1"
+        },
+        {
+            "dnssecEnabled": false,
+            "domainName": "test.cdn2.net",
+            "name": "cdn2"
+        },
+        {
+            "dnssecEnabled": false,
+            "domainName": "test.cdn3.net",
+            "name": "cdn3"
+        },
+        {
+            "dnssecEnabled": false,
+            "domainName": "test.cdn4.net",
+            "name": "cdn4"
+        }
+    ],
+    "deliveryServiceRequestComments": [
+        {
+            "value": "this is comment one"
+        },
+        {
+            "value": "this is comment two"
+        },
+        {
+            "value": "this is comment three"
+        },
+        {
+            "value": "this is comment four"
+        }
+    ],
+    "deliveryServiceRequests": [
+        {
+            "changeType": "create",
+            "deliveryService": {
+                "active": true,
+                "ccrDnsTtl": 30,
+                "deepCachingType": "NEVER",
+                "displayName": "Good Kabletown CDN",
+                "dscp": 1,
+                "geoLimit": 1,
+                "geoProvider": 1,
+                "initialDispersion": 1,
+                "logsEnabled": true,
+                "longDesc": "long desc",
+                "regionalGeoBlocking": true,
+                "routingName": "goodroute",
+                "tenantId": 2,
+                "type": "HTTP",
+                "xmlId": "test-ds1"
+            },
+            "status": "draft"
+        },
+        {
+            "changeType": "create",
+            "deliveryService": {
+                "active": true,
+                "ccrDnsTtl": 30,
+                "deepCachingType": "NEVER",
+                "displayName": "Bad Tenant",
+                "dscp": 0,
+                "geoLimit": 0,
+                "geoProvider": 0,
+                "initialDispersion": 3,
+                "logsEnabled": false,
+                "longDesc": "long desc",
+                "regionalGeoBlocking": false,
+                "tenantId": 1,
+                "type": "HTTP",
+                "xmlId": "test-ds1"
+            },
+            "status": "draft"
+        },
+        {
+            "changeType": "create",
+            "deliveryService": {
+                "ccrDnsTtl": 30,
+                "deepCachingType": "NEVER",
+                "displayName": "Bad Test Case CDN",
+                "dscp": 0,
+                "geoLimit": 0,
+                "geoProvider": 1,
+                "infoUrl": "xxx",
+                "initialDispersion": 1,
+                "logsEnabled": true,
+                "longDesc": "long desc",
+                "orgServerFqdn": "xxx",
+                "regionalGeoBlocking": true,
+                "routingName": "x routing",
+                "tenantId": 2,
+                "type": "HTTP",
+                "xmlId": "test ds1"
+            },
+            "status": "draft"
+        },
+        {
+            "changeType": "update",
+            "deliveryService": {
+                "active": false,
+                "ccrDnsTtl": 30,
+                "deepCachingType": "NEVER",
+                "displayName": "Testing transitions",
+                "dscp": 3,
+                "geoLimit": 1,
+                "geoProvider": 1,
+                "initialDispersion": 1,
+                "logsEnabled": true,
+                "longDesc": "long desc",
+                "regionalGeoBlocking": true,
+                "routingName": "goodroute",
+                "tenantId": 2,
+                "type": "HTTP",
+                "xmlId": "test-transitions"
+            },
+            "status": "draft"
+        }
+    ],
+    "deliveryServices": [
+        {
+            "active": true,
+            "cacheurl": "cacheUrl1",
+            "ccrDnsTtl": 3600,
+            "cdnName": "cdn1",
+            "checkPath": "",
+            "deepCachingType": "NEVER",
+            "displayName": "ds1DisplayName",
+            "dnsBypassCname": null,
+            "dnsBypassIp": "",
+            "dnsBypassIp6": "",
+            "dnsBypassTtl": 30,
+            "dscp": 40,
+            "edgeHeaderRewrite": "edgeHeader1",
+            "exampleURLs": [
+                "http://ccr.ds1.example.net",
+                "https://ccr.ds1.example.net"
+            ],
+            "fqPacingRate": 0,
+            "geoLimit": 0,
+            "geoLimitCountries": "",
+            "geoLimitRedirectURL": null,
+            "geoProvider": 0,
+            "globalMaxMbps": 0,
+            "globalMaxTps": 0,
+            "httpBypassFqdn": "",
+            "infoUrl": "TBD",
+            "initialDispersion": 1,
+            "ipv6RoutingEnabled": true,
+            "lastUpdated": "2018-04-06 16:48:51+00",
+            "logsEnabled": false,
+            "longDesc": "d s 1",
+            "longDesc1": "ds1",
+            "longDesc2": "ds1",
+            "matchList": [
+                {
+                    "pattern": ".*\\.ds1\\..*",
+                    "setNumber": 0,
+                    "type": "HOST_REGEXP"
+                }
+            ],
+            "maxDnsAnswers": 0,
+            "midHeaderRewrite": "midHeader1",
+            "missLat": 41.881944,
+            "missLong": -87.627778,
+            "multiSiteOrigin": false,
+            "orgServerFqdn": "http://origin.example.net",
+            "originShield": null,
+            "profileDescription": null,
+            "profileId": null,
+            "profileName": null,
+            "protocol": 2,
+            "qstringIgnore": 1,
+            "rangeRequestHandling": 0,
+            "regexRemap": "rr1",
+            "regionalGeoBlocking": false,
+            "remapText": "@plugin=tslua.so @pparam=/opt/trafficserver/etc/trafficserver/remapPlugin1.lua",
+            "routingName": "ccr-ds1",
+            "signed": false,
+            "signingAlgorithm": "url_sig",
+            "sslKeyVersion": 2,
+            "tenant": "tenant1",
+            "tenantName": "tenant1",
+            "type": "HTTP_LIVE",
+            "xmlId": "ds1",
+            "anonymousBlockingEnabled": true
+        },
+        {
+            "active": true,
+            "cacheurl": "cacheUrl2",
+            "ccrDnsTtl": 3600,
+            "cdnName": "cdn1",
+            "checkPath": "",
+            "deepCachingType": "NEVER",
+            "displayName": "d s 1",
+            "dnsBypassCname": null,
+            "dnsBypassIp": "",
+            "dnsBypassIp6": "",
+            "dnsBypassTtl": 30,
+            "dscp": 40,
+            "edgeHeaderRewrite": "edgeRewrite2",
+            "exampleURLs": [
+                "http://ccr.ds2.example.net",
+                "https://ccr.ds2x.example.net"
+            ],
+            "fqPacingRate": 0,
+            "geoLimit": 0,
+            "geoLimitCountries": "",
+            "geoLimitRedirectURL": null,
+            "geoProvider": 0,
+            "globalMaxMbps": 0,
+            "globalMaxTps": 0,
+            "httpBypassFqdn": "",
+            "infoUrl": "TBD",
+            "initialDispersion": 1,
+            "ipv6RoutingEnabled": true,
+            "lastUpdated": "2018-04-06 16:48:51+00",
+            "logsEnabled": false,
+            "longDesc": "d s 1",
+            "longDesc1": "ds2",
+            "longDesc2": "ds2",
+            "matchList": [
+                {
+                    "pattern": ".*\\.ds2\\..*",
+                    "setNumber": 0,
+                    "type": "HOST_REGEXP"
+                }
+            ],
+            "maxDnsAnswers": 0,
+            "midHeaderRewrite": "midRewrite2",
+            "missLat": 41.881944,
+            "missLong": -87.627778,
+            "multiSiteOrigin": false,
+            "orgServerFqdn": "http://origin.ds2.example.net",
+            "originShield": null,
+            "profileDescription": null,
+            "profileName": null,
+            "protocol": 2,
+            "qstringIgnore": 1,
+            "rangeRequestHandling": 0,
+            "regexRemap": "regexRemap2",
+            "regionalGeoBlocking": false,
+            "remapText": "@plugin=tslua.so @pparam=/opt/trafficserver/etc/trafficserver/ds2plugin.lua",
+            "routingName": "ccr-ds2",
+            "signed": false,
+            "signingAlgorithm": "url_sig",
+            "sslKeyVersion": 2,
+            "tenant": "tenant2",
+            "tenantName": "tenant2",
+            "type": "HTTP_LIVE",
+            "xmlId": "ds2",
+            "anonymousBlockingEnabled": true
+        }
+    ],
+    "divisions": [
+        {
+            "name": "division1"
+        },
+        {
+            "name": "division2"
+        }
+    ],
+    "federations": [
+        {
+            "cname": "the.cname.com.",
+            "ttl": 48,
+            "description": "the description"
+        },
+        {
+            "cname": "booya.com.",
+            "ttl": 34,
+            "description": "fooya"
+        }
+    ],
+    "coordinates": [
+        {
+            "latitude": 1.1,
+            "longitude": 2.2,
+            "name": "coordinate1"
+        },
+        {
+            "latitude": 3.3,
+            "longitude": 4.4,
+            "name": "coordinate2"
+        }
+    ],
+    "origins": [
+        {
+            "name": "origin1",
+            "fqdn": "origin1.example.com",
+            "ipAddress": "1.2.3.4",
+            "ip6Address": "dead:beef:cafe::42",
+            "port": 1234,
+            "protocol": "http",
+            "tenantId": 2
+        },
+        {
+            "name": "origin2",
+            "fqdn": "origin2.example.com",
+            "ipAddress": "5.6.7.8",
+            "ip6Address": "cafe::42",
+            "port": 5678,
+            "protocol": "https",
+            "tenantId": 2
+        }
+    ],
+    "parameters": [
+        {
+            "configFile": "rascal.properties",
+            "lastUpdated": "2018-01-19T19:01:21.455131+00:00",
+            "name": "health.threshold.loadavg",
+            "secure": false,
+            "value": "25.0"
+        },
+        {
+            "configFile": "rascal.properties",
+            "lastUpdated": "2018-01-19T19:01:21.472279+00:00",
+            "name": "health.threshold.availableBandwidthInKbps",
+            "secure": false,
+            "value": ">1750000"
+        },
+        {
+            "configFile": "rascal.properties",
+            "lastUpdated": "2018-01-19T19:01:21.489534+00:00",
+            "name": "history.count",
+            "secure": false,
+            "value": "30"
+        },
+        {
+            "configFile": "url_sig.config",
+            "lastUpdated": "2018-01-19T19:01:21.431062+00:00",
+            "name": "error_url",
+            "secure": true,
+            "value": "403"
+        },
+        {
+            "configFile": "records.config",
+            "lastUpdated": "2018-01-19T19:01:21.432692+00:00",
+            "name": "CONFIG proxy.config.allocator.debug_filter",
+            "secure": false,
+            "value": "INT 0"
+        },
+        {
+            "configFile": "records.config",
+            "lastUpdated": "2018-01-19T19:01:21.434425+00:00",
+            "name": "CONFIG proxy.config.allocator.enable_reclaim",
+            "secure": false,
+            "value": "INT 0"
+        },
+        {
+            "configFile": "records.config",
+            "lastUpdated": "2018-01-19T19:01:21.435957+00:00",
+            "name": "CONFIG proxy.config.allocator.max_overage",
+            "secure": false,
+            "value": "INT 3"
+        },
+        {
+            "configFile": "records.config",
+            "lastUpdated": "2018-01-19T19:01:21.437496+00:00",
+            "name": "CONFIG proxy.config.diags.show_location",
+            "secure": false,
+            "value": "INT 0"
+        },
+        {
+            "configFile": "records.config",
+            "lastUpdated": "2018-01-19T19:01:21.439033+00:00",
+            "name": "CONFIG proxy.config.http.cache.allow_empty_doc",
+            "secure": false,
+            "value": "INT 0"
+        },
+        {
+            "configFile": "records.config",
+            "lastUpdated": "2018-01-19T19:01:21.440502+00:00",
+            "name": "LOCAL proxy.config.cache.interim.storage",
+            "secure": false,
+            "value": "STRING NULL"
+        },
+        {
+            "configFile": "records.config",
+            "lastUpdated": "2018-01-19T19:01:21.441933+00:00",
+            "name": "CONFIG proxy.config.http.parent_proxy.file",
+            "secure": false,
+            "value": "STRING parent.config"
+        },
+        {
+            "configFile": "plugin.config",
+            "lastUpdated": "2018-01-19T19:01:21.447837+00:00",
+            "name": "astats_over_http.so",
+            "secure": false,
+            "value": "_astats 33.101.99.100,172.39.19.39,172.39.19.49,172.39.19.49,172.39.29.49"
+        },
+        {
+            "configFile": "logs_xml.config",
+            "lastUpdated": "2018-01-19T19:01:21.461206+00:00",
+            "name": "LogFormat.Name",
+            "secure": false,
+            "value": "custom_ats_2"
+        },
+        {
+            "configFile": "logs_xml.config",
+            "lastUpdated": "2018-01-19T19:01:21.462772+00:00",
+            "name": "LogObject.Format",
+            "secure": false,
+            "value": "custom_ats_2"
+        },
+        {
+            "configFile": "logs_xml.config",
+            "lastUpdated": "2018-01-19T19:01:21.464259+00:00",
+            "name": "LogObject.Filename",
+            "secure": false,
+            "value": "custom_ats_2"
+        },
+        {
+            "configFile": "records.config",
+            "lastUpdated": "2018-01-19T19:01:21.467349+00:00",
+            "name": "CONFIG proxy.config.cache.control.filename",
+            "secure": false,
+            "value": "STRING cache.config"
+        },
+        {
+            "configFile": "plugin.config",
+            "lastUpdated": "2018-01-19T19:01:21.469075+00:00",
+            "name": "regex_revalidate.so",
+            "secure": false,
+            "value": "--config regex_revalidate.config"
+        },
+        {
+            "configFile": "records.config",
+            "lastUpdated": "2018-01-19T19:01:21.49285+00:00",
+            "name": "CONFIG proxy.config.hostdb.storage_size",
+            "secure": false,
+            "value": "INT 33554432"
+        },
+        {
+            "configFile": "regex_revalidate.config",
+            "lastUpdated": "2018-01-19T19:01:21.496195+00:00",
+            "name": "maxRevalDurationDays",
+            "secure": false,
+            "value": "90"
+        },
+        {
+            "configFile": "package",
+            "lastUpdated": "2018-01-19T19:01:21.499423+00:00",
+            "name": "trafficserver",
+            "secure": false,
+            "value": "5.3.2-765.f4354b9.el7.centos.x86_64"
+        },
+        {
+            "configFile": "global",
+            "lastUpdated": "2018-01-19T19:01:21.501151+00:00",
+            "name": "use_tenancy",
+            "secure": false,
+            "value": "1"
+        }
+    ],
+    "physLocations": [
+        {
+            "address": "1234 mile high circle",
+            "city": "Denver",
+            "comments": null,
+            "email": null,
+            "lastUpdated": "2018-01-19T21:19:32.081465+00:00",
+            "name": "Denver",
+            "phone": "303-111-1111",
+            "poc": null,
+            "regionId": 100,
+            "shortName": "denver",
+            "state": "CO",
+            "zip": "80202"
+        },
+        {
+            "address": "1234 green way",
+            "city": "Boulder",
+            "comments": null,
+            "email": null,
+            "lastUpdated": "2018-01-19T21:19:32.086195+00:00",
+            "name": "Boulder",
+            "phone": "303-222-2222",
+            "poc": null,
+            "regionId": 100,
+            "shortName": "boulder",
+            "state": "CO",
+            "zip": "80301"
+        },
+        {
+            "address": "1234 southern way",
+            "city": "Atlanta",
+            "comments": null,
+            "email": null,
+            "lastUpdated": "2018-01-19T21:19:32.089538+00:00",
+            "name": "HotAtlanta",
+            "phone": "404-222-2222",
+            "poc": null,
+            "regionId": 100,
+            "shortName": "atlanta",
+            "state": "GA",
+            "zip": "30301"
+        }
+    ],
+    "profiles": [
+        {
+            "cdnName": "cdn1",
+            "description": "edge description",
+            "lastUpdated": "2018-03-02T17:27:11.796899+00:00",
+            "name": "EDGE1",
+            "routing_disabled": true,
+            "type": "ATS_PROFILE"
+        },
+        {
+            "cdnName": "cdn4",
+            "description": "edge2 description",
+            "lastUpdated": "2018-03-02T17:27:11.818418+00:00",
+            "name": "EDGE2",
+            "routing_disabled": false,
+            "type": "ATS_PROFILE"
+        },
+        {
+            "cdnName": "cdn1",
+            "description": "mid description",
+            "lastUpdated": "2018-03-02T17:27:11.80173+00:00",
+            "name": "MID1",
+            "routing_disabled": false,
+            "type": "ATS_PROFILE"
+        },
+        {
+            "cdnName": "cdn1",
+            "description": "origin description",
+            "lastUpdated": "2018-03-02T17:27:11.80173+00:00",
+            "name": "ORIGIN1",
+            "routing_disabled": false,
+            "type": "ORG_PROFILE"
+        },
+        {
+            "cdnName": "cdn1",
+            "description": "cdn1 description",
+            "lastUpdated": "2018-03-02T17:27:11.80452+00:00",
+            "name": "CCR1",
+            "routing_disabled": false,
+            "type": "TR_PROFILE"
+        },
+        {
+            "cdnName": "cdn2",
+            "description": "cdn2 description",
+            "lastUpdated": "2018-03-02T17:27:11.807948+00:00",
+            "name": "CCR2",
+            "routing_disabled": false,
+            "type": "TR_PROFILE"
+        },
+        {
+            "cdnName": "cdn1",
+            "description": "rascal description",
+            "lastUpdated": "2018-03-02T17:27:11.813052+00:00",
+            "name": "RASCAL1",
+            "routing_disabled": false,
+            "type": "TM_PROFILE"
+        }
+    ],
+    "profileParameters": [
+        {
+            "parameterId": 100
+        },
+        {
+            "parameterId": 200
+        }
+    ],
+    "regions": [
+        {
+            "divisionName": "division1",
+            "name": "region1"
+        },
+        {
+            "divisionName": "division2",
+            "name": "region2"
+        }
+    ],
+    "roles": [
+        {
+            "name": "new_admin",
+            "description": "super-user 2",
+            "privLevel": 30,
+            "capabilities": [
+                "all-read",
+                "all-write",
+                "cdn-read"
+            ]
+        },
+        {
+            "name": "bad_admin",
+            "description": "super-user 3",
+            "privLevel": 30,
+            "capabilities": [
+                "all-read",
+                "all-write",
+                "invalid-capability"
+            ]
+        }
+    ],
+    "servers": [
+        {
+            "domainName": "ga.atlanta.kabletown.net",
+            "guid": null,
+            "hostName": "atlanta-edge-01",
+            "httpsPort": null,
+            "iloIpAddress": "",
+            "iloIpGateway": "",
+            "iloIpNetmask": "",
+            "iloPassword": "",
+            "iloUsername": "",
+            "interfaceMtu": 9000,
+            "interfaceName": "bond0",
+            "ip6Address": "2345:1234:12:8::1/64",
+            "ip6Gateway": "2345:1234:12:8::1",
+            "ipAddress": "127.0.0.21",
+            "ipGateway": "127.0.0.21",
+            "ipNetmask": "255.255.255.252",
+            "lastUpdated": "2018-03-28T17:30:00.220351+00:00",
+            "mgmtIpAddress": "",
+            "mgmtIpGateway": "",
+            "mgmtIpNetmask": "",
+            "offlineReason": null,
+            "rack": "RR 119.02",
+            "revalPending": false,
+            "routerHostName": "",
+            "routerPortName": "",
+            "tcpPort": 80,
+            "typeName": "EDGE",
+            "updPending": true,
+            "xmppId": "atlanta-edge-01\\\\@ocdn.kabletown.net",
+            "xmppPasswd": "X"
+        },
+        {
+            "domainName": "kabletown.net",
+            "guid": null,
+            "hostName": "influxdb02",
+            "httpsPort": null,
+            "iloIpAddress": "",
+            "iloIpGateway": "",
+            "iloIpNetmask": "",
+            "iloPassword": "",
+            "iloUsername": "",
+            "interfaceMtu": 1500,
+            "interfaceName": "eth1",
+            "ip6Address": "2345:1234:12:8::2/64",
+            "ip6Gateway": "2345:1234:12:8::2",
+            "ipAddress": "127.0.0.11",
+            "ipGateway": "127.0.0.11",
+            "ipNetmask": "255.255.252.0",
+            "lastUpdated": "2018-03-28T17:30:00.220351+00:00",
+            "mgmtIpAddress": "",
+            "mgmtIpGateway": "",
+            "mgmtIpNetmask": "",
+            "offlineReason": null,
+            "rack": "RR 119.02",
+            "revalPending": false,
+            "routerHostName": "",
+            "routerPortName": "",
+            "tcpPort": 8086,
+            "typeName": "EDGE",
+            "updPending": true,
+            "xmppId": "",
+            "xmppPasswd": ""
+        },
+        {
+            "domainName": "ga.atlanta.kabletown.net",
+            "guid": null,
+            "hostName": "atlanta-router-01",
+            "httpsPort": null,
+            "iloIpAddress": "",
+            "iloIpGateway": "",
+            "iloIpNetmask": "",
+            "iloPassword": "",
+            "iloUsername": "",
+            "interfaceMtu": 9000,
+            "interfaceName": "bond0",
+            "ip6Address": "2345:1234:12:8::3/64",
+            "ip6Gateway": "2345:1234:12:8::3",
+            "ipAddress": "127.0.0.12",
+            "ipGateway": "127.0.0.1",
+            "ipNetmask": "255.255.255.252",
+            "lastUpdated": "2018-03-28T17:30:00.220351+00:00",
+            "mgmtIpAddress": "",
+            "mgmtIpGateway": "",
+            "mgmtIpNetmask": "",
+            "offlineReason": null,
+            "rack": "RR 119.02",
+            "revalPending": false,
+            "routerHostName": "",
+            "routerPortName": "",
+            "tcpPort": 80,
+            "typeName": "EDGE",
+            "updPending": true,
+            "xmppId": "atlanta-router-01\\\\@ocdn.kabletown.net",
+            "xmppPasswd": "X"
+        },
+        {
+            "domainName": "ga.atlanta.kabletown.net",
+            "guid": null,
+            "hostName": "atlanta-edge-03",
+            "httpsPort": null,
+            "iloIpAddress": "",
+            "iloIpGateway": "",
+            "iloIpNetmask": "",
+            "iloPassword": "",
+            "iloUsername": "",
+            "interfaceMtu": 9000,
+            "interfaceName": "bond0",
+            "ip6Address": "2345:1234:12:2::4/64",
+            "ip6Gateway": "2345:1234:12:8::4",
+            "ipAddress": "127.0.0.13",
+            "ipGateway": "127.0.0.1",
+            "ipNetmask": "255.255.255.252",
+            "lastUpdated": "2018-03-28T17:30:00.220351+00:00",
+            "mgmtIpAddress": "",
+            "mgmtIpGateway": "",
+            "mgmtIpNetmask": "",
+            "offlineReason": null,
+            "rack": "RR 119.02",
+            "revalPending": false,
+            "routerHostName": "",
+            "routerPortName": "",
+            "tcpPort": 80,
+            "typeName": "EDGE",
+            "updPending": true,
+            "xmppId": "atlanta-edge-03\\\\@ocdn.kabletown.net",
+            "xmppPasswd": "X"
+        },
+        {
+            "domainName": "ga.atlanta.kabletown.net",
+            "guid": null,
+            "hostName": "atlanta-edge-14",
+            "httpsPort": null,
+            "iloIpAddress": "",
+            "iloIpGateway": "",
+            "iloIpNetmask": "",
+            "iloPassword": "",
+            "iloUsername": "",
+            "interfaceMtu": 9000,
+            "interfaceName": "bond0",
+            "ip6Address": "2345:1234:12:8::5/64",
+            "ip6Gateway": "2345:1234:12:8::5",
+            "ipAddress": "127.0.0.14",
+            "ipGateway": "127.0.0.1",
+            "ipNetmask": "255.255.255.252",
+            "lastUpdated": "2018-03-28T17:30:00.220351+00:00",
+            "mgmtIpAddress": "",
+            "mgmtIpGateway": "",
+            "mgmtIpNetmask": "",
+            "offlineReason": null,
+            "rack": "RR 119.02",
+            "revalPending": false,
+            "routerHostName": "",
+            "routerPortName": "",
+            "tcpPort": 80,
+            "typeName": "EDGE",
+            "updPending": true,
+            "xmppId": "atlanta-edge-14\\\\@ocdn.kabletown.net",
+            "xmppPasswd": "X"
+        },
+        {
+            "domainName": "ga.atlanta.kabletown.net",
+            "guid": null,
+            "hostName": "atlanta-edge-15",
+            "httpsPort": null,
+            "iloIpAddress": "",
+            "iloIpGateway": "",
+            "iloIpNetmask": "",
+            "iloPassword": "",
+            "iloUsername": "",
+            "interfaceMtu": 9000,
+            "interfaceName": "bond0",
+            "ip6Address": "2345:1234:12:d::6/64",
+            "ip6Gateway": "2345:1234:12:d::6",
+            "ipAddress": "127.0.0.15",
+            "ipGateway": "127.0.0.7",
+            "ipNetmask": "255.255.255.252",
+            "lastUpdated": "2018-03-28T17:30:00.220351+00:00",
+            "mgmtIpAddress": "",
+            "mgmtIpGateway": "",
+            "mgmtIpNetmask": "",
+            "offlineReason": null,
+            "rack": "RR 119.02",
+            "revalPending": false,
+            "routerHostName": "",
+            "routerPortName": "",
+            "tcpPort": 80,
+            "typeName": "EDGE",
+            "updPending": true,
+            "xmppId": "atlanta-edge-15\\\\@ocdn.kabletown.net",
+            "xmppPasswd": "X"
+        },
+        {
+            "domainName": "ga.atlanta.kabletown.net",
+            "guid": null,
+            "hostName": "atlanta-mid-16",
+            "httpsPort": null,
+            "iloIpAddress": "",
+            "iloIpGateway": "",
+            "iloIpNetmask": "",
+            "iloPassword": "",
+            "iloUsername": "",
+            "interfaceMtu": 9000,
+            "interfaceName": "bond0",
+            "ip6Address": "2345:1234:12:d::7/64",
+            "ip6Gateway": "2345:1234:12:d::7",
+            "ipAddress": "127.0.0.16",
+            "ipGateway": "127.0.0.7",
+            "ipNetmask": "255.255.255.252",
+            "lastUpdated": "2018-03-28T17:30:00.220351+00:00",
+            "mgmtIpAddress": "",
+            "mgmtIpGateway": "",
+            "mgmtIpNetmask": "",
+            "offlineReason": null,
+            "rack": "RR 119.02",
+            "revalPending": false,
+            "routerHostName": "",
+            "routerPortName": "",
+            "tcpPort": 80,
+            "typeName": "MID",
+            "updPending": true,
+            "xmppId": "atlanta-mid-16\\\\@ocdn.kabletown.net",
+            "xmppPasswd": "X"
+        },
+        {
+            "domainName": "ga.atlanta.kabletown.net",
+            "guid": null,
+            "hostName": "atlanta-org-1",
+            "httpsPort": null,
+            "iloIpAddress": "",
+            "iloIpGateway": "",
+            "iloIpNetmask": "",
+            "iloPassword": "",
+            "iloUsername": "",
+            "interfaceMtu": 9000,
+            "interfaceName": "bond0",
+            "ip6Address": "2345:1234:12:d::8/64",
+            "ip6Gateway": "2345:1234:12:d::8",
+            "ipAddress": "127.0.0.17",
+            "ipGateway": "127.0.0.17",
+            "ipNetmask": "255.255.255.252",
+            "lastUpdated": "2018-03-28T17:30:00.220351+00:00",
+            "mgmtIpAddress": "",
+            "mgmtIpGateway": "",
+            "mgmtIpNetmask": "",
+            "offlineReason": null,
+            "rack": "RR 119.02",
+            "revalPending": false,
+            "routerHostName": "",
+            "routerPortName": "",
+            "tcpPort": 80,
+            "typeName": "EDGE",
+            "updPending": true,
+            "xmppId": "atlanta-org-1\\\\@ocdn.kabletown.net",
+            "xmppPasswd": "X"
+        },
+        {
+            "domainName": "ga.atlanta.kabletown.net",
+            "guid": null,
+            "hostName": "atlanta-org-2",
+            "httpsPort": null,
+            "iloIpAddress": "",
+            "iloIpGateway": "",
+            "iloIpNetmask": "",
+            "iloPassword": "",
+            "iloUsername": "",
+            "interfaceMtu": 9000,
+            "interfaceName": "bond0",
+            "ip6Address": "2345:1234:12:d::9/64",
+            "ip6Gateway": "2345:1234:12:d::9",
+            "ipAddress": "127.0.0.18",
+            "ipGateway": "127.0.0.18",
+            "ipNetmask": "255.255.255.252",
+            "lastUpdated": "2018-03-28T17:30:00.220351+00:00",
+            "mgmtIpAddress": "",
+            "mgmtIpGateway": "",
+            "mgmtIpNetmask": "",
+            "offlineReason": null,
+            "rack": "RR 119.02",
+            "revalPending": false,
+            "routerHostName": "",
+            "routerPortName": "",
+            "tcpPort": 80,
+            "typeName": "EDGE",
+            "updPending": true,
+            "xmppId": "atlanta-org-1\\\\@ocdn.kabletown.net",
+            "xmppPasswd": "X"
+        },
+        {
+            "domainName": "ga.atlanta.kabletown.net",
+            "guid": null,
+            "hostName": "atlanta-mid-01",
+            "httpsPort": null,
+            "iloIpAddress": "",
+            "iloIpGateway": "",
+            "iloIpNetmask": "",
+            "iloPassword": "",
+            "iloUsername": "",
+            "interfaceMtu": 9000,
+            "interfaceName": "bond0",
+            "ip6Address": "2345:1234:12:9::10/64",
+            "ip6Gateway": "2345:1234:12:9::10",
+            "ipAddress": "127.0.0.2",
+            "ipGateway": "127.0.0.2",
+            "ipNetmask": "255.255.255.252",
+            "lastUpdated": "2018-03-28T17:30:00.220351+00:00",
+            "mgmtIpAddress": "",
+            "mgmtIpGateway": "",
+            "mgmtIpNetmask": "",
+            "offlineReason": null,
+            "rack": "RR 119.02",
+            "revalPending": false,
+            "routerHostName": "",
+            "routerPortName": "",
+            "tcpPort": 80,
+            "typeName": "MID",
+            "updPending": true,
+            "xmppId": "atlanta-mid-01\\\\@ocdn.kabletown.net",
+            "xmppPasswd": "X"
+        },
+        {
+            "domainName": "kabletown.net",
+            "guid": null,
+            "hostName": "rascal01",
+            "httpsPort": null,
+            "iloIpAddress": "",
+            "iloIpGateway": "",
+            "iloIpNetmask": "",
+            "iloPassword": "",
+            "iloUsername": "",
+            "interfaceMtu": 9000,
+            "interfaceName": "bond0",
+            "ip6Address": "2345:1234:12:b::11/64",
+            "ip6Gateway": "2345:1234:12:b::11",
+            "ipAddress": "127.0.0.4",
+            "ipGateway": "127.0.0.4",
+            "ipNetmask": "255.255.255.252",
+            "lastUpdated": "2018-03-28T17:30:00.220351+00:00",
+            "mgmtIpAddress": "",
+            "mgmtIpGateway": "",
+            "mgmtIpNetmask": "",
+            "offlineReason": null,
+            "rack": "RR 119.02",
+            "revalPending": false,
+            "routerHostName": "",
+            "routerPortName": "",
+            "tcpPort": 81,
+            "typeName": "TRAFFIC_MONITOR",
+            "updPending": true,
+            "xmppId": "",
+            "xmppPasswd": "X"
+        },
+        {
+            "domainName": "local",
+            "guid": null,
+            "hostName": "riak",
+            "httpsPort": 8088,
+            "iloIpAddress": "",
+            "iloIpGateway": "",
+            "iloIpNetmask": "",
+            "iloPassword": "",
+            "iloUsername": "",
+            "interfaceMtu": 1500,
+            "interfaceName": "eth1",
+            "ip6Address": "2345:1234:12:b::12/64",
+            "ip6Gateway": "2345:1234:12:b::12",
+            "ipAddress": "127.0.0.1",
+            "ipGateway": "127.0.0.1",
+            "ipNetmask": "255.255.252.0",
+            "lastUpdated": "2018-03-28T17:30:00.220351+00:00",
+            "mgmtIpAddress": "",
+            "mgmtIpGateway": "",
+            "mgmtIpNetmask": "",
+            "offlineReason": null,
+            "rack": "RR 119.02",
+            "revalPending": false,
+            "routerHostName": "",
+            "routerPortName": "",
+            "tcpPort": 8088,
+            "typeName": "RIAK",
+            "updPending": true,
+            "xmppId": "",
+            "xmppPasswd": ""
+        }
+    ],
+    "staticdnsentries": [
+        {
+            "address": "192.168.0.1",
+            "cachegroup": "cachegroup2",
+            "deliveryservice": "ds1",
+            "host": "host2",
+            "type": "A_RECORD",
+            "ttl": 10
+        },
+        {
+            "address": "this.is.a.hostname.",
+            "cachegroup": "cachegroup1",
+            "deliveryservice": "ds1",
+            "host": "host1",
+            "type": "CNAME_RECORD",
+            "ttl": 10
+        },
+        {
+            "address": "2001:0db8:85a3:0000:0000:8a2e:0370:7334",
+            "cachegroup": "cachegroup2",
+            "deliveryservice": "ds1",
+            "host": "host3",
+            "ttl": 10,
+            "type": "AAAA_RECORD"
+        }
+    ],
+    "statuses": [
+        {
+            "description": "Edge: Puts server in CCR config file in this state, but CCR will never route traffic to it. Mid: Server will not be included in parent.config files for its edge caches",
+            "name": "OFFLINE"
+        },
+        {
+            "description": "Edge: Puts server in CCR config file in this state, and CCR will always route traffic to it. Mid: Server will be included in parent.config files for its edges",
+            "name": "ONLINE"
+        },
+        {
+            "description": "Edge: Puts server in CCR config file in this state, and CCR will adhere to the health protocol. Mid: N/A for now",
+            "name": "REPORTED"
+        },
+        {
+            "description": "Temporary down. Edge: XMPP client will send status OFFLINE to CCR, otherwise similar to REPORTED. Mid: Server will not be included in parent.config files for its edge caches",
+            "name": "ADMIN_DOWN"
+        },
+        {
+            "description": "Edge: 12M will not include caches in this state in CCR config files. Mid: N/A for now",
+            "name": "CCR_IGNORE"
+        },
+        {
+            "description": "Pre Production. Not active in any configuration.",
+            "name": "PRE_PROD"
+        }
+    ],
+    "tenants": [
+        {
+            "active": true,
+            "name": "tenant1",
+            "parentName": "root"
+        },
+        {
+            "active": false,
+            "name": "tenant2",
+            "parentName": "root"
+        }
+    ],
+    "types": [
+        {
+            "description": "Host header regular expression",
+            "lastUpdated": "2018-03-02T19:13:46.788583+00:00",
+            "name": "HOST_REGEXP",
+            "useInTable": "regex"
+        },
+        {
+            "description": "DNS Content routing, RAM cache, National",
+            "lastUpdated": "2018-03-02T19:13:46.792319+00:00",
+            "name": "DNS_LIVE_NATNL",
+            "useInTable": "deliveryservice"
+        },
+        {
+            "description": "Other CDN (CDS-IS, Akamai, etc)",
+            "lastUpdated": "2018-03-02T19:13:46.793921+00:00",
+            "name": "OTHER_CDN",
+            "useInTable": "server"
+        },
+        {
+            "description": "Client-Controlled Steering Delivery Service",
+            "lastUpdated": "2018-03-02T19:13:46.795291+00:00",
+            "name": "CLIENT_STEERING",
+            "useInTable": "deliveryservice"
+        },
+        {
+            "description": "influxdb type",
+            "lastUpdated": "2018-03-02T19:13:46.796707+00:00",
+            "name": "INFLUXDB",
+            "useInTable": "server"
+        },
+        {
+            "description": "riak type",
+            "lastUpdated": "2018-03-02T19:13:46.798008+00:00",
+            "name": "RIAK",
+            "useInTable": "server"
+        },
+        {
+            "description": "Origin",
+            "lastUpdated": "2018-03-02T19:13:46.799404+00:00",
+            "name": "ORG",
+            "useInTable": "server"
+        },
+        {
+            "description": "HTTP Content routing cache in RAM ",
+            "lastUpdated": "2018-03-02T19:13:46.800738+00:00",
+            "name": "HTTP_LIVE",
+            "useInTable": "deliveryservice"
+        },
+        {
+            "description": "Active Directory User",
+            "lastUpdated": "2018-03-02T19:13:46.802044+00:00",
+            "name": "ACTIVE_DIRECTORY",
+            "useInTable": "tm_user"
+        },
+        {
+            "description": "federation type resolve4",
+            "lastUpdated": "2018-03-02T19:13:46.803471+00:00",
+            "name": "RESOLVE4",
+            "useInTable": "federation"
+        },
+        {
+            "description": "Static DNS A entry",
+            "lastUpdated": "2018-03-02T19:13:46.804776+00:00",
+            "name": "A_RECORD",
+            "useInTable": "staticdnsentry"
+        },
+        {
+            "description": "Local User",
+            "lastUpdated": "2018-03-02T19:13:46.806035+00:00",
+            "name": "LOCAL",
+            "useInTable": "tm_user"
+        },
+        {
+            "description": "Weighted steering target",
+            "lastUpdated": "2018-03-02T19:13:46.80748+00:00",
+            "name": "STEERING_WEIGHT",
+            "useInTable": "steering_target"
+        },
+        {
+            "description": "HTTP Content routing, RAM cache, National",
+            "lastUpdated": "2018-03-02T19:13:46.808911+00:00",
+            "name": "HTTP_LIVE_NATNL",
+            "useInTable": "deliveryservice"
+        },
+        {
+            "description": "Ops hosts for management",
+            "lastUpdated": "2018-03-02T19:13:46.810576+00:00",
+            "name": "TOOLS_SERVER",
+            "useInTable": "server"
+        },
+        {
+            "description": "Path regular expression",
+            "lastUpdated": "2018-03-02T19:13:46.812049+00:00",
+            "name": "PATH_REGEXP",
+            "useInTable": "regex"
+        },
+        {
+            "description": "Static DNS CNAME entry",
+            "lastUpdated": "2018-03-02T19:13:46.813461+00:00",
+            "name": "CNAME_RECORD",
+            "useInTable": "staticdnsentry"
+        },
+        {
+            "description": "Kabletown Content Router",
+            "lastUpdated": "2018-03-02T19:13:46.814833+00:00",
+            "name": "CCR",
+            "useInTable": "server"
+        },
+        {
+            "description": "Origin Cachegroup",
+            "lastUpdated": "2018-03-02T19:13:46.816199+00:00",
+            "name": "ORG_LOC",
+            "useInTable": "cachegroup"
+        },
+        {
+            "description": "Mid Cachegroup",
+            "lastUpdated": "2018-03-02T19:13:46.816199+00:00",
+            "name": "MID_LOC",
+            "useInTable": "cachegroup"
+        },
+        {
+            "description": "Edge Cache",
+            "lastUpdated": "2018-03-02T19:13:46.817689+00:00",
+            "name": "EDGE",
+            "useInTable": "server"
+        },
+        {
+            "description": "Ordered steering target",
+            "lastUpdated": "2018-03-02T19:13:46.81913+00:00",
+            "name": "STEERING_ORDER",
+            "useInTable": "steering_target"
+        },
+        {
+            "description": "DNS Content Routing",
+            "lastUpdated": "2018-03-02T19:13:46.820528+00:00",
+            "name": "DNS",
+            "useInTable": "deliveryservice"
+        },
+        {
+            "description": "federation type resolve6",
+            "lastUpdated": "2018-03-02T19:13:46.822161+00:00",
+            "name": "RESOLVE6",
+            "useInTable": "federation"
+        },
+        {
+            "description": "Static DNS AAAA entry",
+            "lastUpdated": "2018-03-02T19:13:46.823506+00:00",
+            "name": "AAAA_RECORD",
+            "useInTable": "staticdnsentry"
+        },
+        {
+            "description": "HTTP Content Routing, no caching",
+            "lastUpdated": "2018-03-02T19:13:46.824798+00:00",
+            "name": "HTTP_NO_CACHE",
+            "useInTable": "deliveryservice"
+        },
+        {
+            "description": "any_map type",
+            "lastUpdated": "2018-03-02T19:13:46.826411+00:00",
+            "name": "ANY_MAP",
+            "useInTable": "deliveryservice"
+        },
+        {
+            "description": "Steering Delivery Service",
+            "lastUpdated": "2018-03-02T19:13:46.827779+00:00",
+            "name": "STEERING",
+            "useInTable": "deliveryservice"
+        },
+        {
+            "description": "Edge Cachegroup",
+            "lastUpdated": "2018-03-02T19:13:46.829249+00:00",
+            "name": "EDGE_LOC",
+            "useInTable": "cachegroup"
+        },
+        {
+            "description": "HTTP Content routing cache ",
+            "lastUpdated": "2018-03-02T19:13:46.830862+00:00",
+            "name": "HTTP",
+            "useInTable": "deliveryservice"
+        },
+        {
+            "description": "Mid Tier Cache",
+            "lastUpdated": "2018-03-02T19:13:46.832327+00:00",
+            "name": "MID",
+            "useInTable": "server"
+        },
+        {
+            "description": "Traffic Monitor (Rascal)",
+            "lastUpdated": "2018-03-02T19:13:46.832327+00:00",
+            "name": "TRAFFIC_MONITOR",
+            "useInTable": "server"
+        }
+    ],
+    "users": [
+        {
+            "addressLine1": "address of admin",
+            "addressLine2": "",
+            "city": "Anywhere",
+            "company": "Comcast",
+            "country": "USA",
+            "email": "admin@example.com",
+            "fullName": "Fred the admin",
+            "gid": 0,
+            "localPasswd": "pa$$word",
+            "newUser": false,
+            "phoneNumber": "810-555-9876",
+            "postalCode": "55443",
+            "publicSshKey": "",
+            "role": 4,
+            "rolename": "admin",
+            "stateOrProvince": "LA",
+            "tenant": "root",
+            "uid": 0,
+            "username": "adminuser"
+        },
+        {
+            "addressLine1": "address of disallowed",
+            "addressLine2": "place",
+            "city": "somewhere",
+            "company": "else",
+            "country": "UK",
+            "email": "disallowed@example.com",
+            "fullName": "Me me",
+            "gid": 0,
+            "localPasswd": "pa$$word",
+            "newUser": false,
+            "phoneNumber": "",
+            "postalCode": "",
+            "publicSshKey": "",
+            "registrationSent": "",
+            "role": 1,
+            "roleName": "disallowed",
+            "stateOrProvince": "",
+            "tenant": "root",
+            "tenant": 3,
+            "uid": 0,
+            "username": "disalloweduser"
+        },
+        {
+            "addressLine1": "address of read-only",
+            "addressLine2": "",
+            "city": "",
+            "company": "",
+            "country": "",
+            "email": "readonly@example.com",
+            "fullName": "",
+            "gid": 0,
+            "localPasswd": "pa$$word",
+            "newUser": false,
+            "phoneNumber": "",
+            "postalCode": "",
+            "publicSshKey": "",
+            "registrationSent": "",
+            "role": 2,
+            "roleName": "read-only user",
+            "stateOrProvince": "",
+            "tenant": "root",
+            "tenant": 3,
+            "uid": 0,
+            "username": "readuser"
+        },
+        {
+            "addressLine1": "address of operations",
+            "addressLine2": "",
+            "city": "",
+            "company": "",
+            "country": "",
+            "email": "operations@example.com",
+            "fullName": "",
+            "gid": 0,
+            "localPasswd": "pa$$word",
+            "newUser": false,
+            "phoneNumber": "",
+            "postalCode": "",
+            "publicSshKey": "",
+            "registrationSent": "",
+            "role": 3,
+            "roleName": "operations",
+            "stateOrProvince": "",
+            "tenant": "root",
+            "tenant": 4,
+            "uid": 0,
+            "username": "operationsuser"
+        },
+        {
+            "addressLine1": "",
+            "addressLine2": "",
+            "city": "",
+            "company": "",
+            "country": "",
+            "email": "portal@example.com",
+            "fullName": "",
+            "gid": 0,
+            "localPasswd": "pa$$word",
+            "newUser": false,
+            "phoneNumber": "",
+            "postalCode": "",
+            "publicSshKey": "",
+            "registrationSent": "",
+            "role": 5,
+            "roleName": "portal",
+            "stateOrProvince": "",
+            "tenant": "root",
+            "tenant": 2,
+            "uid": 0,
+            "username": "portaluser"
+        },
+        {
+            "addressLine1": "",
+            "addressLine2": "",
+            "city": "",
+            "company": "",
+            "country": "",
+            "email": "federation@example.com",
+            "fullName": "",
+            "gid": 0,
+            "localPasswd": "pa$$word",
+            "newUser": false,
+            "phoneNumber": "",
+            "postalCode": "",
+            "publicSshKey": "",
+            "registrationSent": "",
+            "role": 7,
+            "roleName": "federation",
+            "stateOrProvince": "",
+            "tenant": "root",
+            "tenant": 4,
+            "uid": 0,
+            "username": "federationuser"
+        }
+    ]
+}


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services