Skip to content
This repository was archived by the owner on Nov 24, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
- [#7032](https://github.com/apache/trafficcontrol/issues/7032) Add t3c-apply flag to use local ATS version for config generation rather than Server package Parameter, to allow managing the ATS OS package via external tools. See 'man t3c-apply' and 'man t3c-generate' for details.

- [Traffic Monitor] Added logging for `ipv4Availability` and `ipv6Availability` in TM.
- [Traffic Ops] Added the `ASN` field in TO Server struct, which provides the ability to query servers by `ASN`.

### Changed
- Traffic Portal now obscures sensitive text in Delivery Service "Raw Remap" fields, private SSL keys, "Header Rewrite" rules, and ILO interface passwords by default.
Expand Down
2 changes: 1 addition & 1 deletion cache-config/t3cutil/toreq/clientfuncs.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ func (cl *TOClient) GetServerByHostName(serverHostName string, reqHdr http.Heade
if len(toServers.Response) < 1 {
return errors.New("getting server name '" + serverHostName + "' from Traffic Ops '" + torequtil.MaybeIPStr(reqInf.RemoteAddr) + "': no servers returned")
}
asv, err := serverToLatest(&toServers.Response[0])
asv, err := serverToLatest(&toServers.Response[0].ServerV40)
if err != nil {
return errors.New("converting server to latest version: " + err.Error())
}
Expand Down
8 changes: 6 additions & 2 deletions cache-config/t3cutil/toreq/conversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@ import (
)

func serversToLatest(svs tc.ServersV4Response) ([]atscfg.Server, error) {
return atscfg.ToServers(svs.Response), nil
serversV40 := make([]tc.ServerV40, 0)
for _, srv := range svs.Response {
serversV40 = append(serversV40, srv.ServerV40)
}
return atscfg.ToServers(serversV40), nil
}

func serverToLatest(oldSv *tc.ServerV40) (*atscfg.Server, error) {
Expand Down Expand Up @@ -218,7 +222,7 @@ func (cl *TOClient) GetServersCompat(opts toclient.RequestOptions) (tc.ServersV4
if err != nil {
return tc.ServersV4Response{}, reqInf, errors.New("converting server from possible legacy format: " + err.Error())
}
resp.Response = append(resp.Response, newSv)
resp.Response = append(resp.Response, tc.ServerV41{ServerV40: newSv})
}
return resp, reqInf, nil
}
Expand Down
12 changes: 12 additions & 0 deletions docs/source/api/v4/servers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ Request Structure
| | | the first page is 1. If ``offset`` was defined, this query parameter has no effect. ``limit`` must be defined to |
| | | make use of ``page``. |
+----------------+----------+-------------------------------------------------------------------------------------------------------------------+
| asn | no | Return only the servers that have a cachegroup matching the provided ASN. |
| | | |
| | | .. versionadded:: 4.1 |
+----------------+----------+-------------------------------------------------------------------------------------------------------------------+


.. code-block:: http
:caption: Request Example
Expand All @@ -81,6 +86,9 @@ Request Structure

Response Structure
------------------
:asns: The :abbr:`ASN (Autonomous System Number)` associated with the cachegroups of the current server.

.. versionadded:: 4.1
:cachegroup: A string that is the :ref:`name of the Cache Group <cache-group-name>` to which the server belongs
:cachegroupId: An integer that is the :ref:`ID of the Cache Group <cache-group-id>` to which the server belongs
:cdnId: The integral, unique identifier of the CDN to which the server belongs
Expand Down Expand Up @@ -225,6 +233,10 @@ Response Structure
"routerHostName": "",
"routerPortName": ""
}
],
"asns": [
1,
2
]
}],
"summary": {
Expand Down
2 changes: 1 addition & 1 deletion infrastructure/cdn-in-a-box/enroller/enroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -757,7 +757,7 @@ func enrollServer(toSession *session, r io.Reader) error {
return err
}

alerts, _, err := toSession.CreateServer(s, client.RequestOptions{})
alerts, _, err := toSession.CreateServer(tc.ServerV4{ServerV40: s}, client.RequestOptions{})
if err != nil {
err = fmt.Errorf("error creating Server: %v - alerts: %+v", err, alerts.Alerts)
log.Infoln(err)
Expand Down
10 changes: 8 additions & 2 deletions lib/go-tc/servers.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (

// ServersV4Response is the format of a response to a GET request for API v4.x /servers.
type ServersV4Response struct {
Response []ServerV40 `json:"response"`
Response []ServerV41 `json:"response"`
Summary struct {
Count uint64 `json:"count"`
} `json:"summary"`
Expand Down Expand Up @@ -1019,6 +1019,12 @@ func UpdateServerPropertiesV40(profileNames []string, properties CommonServerPro
}
}

// ServerV41 is the representation of a Server in version 4.1 of the Traffic Ops API.
type ServerV41 struct {
ServerV40
ASNs []int64 `json:"asns"`
Comment thread
srijeet0406 marked this conversation as resolved.
Outdated
}

// ServerV40 is the representation of a Server in version 4.0 of the Traffic Ops API.
type ServerV40 struct {
Cachegroup *string `json:"cachegroup" db:"cachegroup"`
Expand Down Expand Up @@ -1066,7 +1072,7 @@ type ServerV40 struct {

// ServerV4 is the representation of a Server in the latest minor version of
// version 4 of the Traffic Ops API.
type ServerV4 = ServerV40
type ServerV4 = ServerV41

// ServerV30 is the representation of a Server in version 3 of the Traffic Ops API.
type ServerV30 struct {
Expand Down
2 changes: 1 addition & 1 deletion traffic_monitor/towrap/towrap.go
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ func (s TrafficOpsSessionThreadsafe) fetchServerByHostname(hostName string) (tc.
for i, srv := range resp.Response {
num = i
if srv.CDNName != nil && srv.HostName != nil && *srv.HostName == hostName {
server = srv
server = srv.ServerV40
found = true
break
}
Expand Down
65 changes: 53 additions & 12 deletions traffic_ops/testing/api/v4/servers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,24 @@ import (
)

func TestServers(t *testing.T) {
WithObjs(t, []TCObj{CDNs, Types, Tenants, Users, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, Topologies, ServiceCategories, DeliveryServices, DeliveryServiceServerAssignments}, func() {
WithObjs(t, []TCObj{CDNs, Types, Tenants, Users, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, Topologies, ServiceCategories, DeliveryServices, DeliveryServiceServerAssignments, ASN}, func() {

currentTime := time.Now().UTC().Add(-15 * time.Second)
currentTimeRFC := currentTime.Format(time.RFC1123)
tomorrow := currentTime.AddDate(0, 0, 1).Format(time.RFC1123)

setupCacheGroupWithASN(t)
methodTests := utils.V4TestCase{
"GET": {
"NOT MODIFIED when NO CHANGES made": {
ClientSession: TOSession,
RequestOpts: client.RequestOptions{Header: http.Header{rfc.IfModifiedSince: {tomorrow}}},
Expectations: utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusNotModified)),
},
"OK when CORRECT ASN parameter": {
ClientSession: TOSession,
RequestOpts: client.RequestOptions{QueryParameters: url.Values{"asn": {"1111"}}},
Expectations: utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK), utils.ResponseLengthGreaterOrEqual(1)),
},
"OK when VALID HOSTNAME parameter": {
ClientSession: TOSession,
RequestOpts: client.RequestOptions{QueryParameters: url.Values{"hostName": {"atlanta-edge-01"}}},
Expand All @@ -58,6 +63,17 @@ func TestServers(t *testing.T) {
Expectations: utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK), utils.ResponseLengthGreaterOrEqual(1),
validateServerFields(map[string]interface{}{"CachegroupID": GetCacheGroupId(t, "cachegroup1")()})),
},
"OK when VALID ASN parameter": {
ClientSession: TOSession,
RequestOpts: client.RequestOptions{QueryParameters: url.Values{"asn": {"1111"}}},
Expectations: utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK), utils.ResponseLengthGreaterOrEqual(1),
validateServerFields(map[string]interface{}{"Cachegroup": "topology-mid-cg-01"})),
},
"EMPTY RESPONSE when INVALID ASN parameter": {
ClientSession: TOSession,
RequestOpts: client.RequestOptions{QueryParameters: url.Values{"asn": {"5555"}}},
Expectations: utils.CkRequest(utils.NoError(), utils.HasStatus(http.StatusOK), utils.ResponseHasLength(0)),
},
"OK when VALID CACHEGROUPNAME parameter": {
ClientSession: TOSession,
RequestOpts: client.RequestOptions{QueryParameters: url.Values{"cachegroupName": {"topology-mid-cg-01"}}},
Expand Down Expand Up @@ -384,10 +400,35 @@ func TestServers(t *testing.T) {
})
}

func setupCacheGroupWithASN(t *testing.T) {
// Add a new asn for one of the cachegroups
cgResp, _, err := TOSession.GetCacheGroups(client.RequestOptions{QueryParameters: url.Values{"name": {"topology-mid-cg-01"}}})
if err != nil {
t.Fatalf("couldn't get cachegroups: %v", err)
}
if len(cgResp.Response) != 1 {
t.Fatalf("expected 1 cachegroup, but got %d", len(cgResp.Response))
}
if cgResp.Response[0].ID == nil {
t.Fatalf("ID of cachegroup is nil")
}

asn := tc.ASN{
ASN: 1111,
Cachegroup: "topology-mid-cg-01",
CachegroupID: *cgResp.Response[0].ID,
}

_, _, err = TOSession.CreateASN(asn, client.NewRequestOptions())
if err != nil {
t.Fatalf("couldn't create ASN: %v", err)
}
}

Comment thread
srijeet0406 marked this conversation as resolved.
Outdated
func validateServerFields(expectedResp map[string]interface{}) utils.CkReqFunc {
return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, _ tc.Alerts, _ error) {
assert.RequireNotNil(t, resp, "Expected response to not be nil.")
serverResp := resp.([]tc.ServerV40)
serverResp := resp.([]tc.ServerV41)
for field, expected := range expectedResp {
for _, server := range serverResp {
switch field {
Expand Down Expand Up @@ -460,7 +501,7 @@ func validateServerFieldsForUpdate(hostname string, expectedResp map[string]inte
func validateExpectedServers(expectedHostnames []string) utils.CkReqFunc {
return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, _ tc.Alerts, _ error) {
assert.RequireNotNil(t, resp, "Expected response to not be nil.")
serverResp := resp.([]tc.ServerV40)
serverResp := resp.([]tc.ServerV41)
var notInResponse []string
serverMap := make(map[string]struct{})
for _, server := range serverResp {
Expand All @@ -479,7 +520,7 @@ func validateExpectedServers(expectedHostnames []string) utils.CkReqFunc {
func validateServerTypeIsNotMid() utils.CkReqFunc {
return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, _ tc.Alerts, _ error) {
assert.RequireNotNil(t, resp, "Expected response to not be nil.")
serverResp := resp.([]tc.ServerV40)
serverResp := resp.([]tc.ServerV41)
for _, server := range serverResp {
assert.RequireNotNil(t, server.HostName, "Expected server host name to not be nil.")
assert.NotEqual(t, server.Type, tc.CacheTypeMid.String(), "Expected to find no %s-typed servers but found server %s", tc.CacheTypeMid, *server.HostName)
Expand All @@ -490,7 +531,7 @@ func validateServerTypeIsNotMid() utils.CkReqFunc {
func validateServerPagination(paginationParam string) utils.CkReqFunc {
return func(t *testing.T, _ toclientlib.ReqInf, resp interface{}, _ tc.Alerts, _ error) {
assert.RequireNotNil(t, resp, "Expected response to not be nil.")
paginationResp := resp.([]tc.ServerV40)
paginationResp := resp.([]tc.ServerV41)
opts := client.NewRequestOptions()
opts.QueryParameters.Set("orderby", "id")
respBase, _, err := TOSession.GetServers(opts)
Expand Down Expand Up @@ -556,16 +597,16 @@ func UpdateTestServerStatusLastUpdated(t *testing.T) {
assert.RequireNoError(t, err, "Cannot get Server by hostname '%s': %v - alerts %+v", hostName, err, resp.Alerts)
assert.RequireGreaterOrEqual(t, len(resp.Response), 1, "Expected at least one server to exist by hostname '%s'", hostName)
assert.RequireNotNil(t, resp.Response[0].StatusLastUpdated, "Traffic Ops returned a representation for a server with null or undefined Status Last Updated time")
originalServer := resp.Response[0]
originalServer := resp.Response[0].ServerV40

// Perform an update with no changes to status
alerts, _, err := TOSession.UpdateServer(*originalServer.ID, originalServer, client.RequestOptions{})
alerts, _, err := TOSession.UpdateServer(*originalServer.ID, tc.ServerV4{ServerV40: originalServer}, client.RequestOptions{})
assert.RequireNoError(t, err, "Cannot UPDATE Server by ID %d (hostname '%s'): %v - alerts: %+v", *originalServer.ID, hostName, err, alerts)

resp, _, err = TOSession.GetServers(opts)
assert.RequireNoError(t, err, "Cannot get Server by hostname '%s': %v - alerts %+v", hostName, err, resp.Alerts)
assert.RequireGreaterOrEqual(t, len(resp.Response), 1, "Expected at least one server to exist by hostname '%s'", hostName)
respServer := resp.Response[0]
respServer := resp.Response[0].ServerV40
assert.RequireNotNil(t, respServer.StatusLastUpdated, "Traffic Ops returned a representation for a server with null or undefined Status Last Updated time")
assert.Equal(t, *originalServer.StatusLastUpdated, *respServer.StatusLastUpdated, "Since status didnt change, no change in 'StatusLastUpdated' time was expected. "+
"old value: %v, new value: %v", *originalServer.StatusLastUpdated, *respServer.StatusLastUpdated)
Expand All @@ -574,13 +615,13 @@ func UpdateTestServerStatusLastUpdated(t *testing.T) {
newStatusID := GetStatusID(t, "ONLINE")()
originalServer.StatusID = &newStatusID

alerts, _, err = TOSession.UpdateServer(*originalServer.ID, originalServer, client.RequestOptions{})
alerts, _, err = TOSession.UpdateServer(*originalServer.ID, tc.ServerV4{ServerV40: originalServer}, client.RequestOptions{})
assert.RequireNoError(t, err, "Cannot UPDATE Server by ID %d (hostname '%s'): %v - alerts: %+v", *originalServer.ID, hostName, err, alerts)

resp, _, err = TOSession.GetServers(opts)
assert.RequireNoError(t, err, "Cannot get Server by hostname '%s': %v - alerts %+v", hostName, err, resp.Alerts)
assert.RequireGreaterOrEqual(t, len(resp.Response), 1, "Expected at least one server to exist by hostname '%s'", hostName)
respServer = resp.Response[0]
respServer = resp.Response[0].ServerV40
assert.RequireNotNil(t, respServer.StatusLastUpdated, "Traffic Ops returned a representation for a server with null or undefined Status Last Updated time")
assert.NotEqual(t, *originalServer.StatusLastUpdated, *respServer.StatusLastUpdated, "Since status changed, expected 'StatusLastUpdated' to change. "+
"old value: %v, new value: %v", *originalServer.StatusLastUpdated, *respServer.StatusLastUpdated)
Expand Down Expand Up @@ -628,7 +669,7 @@ func UpdateDSGetServerDSID(t *testing.T) {

func CreateTestServers(t *testing.T) {
for _, server := range testData.Servers {
resp, _, err := TOSession.CreateServer(server, client.RequestOptions{})
resp, _, err := TOSession.CreateServer(tc.ServerV4{ServerV40: server}, client.RequestOptions{})
assert.RequireNoError(t, err, "Could not create server '%s': %v - alerts: %+v", *server.HostName, err, resp.Alerts)
}
}
Expand Down
10 changes: 5 additions & 5 deletions traffic_ops/testing/api/v4/serverupdatestatus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,19 +103,19 @@ func TestServerUpdateStatus(t *testing.T) {
}{
{
"atlanta-edge-01",
&edge1cdn1,
&edge1cdn1.ServerV40,
},
{
"atlanta-edge-03",
&edge2cdn1,
&edge2cdn1.ServerV40,
},
{
"atlanta-mid-16",
&mid1cdn1,
&mid1cdn1.ServerV40,
},
{
"edge1-cdn2",
&edge1cdn2,
&edge1cdn2.ServerV40,
},
} {
opts.QueryParameters.Set("hostName", s.name)
Expand All @@ -130,7 +130,7 @@ func TestServerUpdateStatus(t *testing.T) {
t.Errorf("Expected exactly one server named '%s' to exist - actual: %d", s.name, len(resp.Response))
t.Logf("Testing will proceed with server: %+v", resp.Response[0])
}
*s.server = resp.Response[0]
*s.server = resp.Response[0].ServerV40
if s.server.ID == nil {
t.Fatalf("server '%s' was returned with nil ID", s.name)
}
Expand Down
2 changes: 1 addition & 1 deletion traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2024,7 +2024,7 @@ WHERE server.id = $2;`
}

// GetCommonServerPropertiesFromV4 converts ServerV40 to CommonServerProperties struct.
func GetCommonServerPropertiesFromV4(s tc.ServerV40, tx *sql.Tx) (tc.CommonServerProperties, error) {
func GetCommonServerPropertiesFromV4(s tc.ServerV41, tx *sql.Tx) (tc.CommonServerProperties, error) {
var id int
var desc string
if len(s.ProfileNames) == 0 {
Expand Down
2 changes: 2 additions & 0 deletions traffic_ops/traffic_ops_golang/routing/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,8 @@ func Routes(d ServerData) ([]Route, http.Handler, error) {
* 4.x API
*/

// GET servers
{Version: api.Version{Major: 4, Minor: 1}, Method: http.MethodGet, Path: `servers/?$`, Handler: server.Read, RequiredPrivLevel: auth.PrivLevelReadOnly, RequiredPermissions: []string{"SERVER:READ", "DELIVERY-SERVICE:READ", "CDN:READ", "PHYSICAL-LOCATION:READ", "CACHE-GROUP:READ", "TYPE:READ", "PROFILE:READ"}, Authenticated: Authenticated, Middlewares: nil, ID: 47219592853},
// Assign Multiple Server Capabilities
{Version: api.Version{Major: 4, Minor: 1}, Method: http.MethodPut, Path: `multiple_server_capabilities/?$`, Handler: server.AssignMultipleServerCapabilities, RequiredPrivLevel: auth.PrivLevelOperations, RequiredPermissions: []string{"SERVER:UPDATE", "SERVER:READ", "SERVER-CAPABILITY:READ"}, Authenticated: Authenticated, Middlewares: nil, ID: 40792419258},

Expand Down
Loading