You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by oc...@apache.org on 2022/04/26 19:25:00 UTC

[trafficcontrol] branch master updated: Layered Server Feature for `GET` API endpoint `servers/details` (#6593)

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 225f91c5fe Layered Server Feature for `GET` API endpoint `servers/details` (#6593)
225f91c5fe is described below

commit 225f91c5febe8155ed01cb36b501c213de420ad8
Author: Rima Shah <22...@users.noreply.github.com>
AuthorDate: Tue Apr 26 13:24:55 2022 -0600

    Layered Server Feature for `GET` API endpoint `servers/details` (#6593)
    
    * Updated server struct and type for V4 and added commonpropertiesV40 function and struct
    
    * Added db migration files
    
    * Added backward compatibility to get (GET) and update (PUT) /server
    
    * Updated docs for GET /server and PUT /server/{id}
    
    * Updated migration script, doc, /server API endpoint for GET and PUT
    
    * Updated query for profile_names
    
    * Updated profile_names type
    
    * Passing in the original transaction id
    
    * Update servers.go for PUT servers/{id} API
    
    * Moved function having db transactions to dbhelpers.
    
    * Fixed go vet
    
    * Fixed testing/api/v4 test
    
    * Updated cache config and lib test
    
    * Fixed fmt to log
    
    * Fixed server profile to profiles
    
    * Updated docs and tests(cache-config).
    
    * Updated tests to accept first profile to ensure current tests pass.
    
    * Updated tests to accept first profile to ensure current tests pass-1.
    
    * Added changelog entry
    
    * Fixed unit tests
    
    * Removed fmt statement.
    
    * Tc_fixture updated for profiles (v4).
    
    * Added logic for POST servers/
    
    * Updated server_profile foreign key constraint for delete servers/{id} API
    
    * Updated db_helper functions to return err
    
    * Updated parentdotconfig.go and server.go for profile
    
    * Fixed test related to profile
    
    * Updated API/v4 test related to profile.
    Updated tc_fixtures tp remove duplicate interface ip.
    
    * Removed extra if clause.
    
    * Removed database transaction from api/v4/ tests
    
    * Updated changelog and server params
    
    * Removed fmt statements
    
    * updated select statement for v2/v3 and added logic to fill in server_profile table for v2/v3 when creating a server
    
    * replaced profileId with profileNames in traffic portal data
    
    * replaced profileId with profileNames in traffic portal data-1
    
    * Updated ServerDetail struct and getDetailServers() to handle array of profile_names for V4
    
    * Removed changes from checkTypeChangeSafety() in servers.go
    
    * Updated unit test for servers_test.go and added multiple profiles to one of the servers in v4/tc_fixtures
    
    * Changed enroller server_template.json for CIAB
    
    * Traffic Portal changes
    
    * Removed db_helpers function from cache-config
    
    * Updated TP server's integration test
    
    * Removed get profile name request by profile ID since we already have a profile name.
    
    * updated profile field in server
    
    * updated unit test
    
    * updated error message in validatedCommonV40 and server integration tests
    
    * updated API.ts to add random characters for profileNames
    
    * updated APIv4 docs
    
    * Made profile-names singular to match current documentation.
    
    * Update based on review comments.
    
    * Changed Profiles field in go struct to ProfileNames to match JSON.
    
    * Fixed unit test.
    
    * Changed ProfileNames field type in struct ServerV40 to []string from pq.StringArray
    
    * Removed additional code from TP.
    
    * Updated code and queries for PUT and POST call.
    
    * Updated function call param
    
    * Changed CommonServerPropertiesV40 field ProfileNames from a pointer of string slice to a slice of string. Created new migration file to make them as latest date.
    
    * Created new migration file to make them as latest date.
    
    * Updated conversion.go
    
    * Fixed queries and scan() to correct GH failures.
    
    * Updated profile to a []string from a string and removed profileDesc from ServerDetailsV40
    
    * Added error check and renamed Profiles back to Profile for V3/V2
    
    * Added changelog entry and updated doc
    
    * removed incorrect migration file and revert changes in v4/tc_fixtures.json
    
    * removed ServerDetailsV40{}.
    
    * updated based on review comments.
---
 CHANGELOG.md                                       |  1 +
 docs/source/api/v4/servers_details.rst             |  6 +--
 lib/go-tc/servers.go                               | 29 ++++++++++++-
 traffic_ops/testing/api/v4/tc-fixtures.json        | 32 +++++++--------
 .../traffic_ops_golang/dbhelpers/db_helpers.go     | 37 +++++++++++++++++
 traffic_ops/traffic_ops_golang/server/detail.go    | 48 +++++++++++++++++++---
 .../traffic_ops_golang/server/detail_test.go       | 16 +++-----
 7 files changed, 132 insertions(+), 37 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3aaee21caa..043163cbf3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
 - [Traffic Ops | Traffic Go Clients | T3C] Add additional timestamp fields to server for queuing and dequeueing config and revalidate updates.
 - Added layered profile feature to 4.0 for `GET` /servers/, `POST` /servers/, `PUT` /servers/{id} and `DELETE` /servers/{id}.
 - Added a Traffic Ops endpoint and Traffic Portal page to view all CDNi configuration update requests and approve or deny.
+- Added layered profile feature to 4.0 for `GET` /servers/details.
 - Added layered profile feature to 4.0 for `GET` /deliveryservices/{id}/servers/ and /deliveryservices/{id}/servers/eligible.
 
 ### Fixed
diff --git a/docs/source/api/v4/servers_details.rst b/docs/source/api/v4/servers_details.rst
index afc95ed6ae..dc0a917b50 100644
--- a/docs/source/api/v4/servers_details.rst
+++ b/docs/source/api/v4/servers_details.rst
@@ -98,8 +98,7 @@ Response Structure
 	:mgmtIpNetmask:  The IPv4 subnet mask of the server's management port
 	:offlineReason:         A user-entered reason why the server is in ADMIN_DOWN or OFFLINE status
 	:physLocation:          The name of the physical location where the server resides
-	:profile:               The :ref:`profile-name` of the :term:`Profile` used by this server
-	:profileDesc:           A :ref:`profile-description` of the :term:`Profile` used by this server
+	:profileNames:          List of :ref:`profile-name` of the :term:`Profiles` used by this server
 	:rack:  A string indicating "server rack" location
 	:status:                The status of the server
 
@@ -157,8 +156,7 @@ Response Structure
 				"mgmtIpNetmask": "",
 				"offlineReason": "",
 				"physLocation": "Apachecon North America 2018",
-				"profile": "ATS_EDGE_TIER_CACHE",
-				"profileDesc": "Edge Cache - Apache Traffic Server",
+				"profileNames": ["ATS_EDGE_TIER_CACHE"],
 				"rack": "",
 				"status": "REPORTED",
 				"tcpPort": 80,
diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go
index 23971316b5..2f435cdb3f 100644
--- a/lib/go-tc/servers.go
+++ b/lib/go-tc/servers.go
@@ -87,8 +87,33 @@ type ServerDetailV30 struct {
 
 // ServerDetailV40 is the details for a server for API v4.
 type ServerDetailV40 struct {
-	ServerDetail
-	ServerInterfaces []ServerInterfaceInfoV40 `json:"interfaces"`
+	CacheGroup         *string                  `json:"cachegroup" db:"cachegroup"`
+	CDNName            *string                  `json:"cdnName" db:"cdn_name"`
+	DeliveryServiceIDs []int64                  `json:"deliveryservices,omitempty"`
+	DomainName         *string                  `json:"domainName" db:"domain_name"`
+	GUID               *string                  `json:"guid" db:"guid"`
+	HardwareInfo       map[string]string        `json:"hardwareInfo"`
+	HostName           *string                  `json:"hostName" db:"host_name"`
+	HTTPSPort          *int                     `json:"httpsPort" db:"https_port"`
+	ID                 *int                     `json:"id" db:"id"`
+	ILOIPAddress       *string                  `json:"iloIpAddress" db:"ilo_ip_address"`
+	ILOIPGateway       *string                  `json:"iloIpGateway" db:"ilo_ip_gateway"`
+	ILOIPNetmask       *string                  `json:"iloIpNetmask" db:"ilo_ip_netmask"`
+	ILOPassword        *string                  `json:"iloPassword" db:"ilo_password"`
+	ILOUsername        *string                  `json:"iloUsername" db:"ilo_username"`
+	MgmtIPAddress      *string                  `json:"mgmtIpAddress" db:"mgmt_ip_address"`
+	MgmtIPGateway      *string                  `json:"mgmtIpGateway" db:"mgmt_ip_gateway"`
+	MgmtIPNetmask      *string                  `json:"mgmtIpNetmask" db:"mgmt_ip_netmask"`
+	OfflineReason      *string                  `json:"offlineReason" db:"offline_reason"`
+	PhysLocation       *string                  `json:"physLocation" db:"phys_location"`
+	ProfileNames       []string                 `json:"profileNames" db:"profile_name"`
+	Rack               *string                  `json:"rack" db:"rack"`
+	Status             *string                  `json:"status" db:"status"`
+	TCPPort            *int                     `json:"tcpPort" db:"tcp_port"`
+	Type               string                   `json:"type" db:"server_type"`
+	XMPPID             *string                  `json:"xmppId" db:"xmpp_id"`
+	XMPPPasswd         *string                  `json:"xmppPasswd" db:"xmpp_passwd"`
+	ServerInterfaces   []ServerInterfaceInfoV40 `json:"interfaces"`
 }
 
 // ServersV1DetailResponse is the JSON object returned for a single server for v1.
diff --git a/traffic_ops/testing/api/v4/tc-fixtures.json b/traffic_ops/testing/api/v4/tc-fixtures.json
index 011a1a8042..ebf1fab2aa 100644
--- a/traffic_ops/testing/api/v4/tc-fixtures.json
+++ b/traffic_ops/testing/api/v4/tc-fixtures.json
@@ -5009,8 +5009,8 @@
         {
             "cachegroup": "cachegroup1",
             "cdnName": "cdn1",
-			"configUpdateTime": "2022-01-01T17:00:00-07:00",
-			"configApplyTime": "1969-12-31T17:00:00-07:00",
+            "configUpdateTime": "2022-01-01T17:00:00-07:00",
+            "configApplyTime": "1969-12-31T17:00:00-07:00",
             "domainName": "ga.atlanta.kabletown.net",
             "guid": null,
             "hostName": "config-update-time",
@@ -5060,8 +5060,8 @@
         {
             "cachegroup": "cachegroup1",
             "cdnName": "cdn1",
-			"configUpdateTime": "2022-01-01T17:00:00-07:00",
-			"configApplyTime": "1969-12-31T17:00:00-07:00",
+            "configUpdateTime": "2022-01-01T17:00:00-07:00",
+            "configApplyTime": "1969-12-31T17:00:00-07:00",
             "domainName": "ga.atlanta.kabletown.net",
             "guid": null,
             "hostName": "config-update-time-no-updpend",
@@ -5149,8 +5149,8 @@
             "profileNames": ["EDGE1"],
             "rack": "RR 119.02",
             "revalPending": false,
-			"revalUpdateTime": "2022-01-01T17:00:00-07:00",
-			"revalApplyTime": "1969-12-31T17:00:00-07:00",
+            "revalUpdateTime": "2022-01-01T17:00:00-07:00",
+            "revalApplyTime": "1969-12-31T17:00:00-07:00",
             "status": "REPORTED",
             "tcpPort": 80,
             "type": "EDGE",
@@ -5199,8 +5199,8 @@
             "physLocation": "Denver",
             "profileNames": ["EDGE1"],
             "rack": "RR 119.02",
-			"revalUpdateTime": "2022-01-01T17:00:00-07:00",
-			"revalApplyTime": "1969-12-31T17:00:00-07:00",
+            "revalUpdateTime": "2022-01-01T17:00:00-07:00",
+            "revalApplyTime": "1969-12-31T17:00:00-07:00",
             "status": "REPORTED",
             "tcpPort": 80,
             "type": "EDGE",
@@ -5211,8 +5211,8 @@
         {
             "cachegroup": "cachegroup1",
             "cdnName": "cdn1",
-			"configUpdateTime": "2022-01-01T17:00:00-07:00",
-			"configApplyTime": "1969-12-31T17:00:00-07:00",
+            "configUpdateTime": "2022-01-01T17:00:00-07:00",
+            "configApplyTime": "1969-12-31T17:00:00-07:00",
             "domainName": "ga.atlanta.kabletown.net",
             "guid": null,
             "hostName": "config-reval-update-time",
@@ -5252,8 +5252,8 @@
             "profileNames": ["EDGE1"],
             "rack": "RR 119.02",
             "revalPending": false,
-			"revalUpdateTime": "2022-01-01T17:00:00-07:00",
-			"revalApplyTime": "1969-12-31T17:00:00-07:00",
+            "revalUpdateTime": "2022-01-01T17:00:00-07:00",
+            "revalApplyTime": "1969-12-31T17:00:00-07:00",
             "status": "REPORTED",
             "tcpPort": 80,
             "type": "EDGE",
@@ -5264,8 +5264,8 @@
         {
             "cachegroup": "cachegroup1",
             "cdnName": "cdn1",
-			"configUpdateTime": "2022-01-01T17:00:00-07:00",
-			"configApplyTime": "1969-12-31T17:00:00-07:00",
+            "configUpdateTime": "2022-01-01T17:00:00-07:00",
+            "configApplyTime": "1969-12-31T17:00:00-07:00",
             "domainName": "ga.atlanta.kabletown.net",
             "guid": null,
             "hostName": "config-reval-update-time-only",
@@ -5304,8 +5304,8 @@
             "physLocation": "Denver",
             "profileNames": ["EDGE1"],
             "rack": "RR 119.02",
-			"revalUpdateTime": "2022-01-01T17:00:00-07:00",
-			"revalApplyTime": "1969-12-31T17:00:00-07:00",
+            "revalUpdateTime": "2022-01-01T17:00:00-07:00",
+            "revalApplyTime": "1969-12-31T17:00:00-07:00",
             "status": "REPORTED",
             "tcpPort": 80,
             "type": "EDGE",
diff --git a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go
index e024126d01..dc029086bf 100644
--- a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go
+++ b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go
@@ -2091,6 +2091,43 @@ func UpdateServerProfileTableForV2V3(id *int, newProfile *string, origProfile st
 	return profileName, nil
 }
 
+// GetServerDetailFromV4 function converts server details from V4 to V3/V2
+func GetServerDetailFromV4(sd tc.ServerDetailV40, tx *sql.Tx) (tc.ServerDetail, error) {
+	var profileDesc *string
+	if err := tx.QueryRow(`SELECT p.description FROM profile p WHERE p.name=$1`, sd.ProfileNames[0]).Scan(&profileDesc); err != nil {
+		return tc.ServerDetail{}, fmt.Errorf("querying profile description by profile name: %w", err)
+	}
+	return tc.ServerDetail{
+		CacheGroup:         sd.CacheGroup,
+		CDNName:            sd.CDNName,
+		DeliveryServiceIDs: sd.DeliveryServiceIDs,
+		DomainName:         sd.DomainName,
+		GUID:               sd.GUID,
+		HardwareInfo:       sd.HardwareInfo,
+		HostName:           sd.HostName,
+		HTTPSPort:          sd.HTTPSPort,
+		ID:                 sd.ID,
+		ILOIPAddress:       sd.ILOIPAddress,
+		ILOIPGateway:       sd.ILOIPGateway,
+		ILOIPNetmask:       sd.ILOIPNetmask,
+		ILOPassword:        sd.ILOPassword,
+		ILOUsername:        sd.ILOUsername,
+		MgmtIPAddress:      sd.MgmtIPAddress,
+		MgmtIPGateway:      sd.MgmtIPGateway,
+		MgmtIPNetmask:      sd.MgmtIPNetmask,
+		OfflineReason:      sd.OfflineReason,
+		PhysLocation:       sd.PhysLocation,
+		Profile:            &sd.ProfileNames[0],
+		ProfileDesc:        profileDesc,
+		Rack:               sd.Rack,
+		Status:             sd.Status,
+		TCPPort:            sd.TCPPort,
+		Type:               sd.Type,
+		XMPPID:             sd.XMPPID,
+		XMPPPasswd:         sd.XMPPPasswd,
+	}, nil
+}
+
 // GetProfileIDDesc gets profile ID and desc for V3 servers
 func GetProfileIDDesc(tx *sql.Tx, name string) (id int, desc string) {
 	err := tx.QueryRow(`SELECT id, description from "profile" p WHERE p.name=$1`, name).Scan(&id, &desc)
diff --git a/traffic_ops/traffic_ops_golang/server/detail.go b/traffic_ops/traffic_ops_golang/server/detail.go
index 7f2eb9b1f7..aa45dd9552 100644
--- a/traffic_ops/traffic_ops_golang/server/detail.go
+++ b/traffic_ops/traffic_ops_golang/server/detail.go
@@ -91,7 +91,11 @@ func GetDetailParamHandler(w http.ResponseWriter, r *http.Request) {
 				routerPortName = interfaces[0].RouterPortName
 			}
 			v11server := tc.ServerDetailV11{}
-			v11server.ServerDetail = server.ServerDetail
+			v11server.ServerDetail, err = dbhelpers.GetServerDetailFromV4(server, inf.Tx.Tx)
+			if err != nil {
+				api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("failed to GetServerDetailFromV4: %w", err))
+				return
+			}
 			v11server.RouterHostName = &routerHostName
 			v11server.RouterPortName = &routerPortName
 			legacyInterface, err := tc.V4InterfaceInfoToLegacyInterfaces(interfaces)
@@ -117,7 +121,11 @@ func GetDetailParamHandler(w http.ResponseWriter, r *http.Request) {
 				routerHostName = interfaces[0].RouterHostName
 				routerPortName = interfaces[0].RouterPortName
 			}
-			v3Server.ServerDetail = server.ServerDetail
+			v3Server.ServerDetail, err = dbhelpers.GetServerDetailFromV4(server, inf.Tx.Tx)
+			if err != nil {
+				api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, fmt.Errorf("failed to GetServerDetailFromV4: %w", err))
+				return
+			}
 			v3Server.RouterHostName = &routerHostName
 			v3Server.RouterPortName = &routerPortName
 			v3Interfaces, err := tc.V4InterfaceInfoToV3Interfaces(interfaces)
@@ -209,8 +217,7 @@ server.mgmt_ip_gateway,
 server.mgmt_ip_netmask,
 server.offline_reason,
 pl.name as phys_location,
-p.name as profile,
-p.description as profile_desc,
+(SELECT ARRAY_AGG(profile_name) FROM server_profile WHERE server_profile.server=server.id) AS profile_name,
 server.rack,
 st.name as status,
 server.tcp_port,
@@ -275,7 +282,38 @@ JOIN type t ON server.type = t.id
 
 	for rows.Next() {
 		s := tc.ServerDetailV40{}
-		if err := rows.Scan(&s.ID, &s.CacheGroup, &s.CDNName, pq.Array(&s.DeliveryServiceIDs), &s.DomainName, &s.GUID, &s.HostName, &s.HTTPSPort, &s.ILOIPAddress, &s.ILOIPGateway, &s.ILOIPNetmask, &s.ILOPassword, &s.ILOUsername, &serviceAddress, &service6Address, &serviceGateway, &service6Gateway, &serviceNetmask, &serviceInterface, &serviceMtu, &s.MgmtIPAddress, &s.MgmtIPGateway, &s.MgmtIPNetmask, &s.OfflineReason, &s.PhysLocation, &s.Profile, &s.ProfileDesc, &s.Rack, &s.Status, &s.TCPPort, & [...]
+		if err := rows.Scan(&s.ID,
+			&s.CacheGroup,
+			&s.CDNName,
+			pq.Array(&s.DeliveryServiceIDs),
+			&s.DomainName,
+			&s.GUID,
+			&s.HostName,
+			&s.HTTPSPort,
+			&s.ILOIPAddress,
+			&s.ILOIPGateway,
+			&s.ILOIPNetmask,
+			&s.ILOPassword,
+			&s.ILOUsername,
+			&serviceAddress,
+			&service6Address,
+			&serviceGateway,
+			&service6Gateway,
+			&serviceNetmask,
+			&serviceInterface,
+			&serviceMtu,
+			&s.MgmtIPAddress,
+			&s.MgmtIPGateway,
+			&s.MgmtIPNetmask,
+			&s.OfflineReason,
+			&s.PhysLocation,
+			pq.Array(&s.ProfileNames),
+			&s.Rack,
+			&s.Status,
+			&s.TCPPort,
+			&s.Type,
+			&s.XMPPID,
+			&s.XMPPPasswd); err != nil {
 			return nil, errors.New("Error scanning detail server: " + err.Error())
 		}
 		s.ServerInterfaces = []tc.ServerInterfaceInfoV40{}
diff --git a/traffic_ops/traffic_ops_golang/server/detail_test.go b/traffic_ops/traffic_ops_golang/server/detail_test.go
index 9ad95ac564..bbcfa53788 100644
--- a/traffic_ops/traffic_ops_golang/server/detail_test.go
+++ b/traffic_ops/traffic_ops_golang/server/detail_test.go
@@ -13,7 +13,9 @@ package server
 */
 
 import (
+	"fmt"
 	"strconv"
+	"strings"
 	"testing"
 
 	"github.com/apache/trafficcontrol/lib/go-tc"
@@ -75,8 +77,7 @@ func TestGetDetailServers(t *testing.T) {
 		"mgmt_ip_netmask",
 		"offline_reason",
 		"phys_location",
-		"profile",
-		"profile_desc",
+		"profile_name",
 		"rack",
 		"status",
 		"tcp_port",
@@ -93,8 +94,6 @@ func TestGetDetailServers(t *testing.T) {
 	serviceNetmask := util.StrPtr("")
 	serviceInterface := util.StrPtr("")
 	serviceMtu := util.StrPtr("")
-	//routerHostName := util.StrPtr("")
-	//routerPort := util.StrPtr("")
 
 	for _, sd := range testServerDetails {
 		detailRows = detailRows.AddRow(
@@ -123,8 +122,7 @@ func TestGetDetailServers(t *testing.T) {
 			sd.MgmtIPNetmask,
 			sd.OfflineReason,
 			sd.PhysLocation,
-			sd.Profile,
-			sd.ProfileDesc,
+			fmt.Sprintf("{%s}", strings.Join(sd.ProfileNames, ",")),
 			sd.Rack,
 			sd.Status,
 			sd.TCPPort,
@@ -143,7 +141,7 @@ func TestGetDetailServers(t *testing.T) {
 	mock.ExpectQuery("SELECT serverid").WillReturnRows(hwInfoRows)
 	mock.ExpectCommit()
 
-	actualSrvs, err := getDetailServers(db.MustBegin().Tx, &auth.CurrentUser{PrivLevel: 30}, "test", 1, "id", 10, api.Version{Major: 3})
+	actualSrvs, err := getDetailServers(db.MustBegin().Tx, &auth.CurrentUser{PrivLevel: 30}, "test", 1, "id", 10, api.Version{Major: 4})
 	if err != nil {
 		t.Fatalf("an error '%s' occurred during read", err)
 	}
@@ -170,9 +168,7 @@ func TestGetDetailServers(t *testing.T) {
 
 func getMockServerDetails() []tc.ServerDetailV40 {
 	srvData := tc.ServerDetailV40{
-		ServerDetail: tc.ServerDetail{
-			ID: util.IntPtr(1),
-		},
+		ID:               util.IntPtr(1),
 		ServerInterfaces: []tc.ServerInterfaceInfoV40{}, // left empty because it must be written as json above since sqlmock does not support nested arrays
 	}
 	return []tc.ServerDetailV40{srvData}