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

shamrick pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git


The following commit(s) were added to refs/heads/master by this push:
     new c1f82c4000 Api v5 should return rfc3339 timestamps for static dns 
entries (#7740)
c1f82c4000 is described below

commit c1f82c4000e28a101756e80a260bac85ca7a93c8
Author: Srijeet Chatterjee <[email protected]>
AuthorDate: Thu Aug 24 12:16:32 2023 -0600

    Api v5 should return rfc3339 timestamps for static dns entries (#7740)
    
    * wip
    
    * tests passing
    
    * Adding changelog and docs
    
    * cleanup
    
    * remove unneeded commit
---
 CHANGELOG.md                                       |   2 +-
 docs/source/api/v5/staticdnsentries.rst            |  12 +-
 lib/go-tc/staticdnsentry.go                        |  70 ++++
 traffic_ops/testing/api/v5/cdn_locks_test.go       |   8 +-
 .../testing/api/v5/staticdnsentries_test.go        | 117 +++----
 traffic_ops/testing/api/v5/traffic_control_test.go |   2 +-
 traffic_ops/traffic_ops_golang/routing/routes.go   |   8 +-
 .../staticdnsentry/staticdnsentry.go               | 382 +++++++++++++++++++++
 traffic_ops/v5-client/staticdnsentry.go            |  42 +--
 9 files changed, 550 insertions(+), 93 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1a46e6c808..783e8a05e0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -157,7 +157,7 @@ The format is based on [Keep a 
Changelog](http://keepachangelog.com/en/1.0.0/).
 - [#7698](https://github.com/apache/trafficcontrol/pull/7698) *Traffic Ops* 
Fixes `region` v5 apis to respond with `RFC3339` date/time Format.
 - [#7686](https://github.com/apache/trafficcontrol/pull/7686) *Traffic Ops* 
Fixes secured parameters being visible when role has proper permissions.
 - [#7697](https://github.com/apache/trafficcontrol/pull/7697) *Traffic Ops* 
Fixes `iloPassword` and `xmppPassword` checking for priv-level instead of using 
permissions.
-
+- [#7740](https://github.com/apache/trafficcontrol/pull/7740) *Traffic Ops* 
Fixes `staticDNSEntries` v5 apis to respond with `RFC3339` date/time Format.
 ### Removed
 - [#7271](https://github.com/apache/trafficcontrol/pull/7271) Remove 
components in `infrastructre/docker/`, not in use as cdn-in-a-box performs the 
same functionality.
 - [#7271](https://github.com/apache/trafficcontrol/pull/7271) 
Remove`misc/jira_github_issue_import.py`, the project does not use JIRA.
diff --git a/docs/source/api/v5/staticdnsentries.rst 
b/docs/source/api/v5/staticdnsentries.rst
index fb92ee4687..346e183017 100644
--- a/docs/source/api/v5/staticdnsentries.rst
+++ b/docs/source/api/v5/staticdnsentries.rst
@@ -89,7 +89,7 @@ Response Structure
 :deliveryserviceId: The integral, unique identifier of a :term:`Delivery 
Service` under the domain of which this static DNS entry shall be active
 :host:              If ``typeId`` identifies a ``CNAME`` type record, this is 
an alias for the CNAME of the server, otherwise it is the Fully Qualified 
Domain Name (FQDN) which shall resolve to ``address``
 :id:                An integral, unique identifier for this static DNS entry
-:lastUpdated:       The date and time at which this static DNS entry was last 
updated
+:lastUpdated:       The date and time at which this static DNS entry was last 
updated, in :rfc:`3339` format
 :ttl:               The :abbr:`TTL (Time To Live)` of this static DNS entry in 
seconds
 :type:              The name of the type of this static DNS entry
 :typeId:            The integral, unique identifier of the :term:`Type` of 
this static DNS entry
@@ -118,7 +118,7 @@ Response Structure
                        "deliveryserviceId": 1,
                        "host": "test",
                        "id": 2,
-                       "lastUpdated": "2018-12-10 19:59:56+00",
+                       "lastUpdated": "2018-12-10T19:59:56-06:00",
                        "ttl": 300,
                        "type": "CNAME_RECORD",
                        "typeId": 41
@@ -180,7 +180,7 @@ Response Structure
 :deliveryserviceId: The integral, unique identifier of a :term:`Delivery 
Service` under the domain of which this static DNS entry shall be active
 :host:              If ``typeId`` identifies a ``CNAME`` type record, this is 
an alias for the CNAME of the server, otherwise it is the Fully Qualified 
Domain Name (FQDN) which shall resolve to ``address``
 :id:                An integral, unique identifier for this static DNS entry
-:lastUpdated:       The date and time at which this static DNS entry was last 
updated
+:lastUpdated:       The date and time at which this static DNS entry was last 
updated, in :rfc:`3339` format
 :ttl:               The :abbr:`TTL (Time To Live)` of this static DNS entry in 
seconds
 :type:              The name of the :term:`Type` of this static DNS entry
 :typeId:            The integral, unique identifier of the :term:`Type` of 
this static DNS entry
@@ -214,7 +214,7 @@ Response Structure
                "deliveryserviceId": 1,
                "host": "test",
                "id": 2,
-               "lastUpdated": "2018-12-10 19:54:19+00",
+               "lastUpdated": "2018-12-10T19:54:19-06:00",
                "ttl": 300,
                "type": "CNAME_RECORD",
                "typeId": 41
@@ -283,7 +283,7 @@ Response Structure
 :deliveryserviceId: The integral, unique identifier of a :term:`Delivery 
Service` under the domain of which this static DNS entry shall be active
 :host:              If ``typeId`` identifies a ``CNAME`` type record, this is 
an alias for the CNAME of the server, otherwise it is the :abbr:`FQDN (Fully 
Qualified Domain Name)` which shall resolve to ``address``
 :id:                An integral, unique identifier for this static DNS entry
-:lastUpdated:       The date and time at which this static DNS entry was last 
updated
+:lastUpdated:       The date and time at which this static DNS entry was last 
updated, in :rfc:`3339` format
 :ttl:               The :abbr:`TTL (Time To Live)` of this static DNS entry in 
seconds
 :type:              The name of the :term:`Type` of this static DNS entry
 :typeId:            The integral, unique identifier of the :term:`Type` of 
this static DNS entry
@@ -317,7 +317,7 @@ Response Structure
                "deliveryserviceId": 1,
                "host": "test",
                "id": 2,
-               "lastUpdated": "2018-12-10 19:59:56+00",
+               "lastUpdated": "2018-12-10T19:59:56-06:00",
                "ttl": 300,
                "type": "CNAME_RECORD",
                "typeId": 41
diff --git a/lib/go-tc/staticdnsentry.go b/lib/go-tc/staticdnsentry.go
index c867a89d77..a7d9ca6c61 100644
--- a/lib/go-tc/staticdnsentry.go
+++ b/lib/go-tc/staticdnsentry.go
@@ -1,5 +1,7 @@
 package tc
 
+import "time"
+
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -25,6 +27,74 @@ type StaticDNSEntriesResponse struct {
        Alerts
 }
 
+// StaticDNSEntriesResponseV5 is a list of StaticDNSEntry as a response, for 
api version 5.0., for the latest
+// minor version of 5.x.
+type StaticDNSEntriesResponseV5 = StaticDNSEntriesResponseV50
+
+// StaticDNSEntriesResponseV50 is a list of StaticDNSEntry as a response, for 
api version 5.0.
+type StaticDNSEntriesResponseV50 struct {
+       Response []StaticDNSEntryV5 `json:"response"`
+       Alerts
+}
+
+// StaticDNSEntryV5 holds information about a static DNS entry, for the latest 
minor version of 5.x.
+type StaticDNSEntryV5 = StaticDNSEntryV50
+
+// StaticDNSEntryV50 holds information about a static DNS entry, for api 
version 5.0.
+type StaticDNSEntryV50 struct {
+
+       // The static IP Address or fqdn of the static dns entry
+       //
+       // required: true
+       Address *string `json:"address" db:"address"`
+
+       // The Cachegroup Name associated
+       //
+       CacheGroupName *string `json:"cachegroup" db:"cachegroup"`
+
+       // The Cachegroup ID associated
+       //
+       CacheGroupID *int `json:"cachegroupId" db:"cachegroup_id"`
+
+       // The DeliveryService associated
+       //
+       DeliveryService *string `json:"deliveryservice" db:"dsname"`
+
+       // The DeliveryService associated
+       //
+       // required: true
+       DeliveryServiceID *int `json:"deliveryserviceId" 
db:"deliveryservice_id"`
+
+       // The host of the static dns entry
+       //
+       // required: true
+       Host *string `json:"host" db:"host"`
+
+       // ID of the StaticDNSEntry
+       //
+       // required: true
+       ID *int `json:"id" db:"id"`
+
+       // LastUpdated
+       //
+       LastUpdated *time.Time `json:"lastUpdated" db:"last_updated"`
+
+       // The Time To Live for the static dns entry
+       //
+       // required: true
+       TTL *int64 `json:"ttl" db:"ttl"`
+
+       // The type of the static DNS entry
+       //
+       // enum: ["A_RECORD", "AAAA_RECORD", "CNAME_RECORD"]
+       Type *string `json:"type"`
+
+       // The type id of the static DNS entry
+       //
+       // required: true
+       TypeID *int `json:"typeId" db:"type_id"`
+}
+
 // StaticDNSEntry holds information about a static DNS entry.
 type StaticDNSEntry struct {
 
diff --git a/traffic_ops/testing/api/v5/cdn_locks_test.go 
b/traffic_ops/testing/api/v5/cdn_locks_test.go
index 04e36a2293..c3a2708448 100644
--- a/traffic_ops/testing/api/v5/cdn_locks_test.go
+++ b/traffic_ops/testing/api/v5/cdn_locks_test.go
@@ -463,6 +463,7 @@ func TestCDNLocks(t *testing.T) {
                                                "deliveryservice": 
"basic-ds-in-cdn2",
                                                "host":            "host2",
                                                "type":            "A_RECORD",
+                                               "ttl":             int64(0),
                                        },
                                        Expectations: 
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK)),
                                },
@@ -475,6 +476,7 @@ func TestCDNLocks(t *testing.T) {
                                                "deliveryservice": 
"basic-ds-in-cdn2",
                                                "host":            "host2",
                                                "type":            "A_RECORD",
+                                               "ttl":             int64(0),
                                        },
                                        Expectations: 
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusForbidden)),
                                },
@@ -680,18 +682,20 @@ func TestCDNLocks(t *testing.T) {
                                                        }
                                                },
                                                "STATIC DNS ENTRIES POST": 
func(t *testing.T) {
-                                                       staticDNSEntry := 
tc.StaticDNSEntry{}
+                                                       staticDNSEntry := 
tc.StaticDNSEntryV5{}
                                                        err = 
json.Unmarshal(dat, &staticDNSEntry)
                                                        assert.NoError(t, err, 
"Error occurred when unmarshalling request body: %v", err)
+                                                       staticDNSEntry.TTL = 
util.Ptr(int64(0))
                                                        alerts, reqInf, err := 
testCase.ClientSession.CreateStaticDNSEntry(staticDNSEntry, 
testCase.RequestOpts)
                                                        for _, check := range 
testCase.Expectations {
                                                                check(t, 
reqInf, nil, alerts, err)
                                                        }
                                                },
                                                "STATIC DNS ENTRIES PUT": 
func(t *testing.T) {
-                                                       staticDNSEntry := 
tc.StaticDNSEntry{}
+                                                       staticDNSEntry := 
tc.StaticDNSEntryV5{}
                                                        err = 
json.Unmarshal(dat, &staticDNSEntry)
                                                        assert.NoError(t, err, 
"Error occurred when unmarshalling request body: %v", err)
+                                                       staticDNSEntry.TTL = 
util.Ptr(int64(0))
                                                        alerts, reqInf, err := 
testCase.ClientSession.UpdateStaticDNSEntry(testCase.EndpointID(), 
staticDNSEntry, testCase.RequestOpts)
                                                        for _, check := range 
testCase.Expectations {
                                                                check(t, 
reqInf, nil, alerts, err)
diff --git a/traffic_ops/testing/api/v5/staticdnsentries_test.go 
b/traffic_ops/testing/api/v5/staticdnsentries_test.go
index 3a57e58baa..975b1b2f1d 100644
--- a/traffic_ops/testing/api/v5/staticdnsentries_test.go
+++ b/traffic_ops/testing/api/v5/staticdnsentries_test.go
@@ -24,6 +24,7 @@ import (
 
        "github.com/apache/trafficcontrol/lib/go-rfc"
        "github.com/apache/trafficcontrol/lib/go-tc"
+       "github.com/apache/trafficcontrol/lib/go-util"
        "github.com/apache/trafficcontrol/lib/go-util/assert"
        "github.com/apache/trafficcontrol/traffic_ops/testing/api/utils"
        "github.com/apache/trafficcontrol/traffic_ops/toclientlib"
@@ -37,7 +38,7 @@ func TestStaticDNSEntries(t *testing.T) {
                currentTimeRFC := currentTime.Format(time.RFC1123)
                tomorrow := currentTime.AddDate(0, 0, 1).Format(time.RFC1123)
 
-               methodTests := utils.TestCase[client.Session, 
client.RequestOptions, tc.StaticDNSEntry]{
+               methodTests := utils.TestCase[client.Session, 
client.RequestOptions, tc.StaticDNSEntryV5]{
                        "GET": {
                                "NOT MODIFIED when NO CHANGES made": {
                                        ClientSession: TOSession,
@@ -60,13 +61,13 @@ func TestStaticDNSEntries(t *testing.T) {
                                "OK when VALID request": {
                                        EndpointID:    GetStaticDNSEntryID(t, 
"host2"),
                                        ClientSession: TOSession,
-                                       RequestBody: tc.StaticDNSEntry{
-                                               Address:         "192.168.0.2",
-                                               CacheGroupName:  "cachegroup2",
-                                               DeliveryService: "ds2",
-                                               Host:            "host2",
-                                               Type:            "A_RECORD",
-                                               TTL:             10,
+                                       RequestBody: tc.StaticDNSEntryV5{
+                                               Address:         
util.Ptr("192.168.0.2"),
+                                               CacheGroupName:  
util.Ptr("cachegroup2"),
+                                               DeliveryService: 
util.Ptr("ds2"),
+                                               Host:            
util.Ptr("host2"),
+                                               Type:            
util.Ptr("A_RECORD"),
+                                               TTL:             
util.Ptr(int64(10)),
                                        },
                                        Expectations: 
utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK),
                                                
validateStaticDNSEntriesUpdateCreateFields("host2", 
map[string]interface{}{"Address": "192.168.0.2"})),
@@ -74,52 +75,52 @@ func TestStaticDNSEntries(t *testing.T) {
                                "BAD REQUEST when INVALID IPV4 ADDRESS for 
A_RECORD": {
                                        EndpointID:    GetStaticDNSEntryID(t, 
"host2"),
                                        ClientSession: TOSession,
-                                       RequestBody: tc.StaticDNSEntry{
-                                               Address:         
"test.testdomain.net.",
-                                               CacheGroupName:  "cachegroup2",
-                                               DeliveryService: "ds2",
-                                               Host:            "host2",
-                                               Type:            "A_RECORD",
-                                               TTL:             10,
+                                       RequestBody: tc.StaticDNSEntryV5{
+                                               Address:         
util.Ptr("test.testdomain.net."),
+                                               CacheGroupName:  
util.Ptr("cachegroup2"),
+                                               DeliveryService: 
util.Ptr("ds2"),
+                                               Host:            
util.Ptr("host2"),
+                                               Type:            
util.Ptr("A_RECORD"),
+                                               TTL:             
util.Ptr(int64(10)),
                                        },
                                        Expectations: 
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
                                },
                                "BAD REQUEST when INVALID DNS for 
CNAME_RECORD": {
                                        EndpointID:    GetStaticDNSEntryID(t, 
"host1"),
                                        ClientSession: TOSession,
-                                       RequestBody: tc.StaticDNSEntry{
-                                               Address:         
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
-                                               CacheGroupName:  "cachegroup1",
-                                               DeliveryService: "ds1",
-                                               Host:            "host1",
-                                               Type:            "CNAME_RECORD",
-                                               TTL:             0,
+                                       RequestBody: tc.StaticDNSEntryV5{
+                                               Address:         
util.Ptr("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
+                                               CacheGroupName:  
util.Ptr("cachegroup1"),
+                                               DeliveryService: 
util.Ptr("ds1"),
+                                               Host:            
util.Ptr("host1"),
+                                               Type:            
util.Ptr("CNAME_RECORD"),
+                                               TTL:             
util.Ptr(int64(0)),
                                        },
                                        Expectations: 
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
                                },
                                "BAD REQUEST when MISSING TRAILING PERIOD for 
CNAME_RECORD": {
                                        EndpointID:    GetStaticDNSEntryID(t, 
"host1"),
                                        ClientSession: TOSession,
-                                       RequestBody: tc.StaticDNSEntry{
-                                               Address:         "cdn.test.com",
-                                               CacheGroupName:  "cachegroup1",
-                                               DeliveryService: "ds1",
-                                               Host:            "host1",
-                                               Type:            "CNAME_RECORD",
-                                               TTL:             0,
+                                       RequestBody: tc.StaticDNSEntryV5{
+                                               Address:         
util.Ptr("cdn.test.com"),
+                                               CacheGroupName:  
util.Ptr("cachegroup1"),
+                                               DeliveryService: 
util.Ptr("ds1"),
+                                               Host:            
util.Ptr("host1"),
+                                               Type:            
util.Ptr("CNAME_RECORD"),
+                                               TTL:             
util.Ptr(int64(0)),
                                        },
                                        Expectations: 
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
                                },
                                "BAD REQUEST when INVALID IPV6 ADDRESS for 
AAAA_RECORD": {
                                        EndpointID:    GetStaticDNSEntryID(t, 
"host3"),
                                        ClientSession: TOSession,
-                                       RequestBody: tc.StaticDNSEntry{
-                                               Address:         "192.168.0.1",
-                                               CacheGroupName:  "cachegroup2",
-                                               DeliveryService: "ds1",
-                                               Host:            "host3",
-                                               TTL:             10,
-                                               Type:            "AAAA_RECORD",
+                                       RequestBody: tc.StaticDNSEntryV5{
+                                               Address:         
util.Ptr("192.168.0.1"),
+                                               CacheGroupName:  
util.Ptr("cachegroup2"),
+                                               DeliveryService: 
util.Ptr("ds1"),
+                                               Host:            
util.Ptr("host3"),
+                                               TTL:             
util.Ptr(int64(10)),
+                                               Type:            
util.Ptr("AAAA_RECORD"),
                                        },
                                        Expectations: 
utils.CkRequest(utils.HasError(), utils.HasStatus(http.StatusBadRequest)),
                                },
@@ -127,26 +128,26 @@ func TestStaticDNSEntries(t *testing.T) {
                                        EndpointID:    GetStaticDNSEntryID(t, 
"host3"),
                                        ClientSession: TOSession,
                                        RequestOpts:   
client.RequestOptions{Header: http.Header{rfc.IfUnmodifiedSince: 
{currentTimeRFC}}},
-                                       RequestBody: tc.StaticDNSEntry{
-                                               Address:         
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
-                                               CacheGroupName:  "cachegroup2",
-                                               DeliveryService: "ds1",
-                                               Host:            "host3",
-                                               TTL:             10,
-                                               Type:            "AAAA_RECORD",
+                                       RequestBody: tc.StaticDNSEntryV5{
+                                               Address:         
util.Ptr("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
+                                               CacheGroupName:  
util.Ptr("cachegroup2"),
+                                               DeliveryService: 
util.Ptr("ds1"),
+                                               Host:            
util.Ptr("host3"),
+                                               TTL:             
util.Ptr(int64(10)),
+                                               Type:            
util.Ptr("AAAA_RECORD"),
                                        },
                                        Expectations: 
utils.CkRequest(utils.HasError(), 
utils.HasStatus(http.StatusPreconditionFailed)),
                                },
                                "PRECONDITION FAILED when updating with IFMATCH 
ETAG Header": {
                                        EndpointID:    GetStaticDNSEntryID(t, 
"host3"),
                                        ClientSession: TOSession,
-                                       RequestBody: tc.StaticDNSEntry{
-                                               Address:         
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
-                                               CacheGroupName:  "cachegroup2",
-                                               DeliveryService: "ds1",
-                                               Host:            "host3",
-                                               TTL:             10,
-                                               Type:            "AAAA_RECORD",
+                                       RequestBody: tc.StaticDNSEntryV5{
+                                               Address:         
util.Ptr("2001:0db8:85a3:0000:0000:8a2e:0370:7334"),
+                                               CacheGroupName:  
util.Ptr("cachegroup2"),
+                                               DeliveryService: 
util.Ptr("ds1"),
+                                               Host:            
util.Ptr("host3"),
+                                               TTL:             
util.Ptr(int64(10)),
+                                               Type:            
util.Ptr("AAAA_RECORD"),
                                        },
                                        RequestOpts:  
client.RequestOptions{Header: http.Header{rfc.IfMatch: 
{rfc.ETag(currentTime)}}},
                                        Expectations: 
utils.CkRequest(utils.HasError(), 
utils.HasStatus(http.StatusPreconditionFailed)),
@@ -196,14 +197,14 @@ func TestStaticDNSEntries(t *testing.T) {
 func validateStaticDNSEntriesFields(expectedResp map[string]interface{}) 
utils.CkReqFunc {
        return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, _ 
tc.Alerts, _ error) {
                assert.RequireNotNil(t, resp, "Expected Static DNS Entries 
response to not be nil.")
-               staticDNSEntriesResp := resp.([]tc.StaticDNSEntry)
+               staticDNSEntriesResp := resp.([]tc.StaticDNSEntryV5)
                for field, expected := range expectedResp {
                        for _, staticDNSEntry := range staticDNSEntriesResp {
                                switch field {
                                case "Address":
-                                       assert.Equal(t, expected, 
staticDNSEntry.Address, "Expected Address to be %v, but got %s", expected, 
staticDNSEntry.Address)
+                                       assert.Equal(t, expected, 
*staticDNSEntry.Address, "Expected Address to be %v, but got %s", expected, 
*staticDNSEntry.Address)
                                case "Host":
-                                       assert.Equal(t, expected, 
staticDNSEntry.Host, "Expected Host to be %v, but got %s", expected, 
staticDNSEntry.Host)
+                                       assert.Equal(t, expected, 
*staticDNSEntry.Host, "Expected Host to be %v, but got %s", expected, 
*staticDNSEntry.Host)
                                default:
                                        t.Errorf("Expected field: %v, does not 
exist in response", field)
                                }
@@ -227,9 +228,9 @@ func validateStaticDNSEntriesSort() utils.CkReqFunc {
        return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, 
alerts tc.Alerts, _ error) {
                assert.RequireNotNil(t, resp, "Expected Static DNS Entries 
response to not be nil.")
                var staticDNSEntryHosts []string
-               staticDNSEntryResp := resp.([]tc.StaticDNSEntry)
+               staticDNSEntryResp := resp.([]tc.StaticDNSEntryV5)
                for _, staticDNSEntry := range staticDNSEntryResp {
-                       staticDNSEntryHosts = append(staticDNSEntryHosts, 
staticDNSEntry.Host)
+                       staticDNSEntryHosts = append(staticDNSEntryHosts, 
*staticDNSEntry.Host)
                }
                assert.Equal(t, true, 
sort.StringsAreSorted(staticDNSEntryHosts), "List is not sorted by their hosts: 
%v", staticDNSEntryHosts)
        }
@@ -242,7 +243,7 @@ func GetStaticDNSEntryID(t *testing.T, host string) func() 
int {
                staticDNSEntries, _, err := TOSession.GetStaticDNSEntries(opts)
                assert.RequireNoError(t, err, "Get Static DNS Entries Request 
failed with error:", err)
                assert.RequireEqual(t, 1, len(staticDNSEntries.Response), 
"Expected response object length 1, but got %d", len(staticDNSEntries.Response))
-               return staticDNSEntries.Response[0].ID
+               return *staticDNSEntries.Response[0].ID
        }
 }
 
@@ -258,11 +259,11 @@ func DeleteTestStaticDNSEntries(t *testing.T) {
        assert.NoError(t, err, "Cannot get Static DNS Entries: %v - alerts: 
%+v", err, staticDNSEntries.Alerts)
 
        for _, staticDNSEntry := range staticDNSEntries.Response {
-               alerts, _, err := 
TOSession.DeleteStaticDNSEntry(staticDNSEntry.ID, client.RequestOptions{})
+               alerts, _, err := 
TOSession.DeleteStaticDNSEntry(*staticDNSEntry.ID, client.RequestOptions{})
                assert.NoError(t, err, "Unexpected error deleting Static DNS 
Entry '%s' (#%d): %v - alerts: %+v", staticDNSEntry.Host, staticDNSEntry.ID, 
err, alerts.Alerts)
                // Retrieve the Static DNS Entry to see if it got deleted
                opts := client.NewRequestOptions()
-               opts.QueryParameters.Set("host", staticDNSEntry.Host)
+               opts.QueryParameters.Set("host", *staticDNSEntry.Host)
                getStaticDNSEntry, _, err := TOSession.GetStaticDNSEntries(opts)
                assert.NoError(t, err, "Error getting Static DNS Entry '%s' 
after deletion: %v - alerts: %+v", staticDNSEntry.Host, err, 
getStaticDNSEntry.Alerts)
                assert.Equal(t, 0, len(getStaticDNSEntry.Response), "Expected 
Static DNS Entry '%s' to be deleted, but it was found in Traffic Ops", 
staticDNSEntry.Host)
diff --git a/traffic_ops/testing/api/v5/traffic_control_test.go 
b/traffic_ops/testing/api/v5/traffic_control_test.go
index 6fa619b368..6112ea16ac 100644
--- a/traffic_ops/testing/api/v5/traffic_control_test.go
+++ b/traffic_ops/testing/api/v5/traffic_control_test.go
@@ -50,7 +50,7 @@ type TrafficControl struct {
        ServerCapabilities                                
[]tc.ServerCapabilityV5                 `json:"serverCapabilities"`
        ServiceCategories                                 
[]tc.ServiceCategoryV5                  `json:"serviceCategories"`
        Statuses                                          []tc.StatusV5         
                  `json:"statuses"`
-       StaticDNSEntries                                  []tc.StaticDNSEntry   
                  `json:"staticdnsentries"`
+       StaticDNSEntries                                  []tc.StaticDNSEntryV5 
                  `json:"staticdnsentries"`
        StatsSummaries                                    []tc.StatsSummaryV5   
                  `json:"statsSummaries"`
        Tenants                                           []tc.Tenant           
                  `json:"tenants"`
        ServerCheckExtensions                             
[]tc.ServerCheckExtensionNullable       `json:"servercheck_extensions"`
diff --git a/traffic_ops/traffic_ops_golang/routing/routes.go 
b/traffic_ops/traffic_ops_golang/routing/routes.go
index 8412bf74f7..7f2c8ecbbd 100644
--- a/traffic_ops/traffic_ops_golang/routing/routes.go
+++ b/traffic_ops/traffic_ops_golang/routing/routes.go
@@ -428,10 +428,10 @@ func Routes(d ServerData) ([]Route, http.Handler, error) {
                {Version: api.Version{Major: 5, Minor: 0}, Method: 
http.MethodDelete, Path: `service_categories/{name}$`, Handler: 
servicecategory.DeleteServiceCategory, RequiredPrivLevel: 
auth.PrivLevelOperations, RequiredPermissions: 
[]string{"SERVICE-CATEGORY:DELETE", "SERVICE-CATEGORY:READ"}, Authenticated: 
Authenticated, Middlewares: nil, ID: 43253822381},
 
                //StaticDNSEntries
-               {Version: api.Version{Major: 5, Minor: 0}, Method: 
http.MethodGet, Path: `staticdnsentries/?$`, Handler: 
api.ReadHandler(&staticdnsentry.TOStaticDNSEntry{}), RequiredPrivLevel: 
auth.PrivLevelReadOnly, RequiredPermissions: []string{"STATIC-DN:READ", 
"CACHE-GROUP:READ", "DELIVERY-SERVICE:READ"}, Authenticated: Authenticated, 
Middlewares: nil, ID: 42893947731},
-               {Version: api.Version{Major: 5, Minor: 0}, Method: 
http.MethodPut, Path: `staticdnsentries/?$`, Handler: 
api.UpdateHandler(&staticdnsentry.TOStaticDNSEntry{}), RequiredPrivLevel: 
auth.PrivLevelOperations, RequiredPermissions: []string{"STATIC-DN:UPDATE", 
"STATIC-DN:READ", "CACHE-GROUP:READ", "DELIVERY-SERVICE:READ"}, Authenticated: 
Authenticated, Middlewares: nil, ID: 44245711131},
-               {Version: api.Version{Major: 5, Minor: 0}, Method: 
http.MethodPost, Path: `staticdnsentries/?$`, Handler: 
api.CreateHandler(&staticdnsentry.TOStaticDNSEntry{}), RequiredPrivLevel: 
auth.PrivLevelOperations, RequiredPermissions: []string{"STATIC-DN:CREATE", 
"STATIC-DN:READ", "CACHE-GROUP:READ", "DELIVERY-SERVICE:READ"}, Authenticated: 
Authenticated, Middlewares: nil, ID: 462914823831},
-               {Version: api.Version{Major: 5, Minor: 0}, Method: 
http.MethodDelete, Path: `staticdnsentries/?$`, Handler: 
api.DeleteHandler(&staticdnsentry.TOStaticDNSEntry{}), RequiredPrivLevel: 
auth.PrivLevelOperations, RequiredPermissions: []string{"STATIC-DN:DELETE", 
"STATIC-DN:READ", "DELIVERY-SERVICE:READ", "CACHE-GROUP:READ"}, Authenticated: 
Authenticated, Middlewares: nil, ID: 484603113231},
+               {Version: api.Version{Major: 5, Minor: 0}, Method: 
http.MethodGet, Path: `staticdnsentries/?$`, Handler: staticdnsentry.Get, 
RequiredPrivLevel: auth.PrivLevelReadOnly, RequiredPermissions: 
[]string{"STATIC-DN:READ", "CACHE-GROUP:READ", "DELIVERY-SERVICE:READ"}, 
Authenticated: Authenticated, Middlewares: nil, ID: 42893947731},
+               {Version: api.Version{Major: 5, Minor: 0}, Method: 
http.MethodPut, Path: `staticdnsentries/?$`, Handler: staticdnsentry.Update, 
RequiredPrivLevel: auth.PrivLevelOperations, RequiredPermissions: 
[]string{"STATIC-DN:UPDATE", "STATIC-DN:READ", "CACHE-GROUP:READ", 
"DELIVERY-SERVICE:READ"}, Authenticated: Authenticated, Middlewares: nil, ID: 
44245711131},
+               {Version: api.Version{Major: 5, Minor: 0}, Method: 
http.MethodPost, Path: `staticdnsentries/?$`, Handler: staticdnsentry.Create, 
RequiredPrivLevel: auth.PrivLevelOperations, RequiredPermissions: 
[]string{"STATIC-DN:CREATE", "STATIC-DN:READ", "CACHE-GROUP:READ", 
"DELIVERY-SERVICE:READ"}, Authenticated: Authenticated, Middlewares: nil, ID: 
462914823831},
+               {Version: api.Version{Major: 5, Minor: 0}, Method: 
http.MethodDelete, Path: `staticdnsentries/?$`, Handler: staticdnsentry.Delete, 
RequiredPrivLevel: auth.PrivLevelOperations, RequiredPermissions: 
[]string{"STATIC-DN:DELETE", "STATIC-DN:READ", "DELIVERY-SERVICE:READ", 
"CACHE-GROUP:READ"}, Authenticated: Authenticated, Middlewares: nil, ID: 
484603113231},
 
                //ProfileParameters
                {Version: api.Version{Major: 5, Minor: 0}, Method: 
http.MethodGet, Path: `profiles/{id}/parameters/?$`, Handler: 
profileparameter.GetProfileID, RequiredPrivLevel: auth.PrivLevelReadOnly, 
RequiredPermissions: []string{"PROFILE:READ", "PARAMETER:READ"}, Authenticated: 
Authenticated, Middlewares: nil, ID: 47646497531},
diff --git a/traffic_ops/traffic_ops_golang/staticdnsentry/staticdnsentry.go 
b/traffic_ops/traffic_ops_golang/staticdnsentry/staticdnsentry.go
index 71459e3272..3db3282393 100644
--- a/traffic_ops/traffic_ops_golang/staticdnsentry/staticdnsentry.go
+++ b/traffic_ops/traffic_ops_golang/staticdnsentry/staticdnsentry.go
@@ -20,17 +20,22 @@ package staticdnsentry
  */
 
 import (
+       "database/sql"
+       "encoding/json"
        "errors"
        "fmt"
        "net/http"
        "strconv"
        "time"
 
+       "github.com/apache/trafficcontrol/lib/go-log"
        "github.com/apache/trafficcontrol/lib/go-tc"
        "github.com/apache/trafficcontrol/lib/go-tc/tovalidate"
        "github.com/apache/trafficcontrol/lib/go-util"
        "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
        
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
+       
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/util/ims"
+
        validation "github.com/go-ozzo/ozzo-validation"
        "github.com/go-ozzo/ozzo-validation/is"
 )
@@ -260,3 +265,380 @@ func deleteQuery() string {
 WHERE id=:id`
        return query
 }
+
+// Validate validates a statisDNSEntry entity and makes sure that all the 
supplied fields are valid.
+func Validate(staticDNSEntry tc.StaticDNSEntryV5, tx *sql.Tx) (error, error) {
+       typeStr, err := tc.ValidateTypeID(tx, staticDNSEntry.TypeID, 
"staticdnsentry")
+       if err != nil {
+               return err, nil
+       }
+
+       var addressErr, ttlErr error
+       switch typeStr {
+       case "A_RECORD":
+               addressErr = validation.Validate(staticDNSEntry.Address, 
validation.Required, is.IPv4)
+       case "AAAA_RECORD":
+               addressErr = validation.Validate(staticDNSEntry.Address, 
validation.Required, is.IPv6)
+       case "CNAME_RECORD":
+               addressErr = validation.Validate(staticDNSEntry.Address, 
validation.Required, is.DNSName)
+               address := *staticDNSEntry.Address
+               if addressErr == nil {
+                       lastChar := address[len(address)-1:]
+                       if lastChar != "." {
+                               addressErr = fmt.Errorf("for type: CNAME_RECORD 
must have a trailing period")
+                       }
+               }
+       default:
+               addressErr = validation.Validate(staticDNSEntry.Address, 
validation.Required)
+       }
+
+       if staticDNSEntry.TTL != nil {
+               if *staticDNSEntry.TTL == 0 {
+                       ttlErr = validation.Validate(staticDNSEntry.TTL, 
is.Digit)
+               }
+       } else {
+               ttlErr = validation.Validate(staticDNSEntry.TTL, 
validation.Required)
+       }
+
+       errs := validation.Errors{
+               "host":              validation.Validate(staticDNSEntry.Host, 
validation.Required, is.DNSName),
+               "address":           addressErr,
+               "deliveryserviceId": 
validation.Validate(staticDNSEntry.DeliveryServiceID, validation.Required),
+               "ttl":               ttlErr,
+               "typeId":            validation.Validate(staticDNSEntry.TypeID, 
validation.Required),
+       }
+       return util.JoinErrs(tovalidate.ToErrors(errs)), nil
+}
+
+// Update will modify an existing StaticDNSEntry entity in the database, for 
api v5.0.
+func Update(w http.ResponseWriter, r *http.Request) {
+       inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+       if userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+               return
+       }
+       defer inf.Close()
+
+       tx := inf.Tx.Tx
+
+       defer r.Body.Close()
+       var staticDNSEntry tc.StaticDNSEntryV5
+
+       if err := json.NewDecoder(r.Body).Decode(&staticDNSEntry); err != nil {
+               api.HandleErr(w, r, nil, http.StatusInternalServerError, nil, 
err)
+               return
+       }
+
+       userErr, sysErr = Validate(staticDNSEntry, tx)
+       if userErr != nil || sysErr != nil {
+               code := http.StatusBadRequest
+               if sysErr != nil {
+                       code = http.StatusInternalServerError
+               }
+               api.HandleErr(w, r, tx, code, userErr, sysErr)
+               return
+       }
+
+       var cdnName tc.CDNName
+       if id, ok := inf.Params["id"]; !ok {
+               api.HandleErr(w, r, tx, http.StatusBadRequest, 
errors.New("missing key: id"), nil)
+               return
+       } else {
+               idNum, err := strconv.Atoi(id)
+               if err != nil {
+                       api.HandleErr(w, r, tx, http.StatusBadRequest, 
errors.New("couldn't convert ID into a numeric value: "+err.Error()), nil)
+                       return
+               }
+               staticDNSEntry.ID = &idNum
+               if staticDNSEntry.DeliveryServiceID != nil {
+                       _, cdnName, _, err = 
dbhelpers.GetDSNameAndCDNFromID(tx, *staticDNSEntry.DeliveryServiceID)
+                       if err != nil {
+                               api.HandleErr(w, r, tx, 
http.StatusInternalServerError, nil, err)
+                               return
+                       }
+                       userErr, sysErr, errCode := 
dbhelpers.CheckIfCurrentUserCanModifyCDN(tx, string(cdnName), inf.User.UserName)
+                       if userErr != nil || sysErr != nil {
+                               api.HandleErr(w, r, inf.Tx.Tx, errCode, 
userErr, sysErr)
+                               return
+                       }
+               }
+
+               existingLastUpdated, found, err := api.GetLastUpdated(inf.Tx, 
idNum, "staticdnsentry")
+               if err == nil && found == false {
+                       api.HandleErr(w, r, tx, http.StatusNotFound, 
errors.New("no staticDNSEntry found with this id"), nil)
+                       return
+               }
+               if err != nil {
+                       api.HandleErr(w, r, tx, http.StatusNotFound, nil, err)
+                       return
+               }
+               if !api.IsUnmodified(r.Header, *existingLastUpdated) {
+                       api.HandleErr(w, r, tx, http.StatusPreconditionFailed, 
api.ResourceModifiedError, nil)
+                       return
+               }
+
+               rows, err := inf.Tx.NamedQuery(updateQuery(), staticDNSEntry)
+               if err != nil {
+                       userErr, sysErr, errCode = api.ParseDBError(err)
+                       api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+                       return
+               }
+               defer rows.Close()
+
+               if !rows.Next() {
+                       api.HandleErr(w, r, tx, http.StatusNotFound, 
errors.New("no staticDNSEntry found with this id"), nil)
+                       return
+               }
+               lastUpdated := time.Time{}
+               if err := rows.Scan(&lastUpdated); err != nil {
+                       api.HandleErr(w, r, tx, http.StatusInternalServerError, 
nil, errors.New("scanning lastUpdated from staticDNSEntry insert: 
"+err.Error()))
+                       return
+               }
+               staticDNSEntry.LastUpdated = &lastUpdated
+               if rows.Next() {
+                       api.HandleErr(w, r, tx, http.StatusInternalServerError, 
nil, errors.New("staticDNSEntry update affected too many rows: >1"))
+                       return
+               }
+
+               alerts := tc.CreateAlerts(tc.SuccessLevel, "staticDNSEntry was 
updated.")
+               api.WriteAlertsObj(w, r, http.StatusOK, alerts, staticDNSEntry)
+               changeLogMsg := fmt.Sprintf("STATICDNSENTRY: %s, ID: %d, 
ACTION: Updated staticDNSEntry", *staticDNSEntry.Host, *staticDNSEntry.ID)
+               api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, 
tx)
+               return
+       }
+}
+
+// Create will add a new StaticDNSEntry entity into the database, for api v5.0.
+func Create(w http.ResponseWriter, r *http.Request) {
+       inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+       if userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+               return
+       }
+       defer inf.Close()
+
+       tx := inf.Tx.Tx
+
+       defer r.Body.Close()
+       var staticDNSEntry tc.StaticDNSEntryV5
+
+       if err := json.NewDecoder(r.Body).Decode(&staticDNSEntry); err != nil {
+               api.HandleErr(w, r, nil, http.StatusInternalServerError, nil, 
err)
+               return
+       }
+
+       userErr, sysErr = Validate(staticDNSEntry, tx)
+       if userErr != nil || sysErr != nil {
+               code := http.StatusBadRequest
+               if sysErr != nil {
+                       code = http.StatusInternalServerError
+               }
+               api.HandleErr(w, r, tx, code, userErr, sysErr)
+               return
+       }
+
+       var cdnName tc.CDNName
+       var err error
+       if staticDNSEntry.DeliveryServiceID != nil {
+               _, cdnName, _, err = dbhelpers.GetDSNameAndCDNFromID(tx, 
*staticDNSEntry.DeliveryServiceID)
+               if err != nil {
+                       api.HandleErr(w, r, tx, http.StatusInternalServerError, 
nil, err)
+                       return
+               }
+               userErr, sysErr, errCode := 
dbhelpers.CheckIfCurrentUserCanModifyCDN(tx, string(cdnName), inf.User.UserName)
+               if userErr != nil || sysErr != nil {
+                       api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+                       return
+               }
+       }
+
+       resultRows, err := inf.Tx.NamedQuery(insertQuery(), staticDNSEntry)
+       if err != nil {
+               userErr, sysErr, errCode = api.ParseDBError(err)
+               api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+               return
+       }
+       defer resultRows.Close()
+
+       var id int
+       lastUpdated := time.Time{}
+       rowsAffected := 0
+       for resultRows.Next() {
+               rowsAffected++
+               if err := resultRows.Scan(&id, &lastUpdated); err != nil {
+                       api.HandleErr(w, r, tx, http.StatusInternalServerError, 
nil, errors.New("staticDNSEntry create scanning: "+err.Error()))
+                       return
+               }
+       }
+
+       if rowsAffected == 0 {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
errors.New("staticDNSEntry create: no staticDNSEntry was inserted, no id was 
returned"))
+               return
+       } else if rowsAffected > 1 {
+               api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, 
errors.New("too many ids returned from staticDNSEntry insert"))
+               return
+       }
+       staticDNSEntry.ID = &id
+       staticDNSEntry.LastUpdated = &lastUpdated
+
+       alerts := tc.CreateAlerts(tc.SuccessLevel, "staticDNSEntry was 
created.")
+       api.WriteAlertsObj(w, r, http.StatusOK, alerts, staticDNSEntry)
+       changeLogMsg := fmt.Sprintf("STATICDNSENTRY: %s, ID: %d, ACTION: 
Created staticDNSEntry", *staticDNSEntry.Host, *staticDNSEntry.ID)
+       api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx)
+       return
+}
+
+// Delete removes a staticDNSEntry from the database, for api v5.0.
+func Delete(w http.ResponseWriter, r *http.Request) {
+       inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+       if userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+               return
+       }
+       defer inf.Close()
+
+       tx := inf.Tx.Tx
+       if id, ok := inf.Params["id"]; !ok {
+               api.HandleErr(w, r, tx, http.StatusBadRequest, 
errors.New("missing key: id"), nil)
+               return
+       } else {
+               idNum, err := strconv.Atoi(id)
+               if err != nil {
+                       api.HandleErr(w, r, tx, http.StatusBadRequest, 
errors.New("couldn't convert ID into a numeric value: "+err.Error()), nil)
+                       return
+               }
+               staticDNSEntry := tc.StaticDNSEntryV5{
+                       ID: &idNum,
+               }
+               var cdnName tc.CDNName
+               var dsID int
+               if staticDNSEntry.DeliveryServiceID != nil {
+                       dsID = *staticDNSEntry.DeliveryServiceID
+               } else if staticDNSEntry.ID != nil {
+                       dsID, err = dbhelpers.GetDSIDFromStaticDNSEntry(tx, 
*staticDNSEntry.ID)
+                       if err != nil {
+                               api.HandleErr(w, r, tx, 
http.StatusInternalServerError, nil, errors.New("couldn't get DS ID from static 
dns entry ID: "+err.Error()))
+                               return
+                       }
+               }
+               _, cdnName, _, err = dbhelpers.GetDSNameAndCDNFromID(tx, dsID)
+               if err != nil {
+                       api.HandleErr(w, r, tx, http.StatusInternalServerError, 
nil, err)
+                       return
+               }
+               userErr, sysErr, errCode := 
dbhelpers.CheckIfCurrentUserCanModifyCDN(tx, string(cdnName), inf.User.UserName)
+               if userErr != nil || sysErr != nil {
+                       api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+                       return
+               }
+               result, err := inf.Tx.NamedExec(deleteQuery(), staticDNSEntry)
+               if err != nil {
+                       userErr, sysErr, errCode = api.ParseDBError(err)
+                       api.HandleErr(w, r, tx, errCode, userErr, sysErr)
+                       return
+               }
+
+               if rowsAffected, err := result.RowsAffected(); err != nil {
+                       api.HandleErr(w, r, tx, http.StatusInternalServerError, 
nil, errors.New("deleting staticDNSEntry: getting rows affected: "+err.Error()))
+                       return
+               } else if rowsAffected < 1 {
+                       api.HandleErr(w, r, tx, http.StatusBadRequest, 
errors.New("no staticDNSEntry with that key found"), nil)
+                       return
+               } else if rowsAffected > 1 {
+                       api.HandleErr(w, r, tx, http.StatusInternalServerError, 
nil, fmt.Errorf("staticDNSEntry delete affected too many rows: %d", 
rowsAffected))
+                       return
+               }
+               log.Debugf("changelog for delete on staticDNSEntry")
+
+               alerts := tc.CreateAlerts(tc.SuccessLevel, "staticDNSEntry was 
deleted.")
+               api.WriteAlerts(w, r, http.StatusOK, alerts)
+               changeLogMsg := fmt.Sprintf("STATICDNSENTRY: %d, ID: %d, 
ACTION: Deleted staticDNSEntry", *staticDNSEntry.ID, *staticDNSEntry.ID)
+               api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, 
tx)
+               return
+       }
+}
+
+// Get : function to read the staticDNSEntries, for api version 5.0.
+func Get(w http.ResponseWriter, r *http.Request) {
+       inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil)
+       if userErr != nil || sysErr != nil {
+               api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr)
+               return
+       }
+       defer inf.Close()
+
+       api.DefaultSort(inf, "host")
+       useIMS := false
+       config, e := api.GetConfig(r.Context())
+       if e == nil && config != nil {
+               useIMS = config.UseIMS
+       } else {
+               log.Warnf("Couldn't get config %v", e)
+       }
+
+       var maxTime time.Time
+       var runSecond bool
+
+       scList := make([]tc.StaticDNSEntryV5, 0)
+
+       tx := inf.Tx
+
+       where, orderBy, pagination, queryValues, errs := 
dbhelpers.BuildWhereAndOrderByAndPagination(inf.Params, 
map[string]dbhelpers.WhereColumnInfo{
+               "address":           dbhelpers.WhereColumnInfo{Column: 
"sde.address"},
+               "cachegroup":        dbhelpers.WhereColumnInfo{Column: 
"cg.name"},
+               "cachegroupId":      dbhelpers.WhereColumnInfo{Column: "cg.id"},
+               "deliveryservice":   dbhelpers.WhereColumnInfo{Column: 
"ds.xml_id"},
+               "deliveryserviceId": dbhelpers.WhereColumnInfo{Column: 
"sde.deliveryservice"},
+               "host":              dbhelpers.WhereColumnInfo{Column: 
"sde.host"},
+               "id":                dbhelpers.WhereColumnInfo{Column: 
"sde.id"},
+               "ttl":               dbhelpers.WhereColumnInfo{Column: 
"sde.ttl"},
+               "type":              dbhelpers.WhereColumnInfo{Column: 
"tp.name"},
+               "typeId":            dbhelpers.WhereColumnInfo{Column: "tp.id"},
+       })
+       if len(errs) > 0 {
+               api.HandleErr(w, r, tx.Tx, http.StatusBadRequest, nil, 
util.JoinErrs(errs))
+               return
+       }
+       if useIMS {
+               runSecond, maxTime = ims.TryIfModifiedSinceQuery(inf.Tx, 
r.Header, queryValues, selectMaxLastUpdatedQuery(where))
+               if !runSecond {
+                       log.Debugln("IMS HIT")
+                       api.AddLastModifiedHdr(w, maxTime)
+                       w.WriteHeader(http.StatusNotModified)
+                       return
+               }
+               log.Debugln("IMS MISS")
+       } else {
+               log.Debugln("Non IMS request")
+       }
+
+       // Case where we need to run the second query
+       query := selectQuery() + where + orderBy + pagination
+       rows, err := tx.NamedQuery(query, queryValues)
+       if err != nil {
+               api.HandleErr(w, r, tx.Tx, http.StatusInternalServerError, nil, 
errors.New("querying static DNS entries: "+err.Error()))
+               return
+       }
+       defer rows.Close()
+
+       for rows.Next() {
+               v := tc.StaticDNSEntryV5{}
+               if err = rows.StructScan(&v); err != nil {
+                       api.HandleErr(w, r, tx.Tx, 
http.StatusInternalServerError, nil, errors.New("scanning static DNS entries: 
"+err.Error()))
+                       return
+               }
+               scList = append(scList, v)
+       }
+
+       api.WriteResp(w, r, scList)
+}
+
+func selectMaxLastUpdatedQuery(where string) string {
+       return `SELECT max(t) from (
+               SELECT max(sde.last_updated) as t FROM staticdnsentry as sde
+JOIN type as tp on sde.type = tp.id
+LEFT JOIN cachegroup as cg ON sde.cachegroup = cg.id
+JOIN deliveryservice as ds on sde.deliveryservice = ds.id ` + where +
+               ` UNION ALL
+       select max(last_updated) as t from last_deleted l where 
l.table_name='staticdnsentry') as res`
+}
diff --git a/traffic_ops/v5-client/staticdnsentry.go 
b/traffic_ops/v5-client/staticdnsentry.go
index dee4fe520d..63397884a4 100644
--- a/traffic_ops/v5-client/staticdnsentry.go
+++ b/traffic_ops/v5-client/staticdnsentry.go
@@ -28,63 +28,63 @@ import (
 // endpoint.
 const apiStaticDNSEntries = "/staticdnsentries"
 
-func staticDNSEntryIDs(to *Session, sdns *tc.StaticDNSEntry) error {
+func staticDNSEntryIDsV5(to *Session, sdns *tc.StaticDNSEntryV5) error {
        if sdns == nil {
                return errors.New("cannot resolve names to IDs for nil 
StaticDNSEntry")
        }
-       if sdns.CacheGroupID == 0 && sdns.CacheGroupName != "" {
+       if (sdns.CacheGroupID == nil || *sdns.CacheGroupID == 0) && 
(sdns.CacheGroupName != nil && *sdns.CacheGroupName != "") {
                opts := NewRequestOptions()
-               opts.QueryParameters.Set("name", sdns.CacheGroupName)
+               opts.QueryParameters.Set("name", *sdns.CacheGroupName)
                p, _, err := to.GetCacheGroups(opts)
                if err != nil {
                        return err
                }
                if len(p.Response) == 0 {
-                       return errors.New("no CacheGroup named " + 
sdns.CacheGroupName)
+                       return errors.New("no CacheGroup named " + 
*sdns.CacheGroupName)
                }
                if p.Response[0].ID == nil {
-                       return errors.New("CacheGroup named " + 
sdns.CacheGroupName + " has a nil ID")
+                       return errors.New("CacheGroup named " + 
*sdns.CacheGroupName + " has a nil ID")
                }
-               sdns.CacheGroupID = *p.Response[0].ID
+               sdns.CacheGroupID = p.Response[0].ID
        }
 
-       if sdns.DeliveryServiceID == 0 && sdns.DeliveryService != "" {
+       if (sdns.DeliveryServiceID == nil || *sdns.DeliveryServiceID == 0) && 
(sdns.DeliveryService != nil && *sdns.DeliveryService != "") {
                opts := NewRequestOptions()
-               opts.QueryParameters.Set("xmlId", sdns.DeliveryService)
+               opts.QueryParameters.Set("xmlId", *sdns.DeliveryService)
                dses, _, err := to.GetDeliveryServices(opts)
                if err != nil {
                        return err
                }
                if len(dses.Response) == 0 {
-                       return errors.New("no deliveryservice with name " + 
sdns.DeliveryService)
+                       return errors.New("no deliveryservice with name " + 
*sdns.DeliveryService)
                }
                if dses.Response[0].ID == nil {
-                       return errors.New("Deliveryservice with name " + 
sdns.DeliveryService + " has a nil ID")
+                       return errors.New("Deliveryservice with name " + 
*sdns.DeliveryService + " has a nil ID")
                }
-               sdns.DeliveryServiceID = *dses.Response[0].ID
+               sdns.DeliveryServiceID = dses.Response[0].ID
        }
 
-       if sdns.TypeID == 0 && sdns.Type != "" {
+       if (sdns.TypeID == nil || *sdns.TypeID == 0) && (sdns.Type != nil && 
*sdns.Type != "") {
                opts := NewRequestOptions()
-               opts.QueryParameters.Set("name", sdns.Type)
+               opts.QueryParameters.Set("name", *sdns.Type)
                types, _, err := to.GetTypes(opts)
                if err != nil {
                        return err
                }
                if len(types.Response) == 0 {
-                       return errors.New("no type with name " + sdns.Type)
+                       return errors.New("no type with name " + *sdns.Type)
                }
-               sdns.TypeID = types.Response[0].ID
+               sdns.TypeID = &types.Response[0].ID
        }
 
        return nil
 }
 
 // CreateStaticDNSEntry creates the given Static DNS Entry.
-func (to *Session) CreateStaticDNSEntry(sdns tc.StaticDNSEntry, opts 
RequestOptions) (tc.Alerts, toclientlib.ReqInf, error) {
+func (to *Session) CreateStaticDNSEntry(sdns tc.StaticDNSEntryV5, opts 
RequestOptions) (tc.Alerts, toclientlib.ReqInf, error) {
        // fill in missing IDs from names
        var alerts tc.Alerts
-       err := staticDNSEntryIDs(to, &sdns)
+       err := staticDNSEntryIDsV5(to, &sdns)
        if err != nil {
                return alerts, toclientlib.ReqInf{CacheHitStatus: 
toclientlib.CacheHitStatusMiss}, err
        }
@@ -94,10 +94,10 @@ func (to *Session) CreateStaticDNSEntry(sdns 
tc.StaticDNSEntry, opts RequestOpti
 
 // UpdateStaticDNSEntry replaces the Static DNS Entry identified by 'id' with
 // the one provided.
-func (to *Session) UpdateStaticDNSEntry(id int, sdns tc.StaticDNSEntry, opts 
RequestOptions) (tc.Alerts, toclientlib.ReqInf, error) {
+func (to *Session) UpdateStaticDNSEntry(id int, sdns tc.StaticDNSEntryV5, opts 
RequestOptions) (tc.Alerts, toclientlib.ReqInf, error) {
        // fill in missing IDs from names
        var alerts tc.Alerts
-       err := staticDNSEntryIDs(to, &sdns)
+       err := staticDNSEntryIDsV5(to, &sdns)
        if err != nil {
                return alerts, toclientlib.ReqInf{CacheHitStatus: 
toclientlib.CacheHitStatusMiss}, err
        }
@@ -110,8 +110,8 @@ func (to *Session) UpdateStaticDNSEntry(id int, sdns 
tc.StaticDNSEntry, opts Req
 }
 
 // GetStaticDNSEntries retrieves all Static DNS Entries stored in Traffic Ops.
-func (to *Session) GetStaticDNSEntries(opts RequestOptions) 
(tc.StaticDNSEntriesResponse, toclientlib.ReqInf, error) {
-       var data tc.StaticDNSEntriesResponse
+func (to *Session) GetStaticDNSEntries(opts RequestOptions) 
(tc.StaticDNSEntriesResponseV5, toclientlib.ReqInf, error) {
+       var data tc.StaticDNSEntriesResponseV5
        reqInf, err := to.get(apiStaticDNSEntries, opts, &data)
        return data, reqInf, err
 }


Reply via email to