diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b9a51e542..98bc05abcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ## [unreleased] ### Added +- Traffic Ops: [#3577](https://github.com/apache/trafficcontrol/issues/3577) - Added a query param (server host_name or ID) for servercheck API - Traffic Portal: [#5318](https://github.com/apache/trafficcontrol/issues/5318) - Rename server columns for IPv4 address fields. - Traffic Portal: [#5361](https://github.com/apache/trafficcontrol/issues/5361) - Added the ability to change the name of a topology. - Traffic Portal: [#5340](https://github.com/apache/trafficcontrol/issues/5340) - Added the ability to resend a user registration from user screen. diff --git a/docs/source/api/v3/servercheck.rst b/docs/source/api/v3/servercheck.rst index dc4b7ef97f..5aa18573d2 100644 --- a/docs/source/api/v3/servercheck.rst +++ b/docs/source/api/v3/servercheck.rst @@ -31,7 +31,33 @@ Fetches identifying and meta information as well as "check" values regarding all Request Structure ----------------- -No parameters available. +.. table:: Request Query Parameters + + +-----------+------------------------------------------------------------------------------------+ + | Name | Description | + +===========+====================================================================================+ + | id | Return only :term:`cache servers` with this integral, unique identifier (id) | + +-----------+------------------------------------------------------------------------------------+ + | name | Return only :term:`cache servers` with this host_name | + +-----------+------------------------------------------------------------------------------------+ + +.. code-block:: http + :caption: Request Example with ``name`` query param + + GET /api/4.0/servercheck?name=edge HTTP/1.1 + Host: trafficops.infra.ciab.test + User-Agent: curl/7.47.0 + Accept: */* + Cookie: mojolicious=... + +.. code-block:: http + :caption: Request Example with ``id`` query param + + GET /api/4.0/servercheck?id=12 HTTP/1.1 + Host: trafficops.infra.ciab.test + User-Agent: curl/7.47.0 + Accept: */* + Cookie: mojolicious=... Response Structure ------------------ @@ -55,9 +81,9 @@ Response Structure Access-Control-Allow-Origin: * Content-Encoding: gzip Content-Type: application/json - Set-Cookie: mojolicious=...; Path=/; Expires=Thu, 23 Jan 2020 20:00:19 GMT; Max-Age=3600; HttpOnly + Set-Cookie: mojolicious=...; Path=/; Expires=Thu, 18 Feb 2021 20:00:19 GMT; Max-Age=3600; HttpOnly X-Server-Name: traffic_ops_golang/ - Date: Thu, 23 Jan 2020 19:00:19 GMT + Date: Thu, 18 Feb 2021 19:00:19 GMT Content-Length: 352 { "response": [ @@ -70,16 +96,6 @@ Response Structure "profile": "ATS_EDGE_TIER_CACHE", "type": "EDGE", "updPending": false - }, - { - "adminState": "REPORTED", - "cacheGroup": "CDN_in_a_Box_Mid", - "id": 11, - "hostName": "mid", - "revalPending": false, - "profile": "ATS_MID_TIER_CACHE", - "type": "MID", - "updPending": false } ]} diff --git a/docs/source/api/v4/servercheck.rst b/docs/source/api/v4/servercheck.rst index 77c8a813c4..8fdab46c37 100644 --- a/docs/source/api/v4/servercheck.rst +++ b/docs/source/api/v4/servercheck.rst @@ -31,7 +31,33 @@ Fetches identifying and meta information as well as "check" values regarding all Request Structure ----------------- -No parameters available. +.. table:: Request Query Parameters + + +-----------+------------------------------------------------------------------------------------+ + | Name | Description | + +===========+====================================================================================+ + | id | Return only :term:`cache servers` with this integral, unique identifier (id) | + +-----------+------------------------------------------------------------------------------------+ + | name | Return only :term:`cache servers` with this host_name | + +-----------+------------------------------------------------------------------------------------+ + +.. code-block:: http + :caption: Request Example with ``name`` query param + + GET /api/4.0/servercheck?name=edge HTTP/1.1 + Host: trafficops.infra.ciab.test + User-Agent: curl/7.47.0 + Accept: */* + Cookie: mojolicious=... + +.. code-block:: http + :caption: Request Example with ``id`` query param + + GET /api/4.0/servercheck?id=12 HTTP/1.1 + Host: trafficops.infra.ciab.test + User-Agent: curl/7.47.0 + Accept: */* + Cookie: mojolicious=... Response Structure ------------------ @@ -55,9 +81,9 @@ Response Structure Access-Control-Allow-Origin: * Content-Encoding: gzip Content-Type: application/json - Set-Cookie: mojolicious=...; Path=/; Expires=Thu, 23 Jan 2020 20:00:19 GMT; Max-Age=3600; HttpOnly + Set-Cookie: mojolicious=...; Path=/; Expires=Thu, 18 Feb 2021 20:00:19 GMT; Max-Age=3600; HttpOnly X-Server-Name: traffic_ops_golang/ - Date: Thu, 23 Jan 2020 19:00:19 GMT + Date: Thu, 18 Feb 2021 19:00:19 GMT Content-Length: 352 { "response": [ @@ -70,16 +96,6 @@ Response Structure "profile": "ATS_EDGE_TIER_CACHE", "type": "EDGE", "updPending": false - }, - { - "adminState": "REPORTED", - "cacheGroup": "CDN_in_a_Box_Mid", - "id": 11, - "hostName": "mid", - "revalPending": false, - "profile": "ATS_MID_TIER_CACHE", - "type": "MID", - "updPending": false } ]} diff --git a/traffic_ops/testing/api/v4/serverchecks_test.go b/traffic_ops/testing/api/v4/serverchecks_test.go index de9783560a..f782e4f2b3 100644 --- a/traffic_ops/testing/api/v4/serverchecks_test.go +++ b/traffic_ops/testing/api/v4/serverchecks_test.go @@ -16,6 +16,8 @@ package v4 */ import ( + "net/url" + "strconv" "testing" "time" @@ -28,6 +30,8 @@ func TestServerChecks(t *testing.T) { CreateTestInvalidServerChecks(t) UpdateTestServerChecks(t) GetTestServerChecks(t) + GetTestServerChecksWithName(t) + GetTestServerChecksWithID(t) }) } @@ -101,7 +105,7 @@ func UpdateTestServerChecks(t *testing.T) { func GetTestServerChecks(t *testing.T) { hostname := testData.Serverchecks[0].HostName // Get server checks - serverChecksResp, alerts, _, err := TOSession.GetServersChecks() + serverChecksResp, alerts, _, err := TOSession.GetServersChecks(nil, nil) if err != nil { t.Fatalf("could not GET serverchecks: %v (alerts: %+v)", err, alerts) } @@ -138,6 +142,42 @@ func GetTestServerChecks(t *testing.T) { } } +func GetTestServerChecksWithName(t *testing.T) { + params := url.Values{} + params.Set("name", "atlanta-edge-01") + + // Get server checks + scResp, alerts, _, err := TOSession.GetServersChecks(params, nil) + if len(scResp) == 0 { + t.Fatal("no server checks in response, quitting") + } + if err != nil { + t.Fatalf("could not GET serverchecks by name (%v): %v (alerts: %+v)", scResp[0].HostName, err, alerts) + } +} + +func GetTestServerChecksWithID(t *testing.T) { + params := url.Values{} + serverChecksResp, _, _, err := TOSession.GetServersChecks(nil, nil) + if len(serverChecksResp) == 0 { + t.Fatal("no server checks in response, quitting") + } + if serverChecksResp[0].ID == 0 { + t.Fatal("ID of the response server is nil, quitting") + } + id := serverChecksResp[0].ID + params.Set("id", strconv.Itoa(id)) + + // Get server checks + scResp, alerts, _, err := TOSession.GetServersChecks(params, nil) + if len(scResp) == 0 { + t.Fatal("no server checks in response, quitting") + } + if err != nil { + t.Fatalf("could not GET serverchecks by id (%v): %v (alerts: %+v)", scResp[0].ID, err, alerts) + } +} + // Need to define no-op function as TCObj interface expects a delete function // There is no delete path for serverchecks func DeleteTestServerChecks(t *testing.T) { diff --git a/traffic_ops/traffic_ops_golang/servercheck/servercheck.go b/traffic_ops/traffic_ops_golang/servercheck/servercheck.go index 84449b965e..385c9c38fd 100644 --- a/traffic_ops/traffic_ops_golang/servercheck/servercheck.go +++ b/traffic_ops/traffic_ops_golang/servercheck/servercheck.go @@ -50,8 +50,6 @@ LEFT JOIN profile ON server.profile = profile.id LEFT JOIN status ON server.status = status.id LEFT JOIN cachegroup ON server.cachegroup = cachegroup.id LEFT JOIN type ON server.type = type.id -WHERE type.name LIKE 'MID%' OR type.name LIKE 'EDGE%' -ORDER BY hostName ASC ` const serverChecksQuery = ` @@ -239,6 +237,45 @@ func DeprecatedReadServersChecks(w http.ResponseWriter, r *http.Request) { func handleReadServerCheck(inf *api.APIInfo, tx *sql.Tx) ([]tc.GenericServerCheck, error, error, int) { extensions := make(map[string]string) + + // Query Parameters to Database Query column mappings + queryParamsToQueryCols := map[string]dbhelpers.WhereColumnInfo{ + "id": dbhelpers.WhereColumnInfo{"servercheck.server", api.IsInt}, + "name": dbhelpers.WhereColumnInfo{"server.host_name", nil}, + } + + where, orderBy, pagination, queryValues, errs := dbhelpers.BuildWhereAndOrderByAndPagination(inf.Params, queryParamsToQueryCols) + if len(errs) > 0 { + return nil, util.JoinErrs(errs), nil, http.StatusBadRequest + } + // where clause is different for servercheck and server table. Also, it differs for the query param. + var whereSC, whereSI string + if len(inf.Params) < 1 { + whereSI = "WHERE type.name LIKE 'MID%' OR type.name LIKE 'EDGE%' " + whereSC = "" + } else if len(inf.Params) == 1 { + if _, ok := inf.Params["name"]; ok { + whereSI = "WHERE (type.name LIKE 'MID%' OR type.name LIKE 'EDGE%') AND server.host_name=:name " + whereSC = "" + } else if _, ok = inf.Params["id"]; ok { + whereSI = "WHERE (type.name LIKE 'MID%' OR type.name LIKE 'EDGE%') AND server.id=:id " + whereSC = where + } else { + whereSI = "WHERE type.name LIKE 'MID%' OR type.name LIKE 'EDGE%' " + whereSC = "" + } + } else if len(inf.Params) > 1 { + _, ok := inf.Params["id"] + _, ok1 := inf.Params["name"] + if ok && ok1 { + whereSI = "WHERE (type.name LIKE 'MID%' OR type.name LIKE 'EDGE%') AND (server.host_name=:name AND server.id=:id)" + whereSC = "WHERE servercheck.server=:id" + } else { + whereSI = "WHERE type.name LIKE 'MID%' OR type.name LIKE 'EDGE%' " + whereSC = "" + } + } + extRows, err := tx.Query(extensionsQuery) if err != nil { sysErr := fmt.Errorf("querying for extensions: %v", err) @@ -254,9 +291,10 @@ func handleReadServerCheck(inf *api.APIInfo, tx *sql.Tx) ([]tc.GenericServerChec extensions[shortName] = checkName } - colRows, err := inf.Tx.Queryx(serverChecksQuery) + querySC := serverChecksQuery + whereSC + orderBy + pagination + colRows, err := inf.Tx.NamedQuery(querySC, queryValues) if err != nil { - sysErr := fmt.Errorf("Querying server checks columns: %v", err) + sysErr := fmt.Errorf("querying serverchecks columns: %v", err) return nil, nil, sysErr, http.StatusInternalServerError } @@ -267,13 +305,14 @@ func handleReadServerCheck(inf *api.APIInfo, tx *sql.Tx) ([]tc.GenericServerChec sysErr := fmt.Errorf("scanning server checks columns: %v", err) return nil, nil, sysErr, http.StatusInternalServerError } - columns[cols.Server] = cols } - serverRows, err := tx.Query(serverInfoQuery) + orderBySI := orderBy + "ORDER BY hostName ASC" + querySI := serverInfoQuery + whereSI + orderBySI + pagination + serverRows, err := inf.Tx.NamedQuery(querySI, queryValues) if err != nil { - sysErr := fmt.Errorf("Querying server info for checks: %v", err) + sysErr := fmt.Errorf("querying server info for checks: %v", err) return nil, nil, sysErr, http.StatusInternalServerError } diff --git a/traffic_ops/v4-client/servercheck.go b/traffic_ops/v4-client/servercheck.go index 718d51a106..ac48acfe57 100644 --- a/traffic_ops/v4-client/servercheck.go +++ b/traffic_ops/v4-client/servercheck.go @@ -16,6 +16,9 @@ package client import ( + "net/http" + "net/url" + "github.com/apache/trafficcontrol/lib/go-tc" "github.com/apache/trafficcontrol/traffic_ops/toclientlib" ) @@ -34,11 +37,21 @@ func (to *Session) InsertServerCheckStatus(status tc.ServercheckRequestNullable) } // GetServersChecks fetches check and meta information about servers from /servercheck. -func (to *Session) GetServersChecks() ([]tc.GenericServerCheck, tc.Alerts, toclientlib.ReqInf, error) { - var response struct { +func (to *Session) GetServersChecks(params url.Values, header http.Header) ([]tc.GenericServerCheck, tc.Alerts, toclientlib.ReqInf, error) { + data := struct { tc.Alerts Response []tc.GenericServerCheck `json:"response"` + }{} + route := APIServercheck + if params != nil { + route += "?" + params.Encode() + } + reqInf, err := to.get(route, header, &data) + if err != nil { + return nil, data.Alerts, reqInf, err + } + if len(data.Response) == 0 { + return nil, data.Alerts, reqInf, nil } - reqInf, err := to.get(APIServercheck, nil, &response) - return response.Response, response.Alerts, reqInf, err + return data.Response, data.Alerts, reqInf, nil }