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

ocket8888 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 78b6637  updated /deliveryservices/{{ID}}/servers and 
/deliveryservices/{{ID}}… (#4676)
78b6637 is described below

commit 78b663725f7b7374e714d3e89d245620b656b518
Author: mattjackson220 <[email protected]>
AuthorDate: Mon Jun 15 12:34:40 2020 -0600

    updated /deliveryservices/{{ID}}/servers and /deliveryservices/{{ID}}… 
(#4676)
    
    * updated /deliveryservices/{{ID}}/servers and 
/deliveryservices/{{ID}}/servers/eligible to use multiple interfaces
    
    * updates per comments
    
    * updates per comments
    
    * reverted mgmt ip info change and updated for parity with /servers work
    
    * update to fix docs
    
    * added unit testing
    
    * updates to integrate better with other PRs
    
    * updated to change IpAddresses to IPAddresses
    
    * minor update to fix miss in rebase
    
    Co-authored-by: mjacks258 <[email protected]>
---
 CHANGELOG.md                                       |   2 +
 docs/source/api/v3/deliveryservices_id_servers.rst |  49 +++++---
 .../v3/deliveryservices_id_servers_eligible.rst    |  49 +++++---
 lib/go-tc/deliveryservice_servers.go               |  26 ++--
 lib/go-tc/servers.go                               |   2 +-
 lib/go-util/ptr.go                                 |   4 +
 .../traffic_ops_golang/deliveryservice/eligible.go |  59 ++++++---
 .../eligible_test.go}                              | 132 ++++++++++----------
 .../deliveryservice/servers/servers.go             |  93 ++++++++++++--
 .../deliveryservice/servers/servers_test.go        | 135 ++++++++++++++++++++-
 .../traffic_ops_golang/server/detail_test.go       |   4 +-
 traffic_ops/v1-client/deliveryservice.go           |   6 +-
 traffic_ops/v2-client/deliveryservice.go           |   6 +-
 13 files changed, 425 insertions(+), 142 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0b1239f..811a165 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,8 @@ The format is based on [Keep a 
Changelog](http://keepachangelog.com/en/1.0.0/).
 - Updated /servers/details to use multiple interfaces in API v3
 - Added [Edge Traffic 
Routing](https://traffic-control-cdn.readthedocs.io/en/latest/admin/traffic_router.html#edge-traffic-routing)
 feature which allows Traffic Router to localize more DNS record types than 
just the routing name for DNS delivery services
 - Astats csv support - astats will now respond to `Accept: text/csv` and 
return a csv formatted stats list
+- Updated /deliveryservices/{{ID}}/servers to use multiple interfaces in API v3
+- Updated /deliveryservices/{{ID}}/servers/eligible to use multiple interfaces 
in API v3
 
 ### Fixed
 - Fixed the `GET /api/x/jobs` and `GET /api/x/jobs/:id` Traffic Ops API routes 
to allow falling back to Perl via the routing blacklist
diff --git a/docs/source/api/v3/deliveryservices_id_servers.rst 
b/docs/source/api/v3/deliveryservices_id_servers.rst
index 7310505..c6762eb 100644
--- a/docs/source/api/v3/deliveryservices_id_servers.rst
+++ b/docs/source/api/v3/deliveryservices_id_servers.rst
@@ -54,16 +54,22 @@ Response Structure
 :iloIpNetmask:   The IPv4 subnet mask of the lights-out-management port\ 
[#ilowikipedia]_
 :iloPassword:    The password of the of the lights-out-management user - 
displays as ``******`` unless the requesting user has the 'admin' role)\ 
[#ilowikipedia]_
 :iloUsername:    The user name for lights-out-management\ [#ilowikipedia]_
-:interfaceMtu:   The :abbr:`MTU (Maximum Transmission Unit)` to configure for 
``interfaceName``
+:interfaces:     An array of interface and IP address information
 
-       .. seealso:: `The Wikipedia article on Maximum Transmission Unit 
<https://en.wikipedia.org/wiki/Maximum_transmission_unit>`_
+       :max_bandwidth:  The maximum allowed bandwidth for this interface to be 
considered "healthy" by Traffic Monitor. This has no effect if `monitor` is not 
true. Values are in kb/s. The value `null` means "no limit".
+       :monitor:        A boolean indicating if Traffic Monitor should monitor 
this interface
+       :mtu:            The :abbr:`MTU (Maximum Transmission Unit)` to 
configure for ``interfaceName``
+
+               .. seealso:: `The Wikipedia article on Maximum Transmission 
Unit <https://en.wikipedia.org/wiki/Maximum_transmission_unit>`_
+
+       :name:           The network interface name used by the server.
+
+       :ipAddresses:    An array of the IP address information for the 
interface
+
+               :address:       The IPv4 or IPv6 address and subnet mask of the 
server - applicable for the interface ``name``
+               :gateway:       The IPv4 or IPv6 gateway address of the server 
- applicable for the interface ``name``
+               :service_address:  A boolean determining if content will be 
routed to the IP address
 
-:interfaceName:  The network interface name used by the server
-:ip6Address:     The IPv6 address and subnet mask of the server - applicable 
for the interface ``interfaceName``
-:ip6Gateway:     The IPv6 gateway address of the server - applicable for the 
interface ``interfaceName``
-:ipAddress:      The IPv4 address of the server- applicable for the interface 
``interfaceName``
-:ipGateway:      The IPv4 gateway of the server- applicable for the interface 
``interfaceName``
-:ipNetmask:      The IPv4 subnet mask of the server- applicable for the 
interface ``interfaceName``
 :lastUpdated:    The time and date at which this server was last updated, in 
an ISO-like format
 :mgmtIpAddress:  The IPv4 address of the server's management port
 :mgmtIpGateway:  The IPv4 gateway of the server's management port
@@ -121,13 +127,6 @@ Response Structure
                        "iloIpNetmask": "",
                        "iloPassword": "",
                        "iloUsername": "",
-                       "interfaceMtu": 1500,
-                       "interfaceName": "eth0",
-                       "ip6Address": "fc01:9400:1000:8::100",
-                       "ip6Gateway": "fc01:9400:1000:8::1",
-                       "ipAddress": "172.16.239.100",
-                       "ipGateway": "172.16.239.1",
-                       "ipNetmask": "255.255.255.0",
                        "lastUpdated": "2018-11-14 21:08:44+00",
                        "mgmtIpAddress": "",
                        "mgmtIpGateway": "",
@@ -146,7 +145,25 @@ Response Structure
                        "tcpPort": 80,
                        "type": "EDGE",
                        "typeId": 11,
-                       "updPending": false
+                       "updPending": false,
+                       "interfaces": [{
+                               "ipAddresses": [
+                                       {
+                                               "address": "172.16.239.100",
+                                               "gateway": "172.16.239.1",
+                                               "service_address": true
+                                       },
+                                       {
+                                               "address": 
"fc01:9400:1000:8::100",
+                                               "gateway": 
"fc01:9400:1000:8::1",
+                                               "service_address": true
+                                       }
+                               ],
+                               "max_bandwidth": 0,
+                               "monitor": true,
+                               "mtu": 1500,
+                               "name": "eth0"
+                       }]
                }
        ]}
 
diff --git a/docs/source/api/v3/deliveryservices_id_servers_eligible.rst 
b/docs/source/api/v3/deliveryservices_id_servers_eligible.rst
index f6bd15b..57f6495 100644
--- a/docs/source/api/v3/deliveryservices_id_servers_eligible.rst
+++ b/docs/source/api/v3/deliveryservices_id_servers_eligible.rst
@@ -59,16 +59,22 @@ Response Structure
 :iloIpNetmask:   The IPv4 subnet mask of the lights-out-management port\ 
[#ilowikipedia]_
 :iloPassword:    The password of the of the lights-out-management user - 
displays as ``******`` unless the requesting user has the 'admin' role)\ 
[#ilowikipedia]_
 :iloUsername:    The user name for lights-out-management\ [#ilowikipedia]_
-:interfaceMtu:   The :abbr:`MTU (Maximum Transmission Unit)` to configure for 
``interfaceName``
+:interfaces:     An array of interface and IP address information
 
-       .. seealso:: `The Wikipedia article on Maximum Transmission Unit 
<https://en.wikipedia.org/wiki/Maximum_transmission_unit>`_
+       :max_bandwidth:  The maximum allowed bandwidth for this interface to be 
considered "healthy" by Traffic Monitor. This has no effect if `monitor` is not 
true. Values are in kb/s. The value `null` means "no limit".
+       :monitor:        A boolean indicating if Traffic Monitor should monitor 
this interface
+       :mtu:            The :abbr:`MTU (Maximum Transmission Unit)` to 
configure for ``interfaceName``
+
+               .. seealso:: `The Wikipedia article on Maximum Transmission 
Unit <https://en.wikipedia.org/wiki/Maximum_transmission_unit>`_
+
+       :name:           The network interface name used by the server.
+
+       :ipAddresses:    An array of the IP address information for the 
interface
+
+               :address:       The IPv4 or IPv6 address and subnet mask of the 
server - applicable for the interface ``name``
+               :gateway:       The IPv4 or IPv6 gateway address of the server 
- applicable for the interface ``name``
+               :service_address:  A boolean determining if content will be 
routed to the IP address
 
-:interfaceName:  The network interface name used by the server
-:ip6Address:     The IPv6 address and subnet mask of the server - applicable 
for the interface ``interfaceName``
-:ip6Gateway:     The IPv6 gateway address of the server - applicable for the 
interface ``interfaceName``
-:ipAddress:      The IPv4 address of the server- applicable for the interface 
``interfaceName``
-:ipGateway:      The IPv4 gateway of the server- applicable for the interface 
``interfaceName``
-:ipNetmask:      The IPv4 subnet mask of the server- applicable for the 
interface ``interfaceName``
 :lastUpdated:    The time and date at which this server was last updated, in 
an ISO-like format
 :mgmtIpAddress:  The IPv4 address of the server's management port
 :mgmtIpGateway:  The IPv4 gateway of the server's management port
@@ -114,13 +120,6 @@ Response Structure
                        "iloIpNetmask": "",
                        "iloPassword": "",
                        "iloUsername": "",
-                       "interfaceMtu": 1500,
-                       "interfaceName": "eth0",
-                       "ip6Address": "fc01:9400:1000:8::100",
-                       "ip6Gateway": "fc01:9400:1000:8::1",
-                       "ipAddress": "172.16.239.100",
-                       "ipGateway": "172.16.239.1",
-                       "ipNetmask": "255.255.255.0",
                        "lastUpdated": "2018-10-30 16:01:12+00",
                        "mgmtIpAddress": "",
                        "mgmtIpGateway": "",
@@ -139,7 +138,25 @@ Response Structure
                        "tcpPort": 80,
                        "type": "EDGE",
                        "typeId": 11,
-                       "updPending": false
+                       "updPending": false,
+                       "interfaces": [{
+                               "ipAddresses": [
+                                       {
+                                               "address": "172.16.239.100",
+                                               "gateway": "172.16.239.1",
+                                               "service_address": true
+                                       },
+                                       {
+                                               "address": 
"fc01:9400:1000:8::100",
+                                               "gateway": 
"fc01:9400:1000:8::1",
+                                               "service_address": true
+                                       }
+                               ],
+                               "max_bandwidth": 0,
+                               "monitor": true,
+                               "mtu": 1500,
+                               "name": "eth0"
+                       }]
                }
        ]}
 
diff --git a/lib/go-tc/deliveryservice_servers.go 
b/lib/go-tc/deliveryservice_servers.go
index b082b56..bb1314a 100644
--- a/lib/go-tc/deliveryservice_servers.go
+++ b/lib/go-tc/deliveryservice_servers.go
@@ -63,11 +63,8 @@ const (
        Eligible
 )
 
-type DSServersAttrResponse struct {
-       Response []DSServer `json:"response"`
-}
-
-type DSServer struct {
+// DSServerBase contains the base information for a Delivery Service Server.
+type DSServerBase struct {
        Cachegroup                  *string              `json:"cachegroup" 
db:"cachegroup"`
        CachegroupID                *int                 `json:"cachegroupId" 
db:"cachegroup_id"`
        CDNID                       *int                 `json:"cdnId" 
db:"cdn_id"`
@@ -85,13 +82,6 @@ type DSServer struct {
        ILOIPNetmask                *string              `json:"iloIpNetmask" 
db:"ilo_ip_netmask"`
        ILOPassword                 *string              `json:"iloPassword" 
db:"ilo_password"`
        ILOUsername                 *string              `json:"iloUsername" 
db:"ilo_username"`
-       InterfaceMtu                *int                 `json:"interfaceMtu" 
db:"interface_mtu"`
-       InterfaceName               *string              `json:"interfaceName" 
db:"interface_name"`
-       IP6Address                  *string              `json:"ip6Address" 
db:"ip6_address"`
-       IP6Gateway                  *string              `json:"ip6Gateway" 
db:"ip6_gateway"`
-       IPAddress                   *string              `json:"ipAddress" 
db:"ip_address"`
-       IPGateway                   *string              `json:"ipGateway" 
db:"ip_gateway"`
-       IPNetmask                   *string              `json:"ipNetmask" 
db:"ip_netmask"`
        LastUpdated                 *TimeNoMod           `json:"lastUpdated" 
db:"last_updated"`
        MgmtIPAddress               *string              `json:"mgmtIpAddress" 
db:"mgmt_ip_address"`
        MgmtIPGateway               *string              `json:"mgmtIpGateway" 
db:"mgmt_ip_gateway"`
@@ -114,3 +104,15 @@ type DSServer struct {
        ServerCapabilities          []string             `json:"-" 
db:"server_capabilities"`
        DeliveryServiceCapabilities []string             `json:"-" 
db:"deliveryservice_capabilities"`
 }
+
+// DSServerV11 contains the legacy format for a Delivery Service Server.
+type DSServerV11 struct {
+       DSServerBase
+       LegacyInterfaceDetails
+}
+
+// DSServer contains information for a Delivery Service Server.
+type DSServer struct {
+       DSServerBase
+       ServerInterfaces *[]ServerInterfaceInfo `json:"interfaces" 
db:"interfaces"`
+}
diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go
index 0904a52..08c43d1 100644
--- a/lib/go-tc/servers.go
+++ b/lib/go-tc/servers.go
@@ -105,7 +105,7 @@ func (sii *ServerInterfaceInfo) Value() (driver.Value, 
error) {
 }
 
 // Scan implements the sql.Scanner interface
-// expects json.RawMessage and unmarshals to a deliveryservice struct
+// expects json.RawMessage and unmarshals to a ServerInterfaceInfo struct
 func (sii *ServerInterfaceInfo) Scan(src interface{}) error {
        b, ok := src.([]byte)
        if !ok {
diff --git a/lib/go-util/ptr.go b/lib/go-util/ptr.go
index eb79583..8cf013f 100644
--- a/lib/go-util/ptr.go
+++ b/lib/go-util/ptr.go
@@ -31,6 +31,10 @@ func UintPtr(u uint) *uint {
        return &u
 }
 
+func Uint64Ptr(u uint64) *uint64 {
+       return &u
+}
+
 func Int64Ptr(i int64) *int64 {
        return &i
 }
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/eligible.go 
b/traffic_ops/traffic_ops_golang/deliveryservice/eligible.go
index cbc4edf..f99a42c 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/eligible.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/eligible.go
@@ -23,7 +23,6 @@ import (
        "database/sql"
        "errors"
        "net/http"
-       "strconv"
        "strings"
 
        "github.com/apache/trafficcontrol/lib/go-tc"
@@ -63,6 +62,26 @@ func GetServersEligible(w http.ResponseWriter, r 
*http.Request) {
                api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, 
nil, errors.New("getting eligible servers: "+err.Error()))
                return
        }
+
+       if inf.Version.Major < 3 {
+               v11ServerList := []tc.DSServerV11{}
+               for _, srv := range servers {
+                       v11server := tc.DSServerV11{}
+                       v11server.DSServerBase = srv.DSServerBase
+
+                       interfaces := *srv.ServerInterfaces
+                       legacyInterface, err := 
tc.InterfaceInfoToLegacyInterfaces(interfaces)
+                       if err != nil {
+                               api.HandleErr(w, r, inf.Tx.Tx, 
http.StatusInternalServerError, nil, errors.New("converting to server detail 
v11: "+err.Error()))
+                               return
+                       }
+                       v11server.LegacyInterfaceDetails = legacyInterface
+
+                       v11ServerList = append(v11ServerList, v11server)
+               }
+               api.WriteResp(w, r, v11ServerList)
+               return
+       }
        api.WriteResp(w, r, servers)
 }
 
@@ -86,13 +105,26 @@ s.ilo_ip_gateway,
 s.ilo_ip_netmask,
 s.ilo_password,
 s.ilo_username,
-COALESCE(s.interface_mtu, ` + strconv.Itoa(JumboFrameBPS) + `) as 
interface_mtu,
-s.interface_name,
-s.ip6_address,
-s.ip6_gateway,
-s.ip_address,
-s.ip_gateway,
-s.ip_netmask,
+       ARRAY (
+SELECT ( json_build_object (
+'ipAddresses', ARRAY (
+SELECT ( json_build_object (
+'address', ip_address.address,
+'gateway', ip_address.gateway,
+'serviceAddress', ip_address.service_address
+))
+FROM ip_address
+WHERE ip_address.interface = interface.name
+AND ip_address.server = s.id
+),
+'max_bandwidth', interface.max_bandwidth,
+'monitor', interface.monitor,
+'mtu', COALESCE (interface.mtu, 9000),
+'name', interface.name
+))
+FROM interface
+WHERE interface.server = s.id
+) AS interfaces,
 s.last_updated,
 s.mgmt_ip_address,
 s.mgmt_ip_gateway,
@@ -132,6 +164,7 @@ AND (t.name LIKE 'EDGE%' OR t.name LIKE 'ORG%')
 
        servers := []tc.DSServer{}
        for rows.Next() {
+               serverInterfaceInfo := []tc.ServerInterfaceInfo{}
                s := tc.DSServer{}
                err := rows.Scan(
                        &s.Cachegroup,
@@ -148,13 +181,7 @@ AND (t.name LIKE 'EDGE%' OR t.name LIKE 'ORG%')
                        &s.ILOIPNetmask,
                        &s.ILOPassword,
                        &s.ILOUsername,
-                       &s.InterfaceMtu,
-                       &s.InterfaceName,
-                       &s.IP6Address,
-                       &s.IP6Gateway,
-                       &s.IPAddress,
-                       &s.IPGateway,
-                       &s.IPNetmask,
+                       pq.Array(&serverInterfaceInfo),
                        &s.LastUpdated,
                        &s.MgmtIPAddress,
                        &s.MgmtIPGateway,
@@ -180,6 +207,8 @@ AND (t.name LIKE 'EDGE%' OR t.name LIKE 'ORG%')
                if err != nil {
                        return nil, errors.New("scanning delivery service 
eligible servers: " + err.Error())
                }
+               s.ServerInterfaces = &serverInterfaceInfo
+
                eligible := true
 
                if !strings.HasPrefix(s.Type, "ORG") {
diff --git a/traffic_ops/traffic_ops_golang/server/detail_test.go 
b/traffic_ops/traffic_ops_golang/deliveryservice/eligible_test.go
similarity index 51%
copy from traffic_ops/traffic_ops_golang/server/detail_test.go
copy to traffic_ops/traffic_ops_golang/deliveryservice/eligible_test.go
index 3b937f8..f8d0c41 100644
--- a/traffic_ops/traffic_ops_golang/server/detail_test.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/eligible_test.go
@@ -1,10 +1,13 @@
-package server
+package deliveryservice
 
 /*
+
    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.
@@ -17,14 +20,12 @@ import (
 
        "github.com/apache/trafficcontrol/lib/go-tc"
        "github.com/apache/trafficcontrol/lib/go-util"
-       "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api"
-       "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/auth"
        "github.com/jmoiron/sqlx"
 
        "gopkg.in/DATA-DOG/go-sqlmock.v1"
 )
 
-func TestGetDetailServers(t *testing.T) {
+func TestGetEligibleServers(t *testing.T) {
        mockDB, mock, err := sqlmock.New()
        if err != nil {
                t.Fatalf("an error '%s' was not expected when opening a stub 
database connection", err)
@@ -34,10 +35,11 @@ func TestGetDetailServers(t *testing.T) {
        db := sqlx.NewDb(mockDB, "sqlmock")
        defer db.Close()
 
-       testServerDetails := getMockServerDetails()
+       testServers := getMockDSServers()
        cols := []string{"cachegroup",
+               "cachegroup_id",
+               "cdn_id",
                "cdn_name",
-               "deliveryservices",
                "domain_name",
                "guid",
                "host_name",
@@ -49,70 +51,76 @@ func TestGetDetailServers(t *testing.T) {
                "ilo_password",
                "ilo_username",
                "interfaces",
+               "last_updated",
                "mgmt_ip_address",
                "mgmt_ip_gateway",
                "mgmt_ip_netmask",
                "offline_reason",
                "phys_location",
+               "phys_location_id",
                "profile",
                "profile_desc",
+               "profile_id",
                "rack",
                "router_host_name",
                "router_port_name",
                "status",
+               "status_id",
                "tcp_port",
                "server_type",
-               "xmpp_id",
-               "xmpp_passwd",
-       }
+               "server_type_id",
+               "upd_pending",
+               "server_capabilities",
+               "deliveryservice_capabilities"}
+
        rows := sqlmock.NewRows(cols)
 
-       for _, sd := range testServerDetails {
+       for _, s := range testServers {
                rows = rows.AddRow(
-                       sd.CacheGroup,
-                       sd.CDNName,
-                       []byte(`{1}`),
-                       sd.DomainName,
-                       sd.GUID,
-                       sd.HostName,
-                       sd.HTTPSPort,
-                       sd.ID,
-                       sd.ILOIPAddress,
-                       sd.ILOIPGateway,
-                       sd.ILOIPNetmask,
-                       sd.ILOPassword,
-                       sd.ILOUsername,
-                       []byte(`{"{\"ipAddresses\" : [{\"address\" : 
\"127.0.0.0\", \"gateway\" : null, \"serviceAddress\" : true}], 
\"max_bandwidth\" : null, \"monitor\" : true, \"mtu\" : 1500, \"name\" : 
\"eth0\"}"}`),
-                       sd.MgmtIPAddress,
-                       sd.MgmtIPGateway,
-                       sd.MgmtIPNetmask,
-                       sd.OfflineReason,
-                       sd.PhysLocation,
-                       sd.Profile,
-                       sd.ProfileDesc,
-                       sd.Rack,
-                       sd.RouterHostName,
-                       sd.RouterPortName,
-                       sd.Status,
-                       sd.TCPPort,
-                       sd.Type,
-                       sd.XMPPID,
-                       sd.XMPPPasswd,
+                       s.Cachegroup,
+                       s.CachegroupID,
+                       s.CDNID,
+                       s.CDNName,
+                       s.DomainName,
+                       s.GUID,
+                       s.HostName,
+                       s.HTTPSPort,
+                       s.ID,
+                       s.ILOIPAddress,
+                       s.ILOIPGateway,
+                       s.ILOIPNetmask,
+                       s.ILOPassword,
+                       s.ILOUsername,
+                       []byte(`{"{\"ipAddresses\" : [{\"address\" : 
\"127.0.0.0\", \"gateway\" : null, \"service_address\" : true}], 
\"max_bandwidth\" : null, \"monitor\" : true, \"mtu\" : 1500, \"name\" : 
\"eth0\"}"}`),
+                       s.LastUpdated,
+                       s.MgmtIPAddress,
+                       s.MgmtIPGateway,
+                       s.MgmtIPNetmask,
+                       s.OfflineReason,
+                       s.PhysLocation,
+                       s.PhysLocationID,
+                       s.Profile,
+                       s.ProfileDesc,
+                       s.ProfileID,
+                       s.Rack,
+                       s.RouterHostName,
+                       s.RouterPortName,
+                       s.Status,
+                       s.StatusID,
+                       s.TCPPort,
+                       s.Type,
+                       s.TypeID,
+                       s.UpdPending,
+                       []byte(`{""}`),
+                       []byte(`{""}`),
                )
        }
 
-       hwCols := []string{"serverid", "description", "val"}
-       hwRows := sqlmock.NewRows(hwCols)
-       hwRows = hwRows.AddRow(1, "desc1", "val1")
-       hwRows = hwRows.AddRow(1, "desc2", "val2")
-       hwRows = hwRows.AddRow(1, "desc3", "val3")
-
        mock.ExpectBegin()
-       mock.ExpectQuery("SELECT cg.name").WillReturnRows(rows)
-       mock.ExpectQuery("SELECT serverid").WillReturnRows(hwRows)
+       mock.ExpectQuery("SELECT").WillReturnRows(rows)
        mock.ExpectCommit()
 
-       actualSrvs, err := getDetailServers(db.MustBegin().Tx, 
&auth.CurrentUser{PrivLevel: 30}, "test", 1, "id", 10, api.Version{3, 0})
+       actualSrvs, err := getEligibleServers(db.MustBegin().Tx, 1)
        if err != nil {
                t.Fatalf("an error '%s' occurred during read", err)
        }
@@ -127,24 +135,22 @@ func TestGetDetailServers(t *testing.T) {
        }
 
        if len(srvInts[0].IPAddresses) != 1 {
-               t.Fatalf("servers.read expected len(srvInts[0].IpAddresses) == 
1, actual = %v", len(srvInts[0].IPAddresses))
-       }
-
-       if len(actualSrvs[0].HardwareInfo) != 3 {
-               t.Fatalf("servers.read expected len(actualSrvs[0].HardwareInfo) 
== 3, actual = %v", len(actualSrvs[0].HardwareInfo))
-       }
-
-       if !srvInts[0].IPAddresses[0].ServiceAddress {
-               t.Fatalf("srvInts[0].IpAddresses[0].ServiceAddress expected to 
be true, actual = %v", srvInts[0].IPAddresses[0].ServiceAddress)
+               t.Fatalf("servers.read expected len(srvInts[0].IPAddresses) == 
1, actual = %v", len(srvInts[0].IPAddresses))
        }
 }
 
-func getMockServerDetails() []tc.ServerDetailV30 {
-       srvData := tc.ServerDetailV30{
-               tc.ServerDetail{
-                       ID: util.IntPtr(1),
-               },
+func getMockDSServers() []tc.DSServer {
+       base := tc.DSServerBase{
+               Cachegroup:   util.StrPtr("cgTest"),
+               CachegroupID: util.IntPtr(1),
+               CDNID:        util.IntPtr(1),
+               CDNName:      util.StrPtr("cdnTest"),
+               DomainName:   util.StrPtr("domain"),
+       }
+       srv := tc.DSServer{
+               base,
                &[]tc.ServerInterfaceInfo{}, // left empty because it must be 
written as json above since sqlmock does not support nested arrays
        }
-       return []tc.ServerDetailV30{srvData}
+       srvsExpected := []tc.DSServer{srv}
+       return srvsExpected
 }
diff --git a/traffic_ops/traffic_ops_golang/deliveryservice/servers/servers.go 
b/traffic_ops/traffic_ops_golang/deliveryservice/servers/servers.go
index 99d4bc4..69fb684 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/servers/servers.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/servers/servers.go
@@ -38,7 +38,7 @@ import (
        
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/deliveryservice"
        "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/tenant"
 
-       validation "github.com/go-ozzo/ozzo-validation"
+       "github.com/go-ozzo/ozzo-validation"
        "github.com/jmoiron/sqlx"
        "github.com/lib/pq"
 )
@@ -523,7 +523,28 @@ func getRead(w http.ResponseWriter, r *http.Request, 
unassigned bool, alerts tc.
                api.WriteAlerts(w, r, http.StatusInternalServerError, alerts)
                return
        }
-       api.WriteAlertsObj(w, r, 200, alerts, servers)
+
+       if inf.Version.Major < 3 {
+               v11ServerList := []tc.DSServerV11{}
+               for _, srv := range servers {
+                       v11server := tc.DSServerV11{}
+                       v11server.DSServerBase = srv.DSServerBase
+
+                       interfaces := *srv.ServerInterfaces
+                       legacyInterface, err := 
tc.InterfaceInfoToLegacyInterfaces(interfaces)
+                       if err != nil {
+                               api.HandleErr(w, r, inf.Tx.Tx, 
http.StatusInternalServerError, nil, errors.New("converting to server detail 
v11: "+err.Error()))
+                               return
+                       }
+                       v11server.LegacyInterfaceDetails = legacyInterface
+
+                       v11ServerList = append(v11ServerList, v11server)
+               }
+               api.WriteAlertsObj(w, r, http.StatusOK, alerts, v11ServerList)
+               return
+       }
+
+       api.WriteAlertsObj(w, r, http.StatusOK, alerts, servers)
 }
 
 func read(tx *sqlx.Tx, dsID int, user *auth.CurrentUser, unassigned bool) 
([]tc.DSServer, error) {
@@ -541,10 +562,49 @@ func read(tx *sqlx.Tx, dsID int, user *auth.CurrentUser, 
unassigned bool) ([]tc.
 
        servers := []tc.DSServer{}
        for rows.Next() {
+               serverInterfaceInfo := []tc.ServerInterfaceInfo{}
                s := tc.DSServer{}
-               if err = rows.StructScan(&s); err != nil {
+               err := rows.Scan(
+                       &s.Cachegroup,
+                       &s.CachegroupID,
+                       &s.CDNID,
+                       &s.CDNName,
+                       &s.DomainName,
+                       &s.GUID,
+                       &s.HostName,
+                       &s.HTTPSPort,
+                       &s.ID,
+                       &s.ILOIPAddress,
+                       &s.ILOIPGateway,
+                       &s.ILOIPNetmask,
+                       &s.ILOPassword,
+                       &s.ILOUsername,
+                       pq.Array(&serverInterfaceInfo),
+                       &s.LastUpdated,
+                       &s.MgmtIPAddress,
+                       &s.MgmtIPGateway,
+                       &s.MgmtIPNetmask,
+                       &s.OfflineReason,
+                       &s.PhysLocation,
+                       &s.PhysLocationID,
+                       &s.Profile,
+                       &s.ProfileDesc,
+                       &s.ProfileID,
+                       &s.Rack,
+                       &s.RouterHostName,
+                       &s.RouterPortName,
+                       &s.Status,
+                       &s.StatusID,
+                       &s.TCPPort,
+                       &s.Type,
+                       &s.TypeID,
+                       &s.UpdPending,
+               )
+               if err != nil {
                        return nil, errors.New("error scanning dss rows: " + 
err.Error())
                }
+               s.ServerInterfaces = &serverInterfaceInfo
+
                if user.PrivLevel < auth.PrivLevelAdmin {
                        s.ILOPassword = util.StrPtr("")
                }
@@ -574,13 +634,26 @@ func dssSelectQuery() string {
        s.ilo_ip_netmask,
        s.ilo_password,
        s.ilo_username,
-       COALESCE(s.interface_mtu, ` + strconv.Itoa(JumboFrameBPS) + `) as 
interface_mtu,
-       s.interface_name,
-       s.ip6_address,
-       s.ip6_gateway,
-       s.ip_address,
-       s.ip_gateway,
-       s.ip_netmask,
+       ARRAY (
+SELECT ( json_build_object (
+'ipAddresses', ARRAY (
+SELECT ( json_build_object (
+'address', ip_address.address,
+'gateway', ip_address.gateway,
+'serviceAddress', ip_address.service_address
+))
+FROM ip_address
+WHERE ip_address.interface = interface.name
+AND ip_address.server = s.id
+),
+'max_bandwidth', interface.max_bandwidth,
+'monitor', interface.monitor,
+'mtu', COALESCE (interface.mtu, 9000),
+'name', interface.name
+))
+FROM interface
+WHERE interface.server = s.id
+) AS interfaces,
        s.last_updated,
        s.mgmt_ip_address,
        s.mgmt_ip_gateway,
diff --git 
a/traffic_ops/traffic_ops_golang/deliveryservice/servers/servers_test.go 
b/traffic_ops/traffic_ops_golang/deliveryservice/servers/servers_test.go
index 319dfc5..0754bee 100644
--- a/traffic_ops/traffic_ops_golang/deliveryservice/servers/servers_test.go
+++ b/traffic_ops/traffic_ops_golang/deliveryservice/servers/servers_test.go
@@ -20,8 +20,15 @@ package servers
  */
 
 import (
-       
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
        "testing"
+
+       "github.com/apache/trafficcontrol/lib/go-tc"
+       "github.com/apache/trafficcontrol/lib/go-util"
+       "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/auth"
+       
"github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers"
+       "github.com/jmoiron/sqlx"
+
+       "gopkg.in/DATA-DOG/go-sqlmock.v1"
 )
 
 func TestValidateDSSAssignments(t *testing.T) {
@@ -51,3 +58,129 @@ func TestValidateDSSAssignments(t *testing.T) {
                t.Fatalf("Expected no user error, got %v", userErr.Error())
        }
 }
+
+func TestReadServers(t *testing.T) {
+       mockDB, mock, err := sqlmock.New()
+       if err != nil {
+               t.Fatalf("an error '%s' was not expected when opening a stub 
database connection", err)
+       }
+       defer mockDB.Close()
+
+       db := sqlx.NewDb(mockDB, "sqlmock")
+       defer db.Close()
+
+       testServers := getMockDSServers()
+       cols := []string{"cachegroup",
+               "cachegroup_id",
+               "cdn_id",
+               "cdn_name",
+               "domain_name",
+               "guid",
+               "host_name",
+               "https_port",
+               "id",
+               "ilo_ip_address",
+               "ilo_ip_gateway",
+               "ilo_ip_netmask",
+               "ilo_password",
+               "ilo_username",
+               "interfaces",
+               "last_updated",
+               "mgmt_ip_address",
+               "mgmt_ip_gateway",
+               "mgmt_ip_netmask",
+               "offline_reason",
+               "phys_location",
+               "phys_location_id",
+               "profile",
+               "profile_desc",
+               "profile_id",
+               "rack",
+               "router_host_name",
+               "router_port_name",
+               "status",
+               "status_id",
+               "tcp_port",
+               "server_type",
+               "server_type_id",
+               "upd_pending"}
+
+       rows := sqlmock.NewRows(cols)
+
+       for _, s := range testServers {
+               rows = rows.AddRow(
+                       s.Cachegroup,
+                       s.CachegroupID,
+                       s.CDNID,
+                       s.CDNName,
+                       s.DomainName,
+                       s.GUID,
+                       s.HostName,
+                       s.HTTPSPort,
+                       s.ID,
+                       s.ILOIPAddress,
+                       s.ILOIPGateway,
+                       s.ILOIPNetmask,
+                       s.ILOPassword,
+                       s.ILOUsername,
+                       []byte(`{"{\"ipAddresses\" : [{\"address\" : 
\"127.0.0.0\", \"gateway\" : null, \"service_address\" : true}], 
\"max_bandwidth\" : null, \"monitor\" : true, \"mtu\" : 1500, \"name\" : 
\"eth0\"}"}`),
+                       s.LastUpdated,
+                       s.MgmtIPAddress,
+                       s.MgmtIPGateway,
+                       s.MgmtIPNetmask,
+                       s.OfflineReason,
+                       s.PhysLocation,
+                       s.PhysLocationID,
+                       s.Profile,
+                       s.ProfileDesc,
+                       s.ProfileID,
+                       s.Rack,
+                       s.RouterHostName,
+                       s.RouterPortName,
+                       s.Status,
+                       s.StatusID,
+                       s.TCPPort,
+                       s.Type,
+                       s.TypeID,
+                       s.UpdPending,
+               )
+       }
+
+       mock.ExpectBegin()
+       mock.ExpectQuery("SELECT").WillReturnRows(rows)
+       mock.ExpectCommit()
+
+       actualSrvs, err := read(db.MustBegin(), 1, &auth.CurrentUser{PrivLevel: 
30}, false)
+       if err != nil {
+               t.Fatalf("an error '%s' occurred during read", err)
+       }
+
+       if len(actualSrvs) != 1 {
+               t.Fatalf("servers.read expected len(actualSrvs) == 1, actual = 
%v", len(actualSrvs))
+       }
+
+       srvInts := *(actualSrvs[0]).ServerInterfaces
+       if len(srvInts) != 1 {
+               t.Fatalf("servers.read expected len(srvInts) == 1, actual = 
%v", len(srvInts))
+       }
+
+       if len(srvInts[0].IPAddresses) != 1 {
+               t.Fatalf("servers.read expected len(srvInts[0].IPAddresses) == 
1, actual = %v", len(srvInts[0].IPAddresses))
+       }
+}
+
+func getMockDSServers() []tc.DSServer {
+       base := tc.DSServerBase{
+               Cachegroup:   util.StrPtr("cgTest"),
+               CachegroupID: util.IntPtr(1),
+               CDNID:        util.IntPtr(1),
+               CDNName:      util.StrPtr("cdnTest"),
+               DomainName:   util.StrPtr("domain"),
+       }
+       srv := tc.DSServer{
+               base,
+               &[]tc.ServerInterfaceInfo{}, // left empty because it must be 
written as json above since sqlmock does not support nested arrays
+       }
+       srvsExpected := []tc.DSServer{srv}
+       return srvsExpected
+}
diff --git a/traffic_ops/traffic_ops_golang/server/detail_test.go 
b/traffic_ops/traffic_ops_golang/server/detail_test.go
index 3b937f8..1eeaffb 100644
--- a/traffic_ops/traffic_ops_golang/server/detail_test.go
+++ b/traffic_ops/traffic_ops_golang/server/detail_test.go
@@ -127,7 +127,7 @@ func TestGetDetailServers(t *testing.T) {
        }
 
        if len(srvInts[0].IPAddresses) != 1 {
-               t.Fatalf("servers.read expected len(srvInts[0].IpAddresses) == 
1, actual = %v", len(srvInts[0].IPAddresses))
+               t.Fatalf("servers.read expected len(srvInts[0].IPAddresses) == 
1, actual = %v", len(srvInts[0].IPAddresses))
        }
 
        if len(actualSrvs[0].HardwareInfo) != 3 {
@@ -135,7 +135,7 @@ func TestGetDetailServers(t *testing.T) {
        }
 
        if !srvInts[0].IPAddresses[0].ServiceAddress {
-               t.Fatalf("srvInts[0].IpAddresses[0].ServiceAddress expected to 
be true, actual = %v", srvInts[0].IPAddresses[0].ServiceAddress)
+               t.Fatalf("srvInts[0].IPAddresses[0].ServiceAddress expected to 
be true, actual = %v", srvInts[0].IPAddresses[0].ServiceAddress)
        }
 }
 
diff --git a/traffic_ops/v1-client/deliveryservice.go 
b/traffic_ops/v1-client/deliveryservice.go
index 5fb7300..9f99b81 100644
--- a/traffic_ops/v1-client/deliveryservice.go
+++ b/traffic_ops/v1-client/deliveryservice.go
@@ -345,10 +345,10 @@ func (to *Session) GetDeliveryServiceMatches() 
([]tc.DeliveryServicePatterns, Re
        return resp.Response, reqInf, nil
 }
 
-func (to *Session) GetDeliveryServicesEligible(dsID int) ([]tc.DSServer, 
ReqInf, error) {
+func (to *Session) GetDeliveryServicesEligible(dsID int) ([]tc.DSServerV11, 
ReqInf, error) {
        resp := struct {
-               Response []tc.DSServer `json:"response"`
-       }{Response: []tc.DSServer{}}
+               Response []tc.DSServerV11 `json:"response"`
+       }{Response: []tc.DSServerV11{}}
        uri := apiBase + `/deliveryservices/` + strconv.Itoa(dsID) + 
`/servers/eligible`
        reqInf, err := get(to, uri, &resp)
        if err != nil {
diff --git a/traffic_ops/v2-client/deliveryservice.go 
b/traffic_ops/v2-client/deliveryservice.go
index 7191391..e56aaed 100644
--- a/traffic_ops/v2-client/deliveryservice.go
+++ b/traffic_ops/v2-client/deliveryservice.go
@@ -317,10 +317,10 @@ func (to *Session) GetDeliveryServiceSSLKeysByID(XMLID 
string) (*tc.DeliveryServ
 
 // GetDeliveryServicesEligible returns the servers eligible for assignment to 
the Delivery
 // Service identified by the integral, unique identifier 'dsID'.
-func (to *Session) GetDeliveryServicesEligible(dsID int) ([]tc.DSServer, 
ReqInf, error) {
+func (to *Session) GetDeliveryServicesEligible(dsID int) ([]tc.DSServerV11, 
ReqInf, error) {
        resp := struct {
-               Response []tc.DSServer `json:"response"`
-       }{Response: []tc.DSServer{}}
+               Response []tc.DSServerV11 `json:"response"`
+       }{Response: []tc.DSServerV11{}}
 
        reqInf, err := get(to, 
fmt.Sprintf(API_DELIVERY_SERVICE_ELIGIBLE_SERVERS, dsID), &resp)
        if err != nil {

Reply via email to