From 6a3a90cafc78d59c587c7ae893f62aeaf6180150 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 7 May 2020 18:39:27 -0600 Subject: [PATCH 01/87] Reworked GET /servers for new interfaces table --- lib/go-tc/servers.go | 80 +++++++++-- traffic_ops/traffic_ops_golang/api/api.go | 27 +++- .../traffic_ops_golang/routing/routes.go | 8 +- .../traffic_ops_golang/server/servers.go | 130 +++++++++++++----- 4 files changed, 195 insertions(+), 50 deletions(-) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index 9d8398eab8..af4ad56f0a 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -256,7 +256,9 @@ type ServerV1 struct { XMPPPasswd string `json:"xmppPasswd" db:"xmpp_passwd"` } -type ServerNullableV11 struct { +// CommonServerProperties is just the collection of properties which are +// shared by all servers across API versions. +type CommonServerProperties struct { Cachegroup *string `json:"cachegroup" db:"cachegroup"` CachegroupID *int `json:"cachegroupId" db:"cachegroup_id"` CDNID *int `json:"cdnId" db:"cdn_id"` @@ -274,13 +276,6 @@ type ServerNullableV11 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"` @@ -305,12 +300,79 @@ type ServerNullableV11 struct { XMPPPasswd *string `json:"xmppPasswd" db:"xmpp_passwd"` } -type ServerNullable struct { +// ServerNullableV11 is a server as it appeared in API version 1.1. +type ServerNullableV11 struct { + LegacyInterfaceDetails + CommonServerProperties +} + +// ServerNullableV2 is a server as it appeared in API v2. +type ServerNullableV2 struct { ServerNullableV11 IPIsService *bool `json:"ipIsService" db:"ip_address_is_service"` IP6IsService *bool `json:"ip6IsService" db:"ip6_address_is_service"` } +// ServerNullable represents an ATC server, as returned by the TO API. +type ServerNullable struct { + CommonServerProperties + Interfaces []ServerInterfaceInfo `json:"interfaces"` +} + +// ToServerV2 converts the server to an equivalent ServerNullableV2 structure, +// if possible. If the conversion could not be performed, an error is returned. +func (s *ServerNullable) ToServerV2() (ServerNullableV2, error) { + legacyServer := ServerNullableV2{ + ServerNullableV11: ServerNullableV11{ + CommonServerProperties: CommonServerProperties{ + Cachegroup: s.Cachegroup, + CachegroupID: s.CachegroupID, + CDNID: s.CDNID, + CDNName: s.CDNName, + DeliveryServices: s.DeliveryServices, + DomainName: s.DomainName, + FQDN: s.FQDN, + FqdnTime: s.FqdnTime, + GUID: s.GUID, + HostName: s.HostName, + HTTPSPort: s.HTTPSPort, + ID: s.ID, + ILOIPAddress: s.ILOIPAddress, + ILOIPGateway: s.ILOIPGateway, + ILOIPNetmask: s.ILOIPNetmask, + ILOPassword: s.ILOPassword, + ILOUsername: s.ILOUsername, + LastUpdated: s.LastUpdated, + MgmtIPAddress: s.MgmtIPAddress, + MgmtIPGateway: s.MgmtIPGateway, + MgmtIPNetmask: s.MgmtIPNetmask, + OfflineReason: s.OfflineReason, + PhysLocation: s.PhysLocation, + PhysLocationID: s.PhysLocationID, + Profile: s.Profile, + ProfileDesc: s.ProfileDesc, + ProfileID: s.ProfileID, + Rack: s.Rack, + RevalPending: s.RevalPending, + RouterHostName: s.RouterHostName, + RouterPortName: s.RouterPortName, + Status: s.Status, + StatusID: s.StatusID, + TCPPort: s.TCPPort, + Type: s.Type, + TypeID: s.TypeID, + UpdPending: s.UpdPending, + XMPPID: s.XMPPID, + XMPPPasswd: s.XMPPPasswd, + }, + }, + } + + var err error + legacyServer.LegacyInterfaceDetails, err = InterfaceInfoToLegacyInterfaces(s.Interfaces) + return legacyServer, err +} + type ServerUpdateStatus struct { HostName string `json:"host_name"` UpdatePending bool `json:"upd_pending"` diff --git a/traffic_ops/traffic_ops_golang/api/api.go b/traffic_ops/traffic_ops_golang/api/api.go index af138f13e7..23a525c86e 100644 --- a/traffic_ops/traffic_ops_golang/api/api.go +++ b/traffic_ops/traffic_ops_golang/api/api.go @@ -70,16 +70,25 @@ WHERE type in ( SELECT id ) AND status=(SELECT id FROM status WHERE name='ONLINE') ` +type APIResponse struct { + Response interface{} `json:"response"` +} + +type APIResponseWithSummary struct { + Response interface{} `json:"response"` + Summary struct { + Count uint64 `json:"count"` + } `json:"summary"` +} // WriteResp takes any object, serializes it as JSON, and writes that to w. Any errors are logged and written to w via tc.GetHandleErrorsFunc. // This is a helper for the common case; not using this in unusual cases is perfectly acceptable. func WriteResp(w http.ResponseWriter, r *http.Request, v interface{}) { - resp := struct { - Response interface{} `json:"response"` - }{v} + resp := APIResponse{v} WriteRespRaw(w, r, resp) } + // WriteRespRaw acts like WriteResp, but doesn't wrap the object in a `{"response":` object. This should be used to respond with endpoints which don't wrap their response in a "response" object. func WriteRespRaw(w http.ResponseWriter, r *http.Request, v interface{}) { if respWritten(r) { @@ -98,6 +107,18 @@ func WriteRespRaw(w http.ResponseWriter, r *http.Request, v interface{}) { w.Write(append(bts, '\n')) } +// WriteRespWithSummary writes a JSON-encoded representation of an arbitrary +// object to the provided writer, and cleans up the corresponding request +// object. It also provides a "summary" section to the response object that +// contains the given "count". +func WriteRespWithSummary(w http.ResponseWriter, r *http.Request, v interface{}, count uint64) { + var resp APIResponseWithSummary + resp.Response = v + resp.Summary.Count = count + + WriteRespRaw(w, r, resp) +} + // WriteRespVals is like WriteResp, but also takes a map of root-level values to write. The API most commonly needs these for meta-parameters, like size, limit, and orderby. // This is a helper for the common case; not using this in unusual cases is perfectly acceptable. func WriteRespVals(w http.ResponseWriter, r *http.Request, v interface{}, vals map[string]interface{}) { diff --git a/traffic_ops/traffic_ops_golang/routing/routes.go b/traffic_ops/traffic_ops_golang/routing/routes.go index 1763f719df..414882efac 100644 --- a/traffic_ops/traffic_ops_golang/routing/routes.go +++ b/traffic_ops/traffic_ops_golang/routing/routes.go @@ -319,7 +319,7 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) { {api.Version{3, 0}, http.MethodPost, `servers/{id-or-name}/update$`, server.UpdateHandler, auth.PrivLevelOperations, Authenticated, nil, 143813233, noPerlBypass}, //Server: CRUD - {api.Version{3, 0}, http.MethodGet, `servers/?$`, api.ReadHandler(&server.TOServer{}), auth.PrivLevelReadOnly, Authenticated, nil, 27209592853, noPerlBypass}, + {api.Version{3, 0}, http.MethodGet, `servers/?$`, server.Read, auth.PrivLevelReadOnly, Authenticated, nil, 27209592853, noPerlBypass}, {api.Version{3, 0}, http.MethodPut, `servers/{id}$`, api.UpdateHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 2586341033, noPerlBypass}, {api.Version{3, 0}, http.MethodPost, `servers/?$`, api.CreateHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 22255580613, noPerlBypass}, {api.Version{3, 0}, http.MethodDelete, `servers/{id}$`, api.DeleteHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 2923222333, noPerlBypass}, @@ -683,7 +683,7 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) { {api.Version{2, 0}, http.MethodPost, `servers/{id-or-name}/update$`, server.UpdateHandler, auth.PrivLevelOperations, Authenticated, nil, 14381323, noPerlBypass}, //Server: CRUD - {api.Version{2, 0}, http.MethodGet, `servers/?$`, api.ReadHandler(&server.TOServer{}), auth.PrivLevelReadOnly, Authenticated, nil, 2720959285, noPerlBypass}, + {api.Version{2, 0}, http.MethodGet, `servers/?$`, server.Read, auth.PrivLevelReadOnly, Authenticated, nil, 2720959285, noPerlBypass}, {api.Version{2, 0}, http.MethodPut, `servers/{id}$`, api.UpdateHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 258634103, noPerlBypass}, {api.Version{2, 0}, http.MethodPost, `servers/?$`, api.CreateHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 2225558061, noPerlBypass}, {api.Version{2, 0}, http.MethodDelete, `servers/{id}$`, api.DeleteHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 292322233, noPerlBypass}, @@ -1080,8 +1080,8 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) { {api.Version{1, 3}, http.MethodGet, `servers/{host_name}/update_status$`, server.GetServerUpdateStatusHandler, auth.PrivLevelReadOnly, Authenticated, nil, 438451599, noPerlBypass}, //Server: CRUD - {api.Version{1, 1}, http.MethodGet, `servers/?(\.json)?$`, api.ReadHandler(&server.TOServer{}), auth.PrivLevelReadOnly, Authenticated, nil, 1720959285, noPerlBypass}, - {api.Version{1, 1}, http.MethodGet, `servers/{id}$`, api.DeprecatedReadHandler(&server.TOServer{}, util.StrPtr("GET /servers with query parameter id")), auth.PrivLevelReadOnly, Authenticated, nil, 1543122028, noPerlBypass}, + {api.Version{1, 1}, http.MethodGet, `servers/?(\.json)?$`, server.Read, auth.PrivLevelReadOnly, Authenticated, nil, 1720959285, noPerlBypass}, + {api.Version{1, 1}, http.MethodGet, `servers/{id}$`, server.ReadID, auth.PrivLevelReadOnly, Authenticated, nil, 1543122028, noPerlBypass}, {api.Version{1, 1}, http.MethodPut, `servers/{id}$`, api.UpdateHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 958634103, noPerlBypass}, {api.Version{1, 1}, http.MethodPost, `servers/?$`, api.CreateHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 2025558061, noPerlBypass}, {api.Version{1, 1}, http.MethodDelete, `servers/{id}$`, api.DeleteHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 192322233, noPerlBypass}, diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 1ed79680d4..db45fc4c5c 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -37,6 +37,7 @@ import ( "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/auth" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/tenant" + "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/routing/middleware" validation "github.com/go-ozzo/ozzo-validation" "github.com/go-ozzo/ozzo-validation/is" "github.com/jmoiron/sqlx" @@ -47,9 +48,14 @@ import ( // provides methods that implement several interfaces from the api package. type TOServer struct { api.APIInfoImpl `json:"-"` - tc.ServerNullable + tc.ServerNullableV2 } +const unfilteredServersQuery = ` +SELECT COUNT(server.id) +FROM server +` + func (s *TOServer) SetLastUpdated(t tc.TimeNoMod) { s.LastUpdated = &t } func (*TOServer) InsertQuery() string { return insertQuery() } func (*TOServer) UpdateQuery() string { return updateQuery() } @@ -197,36 +203,94 @@ func (s TOServer) ChangeLogMessage(action string) (string, error) { return message, nil } -func (s *TOServer) Read() ([]interface{}, error, error, int) { - version := s.APIInfo().Version - if version == nil { - return nil, nil, errors.New("TOServer.Read called with nil API version"), http.StatusInternalServerError +func Read(w http.ResponseWriter, r *http.Request) { + inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) + tx := inf.Tx.Tx + if userErr != nil || sysErr != nil { + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return } + defer inf.Close() - returnable := []interface{}{} + // Middleware should've already handled this, so idk why this is a pointer at all tbh + version := inf.Version + if version == nil { + middleware.NotImplementedHandler().ServeHTTP(w, r) + return + } - servers, userErr, sysErr, errCode := getServers(s.ReqInfo.Params, s.ReqInfo.Tx, s.ReqInfo.User) + var servers []tc.ServerNullable + var unfiltered uint64 + servers, unfiltered, userErr, sysErr, errCode = getServers(inf.Params, inf.Tx, inf.User) if userErr != nil || sysErr != nil { - return nil, userErr, sysErr, errCode + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return } + if version.Major >= 3 { + api.WriteRespWithSummary(w, r, servers, unfiltered) + return + } + + if version.Major <= 1 { + legacyServers := make([]tc.ServerNullableV2, len(servers)) + for _, server := range servers { + legacyServer, err := server.ToServerV2() + if err != nil { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Failed to convert servers to legacy format: %v", err)) + return + } + legacyServers = append(legacyServers, legacyServer) + } + api.WriteResp(w, r, legacyServers) + return + } + + legacyServers := make([]tc.ServerNullableV11, len(servers)) for _, server := range servers { - switch { - // NOTE: it's required to handle minor version cases in a descending >= manner - case version.Major >= 2: - returnable = append(returnable, server) - case version.Major == 1 && version.Minor >= 1: - returnable = append(returnable, server.ServerNullableV11) - default: - return nil, nil, fmt.Errorf("TOServer.Read called with invalid API version: %d.%d", version.Major, version.Minor), http.StatusInternalServerError + legacyServer, err := server.ToServerV2() + if err != nil { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Failed to convert servers to legacy format: %v", err)) + return } + legacyServers = append(legacyServers, legacyServer.ServerNullableV11) + } + api.WriteResp(w, r, legacyServers) +} + +func ReadID(w http.ResponseWriter, r *http.Request) { + alternative := "GET /servers with query parameter id" + inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) + tx := inf.Tx.Tx + if userErr != nil || sysErr != nil { + api.HandleDeprecatedErr(w, r, tx, errCode, userErr, sysErr, &alternative) + return } + defer inf.Close() + + var servers []tc.ServerNullable + servers, _, userErr, sysErr, errCode = getServers(inf.Params, inf.Tx, inf.User) - return returnable, nil, nil, http.StatusOK + legacyServers := make([]tc.ServerNullableV11, len(servers)) + for _, server := range servers { + legacyServer, err := server.ToServerV2() + if err != nil { + api.HandleDeprecatedErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Failed to convert servers to legacy format: %v", err), &alternative) + return + } + legacyServers = append(legacyServers, legacyServer.ServerNullableV11) + } + deprecationAlerts := api.CreateDeprecationAlerts(&alternative) + api.WriteAlertsObj(w, r, http.StatusOK, deprecationAlerts, legacyServers) } -func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ([]tc.ServerNullable, error, error, int) { +func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ([]tc.ServerNullable, uint64, error, error, int) { + var unfiltered uint64 + if err := tx.QueryRow(unfilteredServersQuery).Scan(&unfiltered); err != nil { + return nil, 0, nil, fmt.Errorf("Failed to get servers count: %v", err), http.StatusInternalServerError + } + // Query Parameters to Database Query column mappings // see the fields mapped in the SQL query queryParamsToSQLCols := map[string]dbhelpers.WhereColumnInfo{ @@ -248,23 +312,21 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( // don't allow query on ds outside user's tenant dsID, err := strconv.Atoi(dsIDStr) if err != nil { - return nil, errors.New("dsId must be an integer"), nil, http.StatusNotFound + return nil, unfiltered, errors.New("dsId must be an integer"), nil, http.StatusNotFound } userErr, sysErr, _ := tenant.CheckID(tx.Tx, user, dsID) if userErr != nil || sysErr != nil { - return nil, errors.New("Forbidden"), sysErr, http.StatusForbidden + return nil, unfiltered, errors.New("Forbidden"), sysErr, http.StatusForbidden } // only if dsId is part of params: add join on deliveryservice_server table - queryAddition = ` -FULL OUTER JOIN deliveryservice_server dss ON dss.server = s.id -` + queryAddition = "\nFULL OUTER JOIN deliveryservice_server dss ON dss.server = s.id\n" // depending on ds type, also need to add mids dsType, exists, err := dbhelpers.GetDeliveryServiceType(dsID, tx.Tx) if err != nil { - return nil, nil, err, http.StatusInternalServerError + return nil, unfiltered, nil, err, http.StatusInternalServerError } if !exists { - return nil, fmt.Errorf("a deliveryservice with id %v was not found", dsID), nil, http.StatusBadRequest + return nil, unfiltered, fmt.Errorf("a deliveryservice with id %v was not found", dsID), nil, http.StatusBadRequest } usesMids = dsType.UsesMidCache() log.Debugf("Servers for ds %d; uses mids? %v\n", dsID, usesMids) @@ -272,7 +334,7 @@ FULL OUTER JOIN deliveryservice_server dss ON dss.server = s.id where, orderBy, pagination, queryValues, errs := dbhelpers.BuildWhereAndOrderByAndPagination(params, queryParamsToSQLCols) if len(errs) > 0 { - return nil, util.JoinErrs(errs), nil, http.StatusBadRequest + return nil, unfiltered, util.JoinErrs(errs), nil, http.StatusBadRequest } query := selectQuery() + queryAddition + where + orderBy + pagination @@ -280,7 +342,7 @@ FULL OUTER JOIN deliveryservice_server dss ON dss.server = s.id rows, err := tx.NamedQuery(query, queryValues) if err != nil { - return nil, nil, errors.New("querying: " + err.Error()), http.StatusInternalServerError + return nil, unfiltered, nil, errors.New("querying: " + err.Error()), http.StatusInternalServerError } defer rows.Close() @@ -291,7 +353,7 @@ FULL OUTER JOIN deliveryservice_server dss ON dss.server = s.id for rows.Next() { var s tc.ServerNullable if err = rows.StructScan(&s); err != nil { - return nil, nil, errors.New("getting servers: " + err.Error()), http.StatusInternalServerError + return nil, unfiltered, nil, errors.New("getting servers: " + err.Error()), http.StatusInternalServerError } if user.PrivLevel < auth.PrivLevelOperations { s.ILOPassword = &HiddenField @@ -307,12 +369,12 @@ FULL OUTER JOIN deliveryservice_server dss ON dss.server = s.id log.Debugf("getting mids: %v, %v, %s\n", userErr, sysErr, http.StatusText(errCode)) if userErr != nil || sysErr != nil { - return nil, userErr, sysErr, errCode + return nil, unfiltered, userErr, sysErr, errCode } servers = append(servers, mids...) } - return servers, nil, nil, http.StatusOK + return servers, unfiltered, nil, nil, http.StatusOK } // getMidServers gets the mids used by the servers in this DS. @@ -439,10 +501,10 @@ func (s *TOServer) Create() (error, error, int) { func (s *TOServer) Delete() (error, error, int) { return api.GenericDelete(s) } func selectV20UpdatesQuery() string { - return `SELECT -sv.ip_address_is_service, -sv.ip6_address_is_service -FROM + return `SELECT +sv.ip_address_is_service, +sv.ip6_address_is_service +FROM server sv` } From 4669aea33f1328337c88442808cc3860e587ba62 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 7 May 2020 18:57:38 -0600 Subject: [PATCH 02/87] Updated query --- lib/go-tc/servers.go | 2 +- .../traffic_ops_golang/server/servers.go | 96 +++++++++---------- 2 files changed, 49 insertions(+), 49 deletions(-) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index af4ad56f0a..63277bced1 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -74,7 +74,7 @@ type ServersV3DetailResponse struct { type ServerIpAddress struct { Address string `json:"address" db:"address"` Gateway *string `json:"gateway" db:"gateway"` - ServiceAddress bool `json:"service_address" db:"service_address"` + ServiceAddress bool `json:"serviceAddress" db:"service_address"` } // ServerInterfaceInfo is the data associated with a server's interface. diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index db45fc4c5c..af9f1b6107 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -510,54 +510,54 @@ FROM func selectQuery() string { const JumboFrameBPS = 9000 - return `SELECT -cg.name as cachegroup, -s.cachegroup as cachegroup_id, -s.cdn_id, -cdn.name as cdn_name, -s.domain_name, -s.guid, -s.host_name, -s.https_port, -s.id, -s.ilo_ip_address, -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_address_is_service, -s.ip6_gateway, -s.ip_address, -s.ip_address_is_service, -s.ip_gateway, -s.ip_netmask, -s.last_updated, -s.mgmt_ip_address, -s.mgmt_ip_gateway, -s.mgmt_ip_netmask, -s.offline_reason, -pl.name as phys_location, -s.phys_location as phys_location_id, -p.name as profile, -p.description as profile_desc, -s.profile as profile_id, -s.rack, -s.reval_pending, -s.router_host_name, -s.router_port_name, -st.name as status, -s.status as status_id, -s.tcp_port, -t.name as server_type, -s.type as server_type_id, -s.upd_pending as upd_pending, -s.xmpp_id, -s.xmpp_passwd -FROM - server s + return ` +SELECT + cg.name AS cachegroup, + cdn.name AS cdn_name, + ARRAY(select deliveryservice from deliveryservice_server where server = s.id), + s.domain_name, + s.guid, + s.host_name, + s.https_port, + s.id, + s.ilo_ip_address, + s.ilo_ip_gateway, + s.ilo_ip_netmask, + s.ilo_password, + s.ilo_username, + ARRAY ( +SELECT ( json_build_object ( +'ipAddresses', ARRAY ( +SELECT ( json_build_object ( +'address', ip_address.address, +'gateway', ip_address.gateway, +'service_address', 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.offline_reason, + pl.name as phys_location, + p.name as profile, + p.description as profile_desc, + s.rack, + s.router_host_name, + s.router_port_name, + st.name as status, + s.tcp_port, + t.name as server_type, + s.xmpp_id, + s.xmpp_passwd +FROM server AS s JOIN cachegroup cg ON s.cachegroup = cg.id JOIN cdn cdn ON s.cdn_id = cdn.id JOIN phys_location pl ON s.phys_location = pl.id From 4e8029b277b5e09926d384b65c21a31497faa864 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 7 May 2020 19:05:25 -0600 Subject: [PATCH 03/87] Simplified V2 server conversion --- lib/go-tc/servers.go | 42 +----------------------------------------- 1 file changed, 1 insertion(+), 41 deletions(-) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index 63277bced1..bda36adb74 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -324,47 +324,7 @@ type ServerNullable struct { func (s *ServerNullable) ToServerV2() (ServerNullableV2, error) { legacyServer := ServerNullableV2{ ServerNullableV11: ServerNullableV11{ - CommonServerProperties: CommonServerProperties{ - Cachegroup: s.Cachegroup, - CachegroupID: s.CachegroupID, - CDNID: s.CDNID, - CDNName: s.CDNName, - DeliveryServices: s.DeliveryServices, - DomainName: s.DomainName, - FQDN: s.FQDN, - FqdnTime: s.FqdnTime, - GUID: s.GUID, - HostName: s.HostName, - HTTPSPort: s.HTTPSPort, - ID: s.ID, - ILOIPAddress: s.ILOIPAddress, - ILOIPGateway: s.ILOIPGateway, - ILOIPNetmask: s.ILOIPNetmask, - ILOPassword: s.ILOPassword, - ILOUsername: s.ILOUsername, - LastUpdated: s.LastUpdated, - MgmtIPAddress: s.MgmtIPAddress, - MgmtIPGateway: s.MgmtIPGateway, - MgmtIPNetmask: s.MgmtIPNetmask, - OfflineReason: s.OfflineReason, - PhysLocation: s.PhysLocation, - PhysLocationID: s.PhysLocationID, - Profile: s.Profile, - ProfileDesc: s.ProfileDesc, - ProfileID: s.ProfileID, - Rack: s.Rack, - RevalPending: s.RevalPending, - RouterHostName: s.RouterHostName, - RouterPortName: s.RouterPortName, - Status: s.Status, - StatusID: s.StatusID, - TCPPort: s.TCPPort, - Type: s.Type, - TypeID: s.TypeID, - UpdPending: s.UpdPending, - XMPPID: s.XMPPID, - XMPPPasswd: s.XMPPPasswd, - }, + CommonServerProperties: s.CommonServerProperties, }, } From 30110a5deff7c83e248c781616e9310ba7d31299 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 11 May 2020 11:28:36 -0600 Subject: [PATCH 04/87] Finally got GET working --- lib/go-tc/servers.go | 96 +- traffic_ops/app/conf/cdn.conf | 14 +- .../app/conf/development/database.conf | 2 +- .../traffic_ops_golang/routing/routes.go | 12 +- .../traffic_ops_golang/server/servers.go | 827 ++++++++++++------ 5 files changed, 658 insertions(+), 293 deletions(-) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index bda36adb74..ffddd4b7ad 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -1,13 +1,19 @@ package tc import ( + // "bytes" "database/sql/driver" "encoding/json" + // "errors" "fmt" "net" + // "strconv" "time" "github.com/apache/trafficcontrol/lib/go-util" + "github.com/apache/trafficcontrol/lib/go-log" + + // "github.com/lib/pq" ) /* @@ -86,7 +92,7 @@ type ServerInterfaceInfo struct { Name string `json:"name" db:"name"` } -// Value implements the database/sql/driver.Valuer interface. +// Value implements the driver.Valuer interface // marshals struct to json to pass back as a json.RawMessage func (sii *ServerInterfaceInfo) Value() (driver.Value, error) { b, err := json.Marshal(sii) @@ -101,9 +107,80 @@ func (sii *ServerInterfaceInfo) Scan(src interface{}) error { return fmt.Errorf("expected deliveryservice in byte array form; got %T", src) } + log.Debugf(string(b)) + return json.Unmarshal([]byte(b), sii) } +// Scan implements the sql.Scanner interface +// expects json.RawMessage and unmarshals to a deliveryservice struct +// func (sii *ServerInterfaceInfo) Scan(src interface{}) error { +// b, ok := src.([]byte) +// if !ok { +// return fmt.Errorf("expected deliveryservice in byte array form; got %T", src) +// } +// log.Debugf(string(b)) +// log.Debugf(fmt.Sprintf("%v", b)) + +// start := bytes.Index(b, []byte("\"")) +// if start < 0 { +// return errors.New("expected a '\"' to indicate beginning of array") +// } +// end := bytes.LastIndex(b, []byte("\"")) +// if end < 0 { +// return errors.New("expected a '\"' to indicate end of array") +// } +// if start >= end { +// return errors.New("expected a '\"' at the beginning and end of the array") +// } + +// log.Debugf("start=%d, end=%d", start, end) + +// var ips []ServerIpAddress +// if err := pq.Array(&ips).Scan(b[start+1:end]); err != nil { +// return fmt.Errorf("Scanning IP address array: %v", err) +// } + +// sii.IpAddresses = ips + +// rest := bytes.Split(b[end+1:], []byte(",")) +// if len(rest) != 4 { +// return fmt.Errorf("Expected 4 values to parse after ips, got %d (%v)", len(rest), rest) +// } + +// if len(rest[0]) == 0 { +// sii.MaxBandwidth = nil +// } else if mb, err := strconv.ParseInt(string(rest[0]), 10, 64); err != nil { +// return fmt.Errorf("Parsing max bandwidth: %v", err) +// } else { +// sii.MaxBandwidth = &mb +// } + +// if len(rest[1]) != 1 { +// return fmt.Errorf("Unknown boolean value encountered parsing 'monitor': %v", rest[1]) +// } +// if rest[1][0] == []byte("t")[0] { +// sii.Monitor = true +// } else if rest[1][0] == []byte("f")[0] { +// sii.Monitor = false +// } else { +// return fmt.Errorf("Unknown boolean value encountered parsing 'monitor': %v", rest[1]) +// } + +// if len(rest[2]) == 0 { +// sii.MTU = nil +// } else if mtu, err := strconv.ParseUint(string(rest[2]), 10, 64); err != nil { +// return fmt.Errorf("Parsing MTU: %v", err) +// } else { +// sii.MTU = &mtu +// } + +// sii.Name = string(bytes.TrimRight(rest[3], ")")) + +// // return json.Unmarshal([]byte(b), sii) +// return nil +// } + // LegacyInterfaceDetails is the details for interfaces on servers for API v1 and v2. type LegacyInterfaceDetails struct { InterfaceMtu *int `json:"interfaceMtu" db:"interface_mtu"` @@ -137,18 +214,27 @@ func InterfaceInfoToLegacyInterfaces(serverInterfaces []ServerInterfaceInfo) (Le address := addr.Address gateway := addr.Gateway - parsedIp, mask, err := net.ParseCIDR(address) + var parsedIp net.IP + var mask *net.IPNet + var err error + parsedIp, mask, err = net.ParseCIDR(address) if err != nil { - return legacyDetails, fmt.Errorf("Failed to parse '%s' as network or CIDR string: %v", address, err) + parsedIp = net.ParseIP(address) + if parsedIp == nil { + return legacyDetails, fmt.Errorf("Failed to parse '%s' as network or CIDR string: %v", address, err) + } } if parsedIp.To4() == nil { legacyDetails.IP6Address = &address legacyDetails.IP6Gateway = gateway - } else { + } else if mask != nil { legacyDetails.IPAddress = util.StrPtr(parsedIp.String()) legacyDetails.IPGateway = gateway legacyDetails.IPNetmask = util.StrPtr(fmt.Sprintf("%d.%d.%d.%d", mask.Mask[0], mask.Mask[1], mask.Mask[2], mask.Mask[3])) + } else { + legacyDetails.IPAddress = util.StrPtr(parsedIp.String()) + legacyDetails.IPGateway = gateway } } } @@ -316,7 +402,7 @@ type ServerNullableV2 struct { // ServerNullable represents an ATC server, as returned by the TO API. type ServerNullable struct { CommonServerProperties - Interfaces []ServerInterfaceInfo `json:"interfaces"` + Interfaces []ServerInterfaceInfo `json:"interfaces" db:"interfaces"` } // ToServerV2 converts the server to an equivalent ServerNullableV2 structure, diff --git a/traffic_ops/app/conf/cdn.conf b/traffic_ops/app/conf/cdn.conf index 5f681062ec..5ee6e739c7 100644 --- a/traffic_ops/app/conf/cdn.conf +++ b/traffic_ops/app/conf/cdn.conf @@ -1,7 +1,7 @@ { "hypnotoad" : { "listen" : [ - "https://[::]:60443?cert=/etc/pki/tls/certs/localhost.crt&key=/etc/pki/tls/private/localhost.key&verify=0x00&ciphers=AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL:!EDH:!ED" + "https://[::]:60443?cert=/home/ocket8888/src/localhost.crt&key=/home/ocket8888/src/localhost.key&verify=0x00&ciphers=AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL:!EDH:!ED" ], "user" : "trafops", "group" : "trafops", @@ -10,7 +10,7 @@ "workers" : 12 }, "traffic_ops_golang" : { - "port" : "443", + "port" : "6443", "proxy_timeout" : 60, "proxy_keep_alive" : 60, "proxy_tls_timeout" : 60, @@ -20,11 +20,11 @@ "read_header_timeout" : 60, "write_timeout" : 60, "idle_timeout" : 60, - "log_location_error": "/var/log/traffic_ops/error.log", - "log_location_warning": "", - "log_location_info": "", - "log_location_debug": "", - "log_location_event": "/var/log/traffic_ops/access.log", + "log_location_error": "stderr", + "log_location_warning": "stderr", + "log_location_info": "stderr", + "log_location_debug": "stderr", + "log_location_event": null, "max_db_connections": 20, "db_max_idle_connections": 15, "db_conn_max_lifetime_seconds": 60, diff --git a/traffic_ops/app/conf/development/database.conf b/traffic_ops/app/conf/development/database.conf index c19451d643..a4b9980ec9 100644 --- a/traffic_ops/app/conf/development/database.conf +++ b/traffic_ops/app/conf/development/database.conf @@ -1,7 +1,7 @@ { "description": "Local PostgreSQL database on port 5432", - "dbname": "to_development", + "dbname": "traffic_ops", "hostname": "localhost", "user": "traffic_ops", "password": "twelve", diff --git a/traffic_ops/traffic_ops_golang/routing/routes.go b/traffic_ops/traffic_ops_golang/routing/routes.go index 414882efac..db33b1ed5e 100644 --- a/traffic_ops/traffic_ops_golang/routing/routes.go +++ b/traffic_ops/traffic_ops_golang/routing/routes.go @@ -320,8 +320,8 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) { //Server: CRUD {api.Version{3, 0}, http.MethodGet, `servers/?$`, server.Read, auth.PrivLevelReadOnly, Authenticated, nil, 27209592853, noPerlBypass}, - {api.Version{3, 0}, http.MethodPut, `servers/{id}$`, api.UpdateHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 2586341033, noPerlBypass}, - {api.Version{3, 0}, http.MethodPost, `servers/?$`, api.CreateHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 22255580613, noPerlBypass}, + {api.Version{3, 0}, http.MethodPut, `servers/{id}$`, server.Update, auth.PrivLevelOperations, Authenticated, nil, 2586341033, noPerlBypass}, + {api.Version{3, 0}, http.MethodPost, `servers/?$`, server.Create, auth.PrivLevelOperations, Authenticated, nil, 22255580613, noPerlBypass}, {api.Version{3, 0}, http.MethodDelete, `servers/{id}$`, api.DeleteHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 2923222333, noPerlBypass}, //Server Capability @@ -684,8 +684,8 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) { //Server: CRUD {api.Version{2, 0}, http.MethodGet, `servers/?$`, server.Read, auth.PrivLevelReadOnly, Authenticated, nil, 2720959285, noPerlBypass}, - {api.Version{2, 0}, http.MethodPut, `servers/{id}$`, api.UpdateHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 258634103, noPerlBypass}, - {api.Version{2, 0}, http.MethodPost, `servers/?$`, api.CreateHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 2225558061, noPerlBypass}, + {api.Version{2, 0}, http.MethodPut, `servers/{id}$`, server.Update, auth.PrivLevelOperations, Authenticated, nil, 258634103, noPerlBypass}, + {api.Version{2, 0}, http.MethodPost, `servers/?$`, server.Create, auth.PrivLevelOperations, Authenticated, nil, 2225558061, noPerlBypass}, {api.Version{2, 0}, http.MethodDelete, `servers/{id}$`, api.DeleteHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 292322233, noPerlBypass}, //Server Capability @@ -1082,8 +1082,8 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) { //Server: CRUD {api.Version{1, 1}, http.MethodGet, `servers/?(\.json)?$`, server.Read, auth.PrivLevelReadOnly, Authenticated, nil, 1720959285, noPerlBypass}, {api.Version{1, 1}, http.MethodGet, `servers/{id}$`, server.ReadID, auth.PrivLevelReadOnly, Authenticated, nil, 1543122028, noPerlBypass}, - {api.Version{1, 1}, http.MethodPut, `servers/{id}$`, api.UpdateHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 958634103, noPerlBypass}, - {api.Version{1, 1}, http.MethodPost, `servers/?$`, api.CreateHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 2025558061, noPerlBypass}, + {api.Version{1, 1}, http.MethodPut, `servers/{id}$`, server.Update, auth.PrivLevelOperations, Authenticated, nil, 958634103, noPerlBypass}, + {api.Version{1, 1}, http.MethodPost, `servers/?$`, server.Create, auth.PrivLevelOperations, Authenticated, nil, 2025558061, noPerlBypass}, {api.Version{1, 1}, http.MethodDelete, `servers/{id}$`, api.DeleteHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 192322233, noPerlBypass}, //Server Capability diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index af9f1b6107..f482af7c19 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -23,6 +23,7 @@ package server import ( "database/sql" + "encoding/json" "errors" "fmt" "net/http" @@ -33,12 +34,14 @@ import ( "github.com/apache/trafficcontrol/lib/go-tc" "github.com/apache/trafficcontrol/lib/go-tc/tovalidate" "github.com/apache/trafficcontrol/lib/go-util" + "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/auth" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/tenant" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/routing/middleware" - validation "github.com/go-ozzo/ozzo-validation" + + "github.com/go-ozzo/ozzo-validation" "github.com/go-ozzo/ozzo-validation/is" "github.com/jmoiron/sqlx" "github.com/lib/pq" @@ -56,9 +59,190 @@ SELECT COUNT(server.id) FROM server ` +const selectQuery = ` +SELECT + cg.name AS cachegroup, + cdn.name AS cdn_name, + s.domain_name, + s.guid, + s.host_name, + s.https_port, + s.id, + s.ilo_ip_address, + s.ilo_ip_gateway, + s.ilo_ip_netmask, + s.ilo_password, + s.ilo_username, + s.offline_reason, + pl.name as phys_location, + p.name as profile, + p.description as profile_desc, + s.rack, + s.router_host_name, + s.router_port_name, + st.name as status, + s.tcp_port, + t.name as server_type, + s.xmpp_id, + s.xmpp_passwd +FROM server AS s +JOIN cachegroup cg ON s.cachegroup = cg.id +JOIN cdn cdn ON s.cdn_id = cdn.id +JOIN phys_location pl ON s.phys_location = pl.id +JOIN profile p ON s.profile = p.id +JOIN status st ON s.status = st.id +JOIN type t ON s.type = t.id +` + +const selectInterfacesQuery = ` +SELECT ( + ARRAY ( SELECT ( + json_build_object ( + 'ipAddresses', + ARRAY ( + SELECT ( + json_build_object ( + 'address', ip_address.address, + 'gateway', ip_address.gateway, + 'service_address', ip_address.service_address + ) + ) + FROM ip_address + WHERE ip_address.interface = interface.name + AND ip_address.server = server.id + ), + 'max_bandwidth', interface.max_bandwidth, + 'monitor', interface.monitor, + 'mtu', interface.mtu, + 'name', interface.name + ) + ) + FROM interface + WHERE interface.server = server.id +)) AS interfaces, +server.id +FROM server +WHERE server.id = ANY ($1) +` + +const insertQuery = ` +INSERT INTO server ( + cachegroup, + cdn_id, + domain_name, + host_name, + https_port, + ilo_ip_address, + ilo_ip_netmask, + ilo_ip_gateway, + ilo_username, + ilo_password, + mgmt_ip_address, + mgmt_ip_netmask, + mgmt_ip_gateway, + offline_reason, + phys_location, + profile, + rack, + router_host_name, + router_port_name, + status, + tcp_port, + type, + upd_pending, + xmpp_id, + xmpp_passwd +) VALUES ( + :cachegroup_id, + :cdn_id, + :domain_name, + :host_name, + :https_port, + :ilo_ip_address, + :ilo_ip_netmask, + :ilo_ip_gateway, + :ilo_username, + :ilo_password, + :mgmt_ip_address, + :mgmt_ip_netmask, + :mgmt_ip_gateway, + :offline_reason, + :phys_location_id, + :profile_id, + :rack, + :router_host_name, + :router_port_name, + :status_id, + :tcp_port, + :server_type_id, + :upd_pending, + :xmpp_id, + :xmpp_passwd +) RETURNING id,last_updated +` + +const insertInterfacesQuery = ` +INSERT INTO interface ( + max_bandwidth, + monitor, + mtu, + name, + server +) VALUES ( + $1, + $2, + $3, + $4, + $5 +) +` + +const insertIPsQuery = ` +INSERT INTO ip_address ( + address, + gateway, + interface, + server, + service_address +) VALUES UNNEST ( + $1 +) +` + +const updateQuery = ` +UPDATE server SET + cachegroup=:cachegroup_id, + cdn_id=:cdn_id, + domain_name=:domain_name, + host_name=:host_name, + https_port=:https_port, + ilo_ip_address=:ilo_ip_address, + ilo_ip_netmask=:ilo_ip_netmask, + ilo_ip_gateway=:ilo_ip_gateway, + ilo_username=:ilo_username, + ilo_password=:ilo_password, + mgmt_ip_address=:mgmt_ip_address, + mgmt_ip_netmask=:mgmt_ip_netmask, + mgmt_ip_gateway=:mgmt_ip_gateway, + offline_reason=:offline_reason, + phys_location=:phys_location_id, + profile=:profile_id, + rack=:rack, + router_host_name=:router_host_name, + router_port_name=:router_port_name, + status=:status_id, + tcp_port=:tcp_port, + type=:server_type_id, + upd_pending=:upd_pending, + xmpp_id=:xmpp_id, + xmpp_passwd=:xmpp_passwd +WHERE id=:id +RETURNING last_updated +` + func (s *TOServer) SetLastUpdated(t tc.TimeNoMod) { s.LastUpdated = &t } -func (*TOServer) InsertQuery() string { return insertQuery() } -func (*TOServer) UpdateQuery() string { return updateQuery() } +func (*TOServer) InsertQuery() string { return insertQuery } +func (*TOServer) UpdateQuery() string { return updateQuery } func (*TOServer) DeleteQuery() string { return deleteQuery() } func (TOServer) GetKeyFieldsInfo() []api.KeyFieldInfo { @@ -97,37 +281,19 @@ func (s *TOServer) Sanitize() { } } -func (s *TOServer) Validate() error { - s.Sanitize() - version := s.APIInfo().Version - noSpaces := validation.NewStringRule(tovalidate.NoSpaces, "cannot contain spaces") - - errs := []error{} - if (s.IPAddress == nil || *s.IPAddress == "") && (s.IP6Address == nil || *s.IP6Address == "") { - errs = append(errs, tc.NeedsAtLeastOneIPError) - } - - if s.IPIsService != nil && *s.IPIsService && (s.IPAddress == nil || *s.IPAddress == "") { - errs = append(errs, tc.EmptyAddressCannotBeAServiceAddressError) - } - - if s.IP6IsService != nil && *s.IP6IsService && (s.IP6Address == nil || *s.IP6Address == "") { - errs = append(errs, tc.EmptyAddressCannotBeAServiceAddressError) +func validateCommon(s tc.CommonServerProperties, tx *sql.Tx) []error { + if s.XMPPID == nil || *s.XMPPID == "" { + hostName := *s.HostName + s.XMPPID = &hostName } - if version.Major >= 2 { - if (s.IPIsService == nil || !*s.IPIsService) && (s.IP6IsService == nil || !*s.IP6IsService) { - errs = append(errs, tc.NeedsAtLeastOneServiceAddressError) - } - } + noSpaces := validation.NewStringRule(tovalidate.NoSpaces, "cannot contain spaces") - validateErrs := validation.Errors{ + errs := tovalidate.ToErrors(validation.Errors{ "cachegroupId": validation.Validate(s.CachegroupID, validation.NotNil), "cdnId": validation.Validate(s.CDNID, validation.NotNil), "domainName": validation.Validate(s.DomainName, validation.NotNil, noSpaces), "hostName": validation.Validate(s.HostName, validation.NotNil, noSpaces), - "interfaceMtu": validation.Validate(s.InterfaceMtu, validation.NotNil), - "interfaceName": validation.Validate(s.InterfaceName, validation.NotNil), "physLocationId": validation.Validate(s.PhysLocationID, validation.NotNil), "profileId": validation.Validate(s.ProfileID, validation.NotNil), "statusId": validation.Validate(s.StatusID, validation.NotNil), @@ -135,7 +301,51 @@ func (s *TOServer) Validate() error { "updPending": validation.Validate(s.UpdPending, validation.NotNil), "httpsPort": validation.Validate(s.HTTPSPort, validation.By(tovalidate.IsValidPortNumber)), "tcpPort": validation.Validate(s.TCPPort, validation.By(tovalidate.IsValidPortNumber)), + }) + + if len(errs) > 0 { + return errs + } + + if _, err := tc.ValidateTypeID(tx, s.TypeID, "server"); err != nil { + errs = append(errs, err) } + + var cdnID int + if err := tx.QueryRow("SELECT cdn from profile WHERE id=$1", s.ProfileID).Scan(&cdnID); err != nil { + log.Error.Printf("could not execute select cdnID from profile: %s\n", err) + if err == sql.ErrNoRows { + errs = append(errs, errors.New("associated profile must have a cdn associated")) + } else { + errs = append(errs, tc.DBError) + } + return errs + } + + log.Infof("got cdn id: %d from profile and cdn id: %d from server", cdnID, *s.CDNID) + if cdnID != *s.CDNID { + errs = append(errs, fmt.Errorf("CDN id '%d' for profile '%d' does not match Server CDN '%d'", cdnID, *s.ProfileID, *s.CDNID)) + } + + return errs +} + +func validateV1(s tc.ServerNullableV11, tx *sql.Tx) error { + if s.IP6Address != nil && len(strings.TrimSpace(*s.IP6Address)) == 0 { + s.IP6Address = nil + } + + + errs := []error{} + if (s.IPAddress == nil || *s.IPAddress == "") && s.IP6Address == nil { + errs = append(errs, tc.NeedsAtLeastOneIPError) + } + + validateErrs := validation.Errors{ + "interfaceMtu": validation.Validate(s.InterfaceMtu, validation.NotNil), + "interfaceName": validation.Validate(s.InterfaceName, validation.NotNil), + } + if s.IPAddress != nil && *s.IPAddress != "" { validateErrs["ipAddress"] = validation.Validate(s.IPAddress, is.IPv4) validateErrs["ipNetmask"] = validation.Validate(s.IPNetmask, validation.NotNil) @@ -145,36 +355,36 @@ func (s *TOServer) Validate() error { validateErrs["ip6Address"] = validation.Validate(s.IP6Address, validation.By(tovalidate.IsValidIPv6CIDROrAddress)) } errs = append(errs, tovalidate.ToErrors(validateErrs)...) - if len(errs) > 0 { - return util.JoinErrs(errs) - } + errs = append(errs, validateCommon(s.CommonServerProperties, tx)...) + + return util.JoinErrs(errs) +} - if _, err := tc.ValidateTypeID(s.ReqInfo.Tx.Tx, s.TypeID, "server"); err != nil { +func validateV2(s tc.ServerNullableV2, tx *sql.Tx) error { + var errs []error + + if err := validateV1(s.ServerNullableV11, tx); err != nil { return err } - rows, err := s.ReqInfo.Tx.Tx.Query("select cdn from profile where id=$1", s.ProfileID) - if err != nil { - log.Error.Printf("could not execute select cdnID from profile: %s\n", err) - errs = append(errs, tc.DBError) - return util.JoinErrs(errs) + if (s.IPIsService == nil || !*s.IPIsService) && (s.IP6IsService == nil || !*s.IP6IsService) { + errs = append(errs, tc.NeedsAtLeastOneServiceAddressError) } - defer rows.Close() - var cdnID int - for rows.Next() { - if err := rows.Scan(&cdnID); err != nil { - log.Error.Printf("could not scan cdnID from profile: %s\n", err) - errs = append(errs, errors.New("associated profile must have a cdn associated")) - return util.JoinErrs(errs) - } + + if s.IPIsService != nil && *s.IPIsService && (s.IPAddress == nil) { + errs = append(errs, tc.EmptyAddressCannotBeAServiceAddressError) } - log.Infof("got cdn id: %d from profile and cdn id: %d from server", cdnID, *s.CDNID) - if cdnID != *s.CDNID { - errs = append(errs, errors.New(fmt.Sprintf("CDN id '%d' for profile '%d' does not match Server CDN '%d'", cdnID, *s.ProfileID, *s.CDNID))) + + if s.IP6IsService != nil && *s.IP6IsService && (s.IP6Address == nil) { + errs = append(errs, tc.EmptyAddressCannotBeAServiceAddressError) } return util.JoinErrs(errs) } +func validateV3(tc.ServerNullableV2, *sql.Tx) error { + return nil +} + // ChangeLogMessage implements the api.ChangeLogger interface for a custom log message func (s TOServer) ChangeLogMessage(action string) (string, error) { @@ -234,7 +444,7 @@ func Read(w http.ResponseWriter, r *http.Request) { } if version.Major <= 1 { - legacyServers := make([]tc.ServerNullableV2, len(servers)) + legacyServers := make([]tc.ServerNullableV2, 0, len(servers)) for _, server := range servers { legacyServer, err := server.ToServerV2() if err != nil { @@ -247,7 +457,8 @@ func Read(w http.ResponseWriter, r *http.Request) { return } - legacyServers := make([]tc.ServerNullableV11, len(servers)) + legacyServers := make([]tc.ServerNullableV11, 0, len(servers)) + log.Debugf("servers len=%d", len(servers)) for _, server := range servers { legacyServer, err := server.ToServerV2() if err != nil { @@ -256,6 +467,7 @@ func Read(w http.ResponseWriter, r *http.Request) { } legacyServers = append(legacyServers, legacyServer.ServerNullableV11) } + log.Debugf("legacyServers len=%d", len(legacyServers)) api.WriteResp(w, r, legacyServers) } @@ -337,7 +549,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( return nil, unfiltered, util.JoinErrs(errs), nil, http.StatusBadRequest } - query := selectQuery() + queryAddition + where + orderBy + pagination + query := selectQuery + queryAddition + where + orderBy + pagination log.Debugln("Query is ", query) rows, err := tx.NamedQuery(query, queryValues) @@ -346,10 +558,12 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( } defer rows.Close() - servers := []tc.ServerNullable{} HiddenField := "********" + + servers := make(map[int]tc.ServerNullable) + ids := []int{} for rows.Next() { var s tc.ServerNullable if err = rows.StructScan(&s); err != nil { @@ -359,22 +573,56 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( s.ILOPassword = &HiddenField s.XMPPPasswd = &HiddenField } - servers = append(servers, s) + + if s.ID == nil { + return nil, unfiltered, nil, errors.New("found server with nil ID"), http.StatusInternalServerError + } + if _, ok := servers[*s.ID]; ok { + return nil, unfiltered, nil, fmt.Errorf("found more than one server with ID #%d", *s.ID), http.StatusInternalServerError + } + servers[*s.ID] = s + ids = append(ids, *s.ID) + } + + interfaceRows, err := tx.Tx.Query(selectInterfacesQuery, pq.Array(ids)) + if err != nil { + return nil, unfiltered, nil, fmt.Errorf("querying for interfaces: %v", err), http.StatusInternalServerError + } + defer interfaceRows.Close() + + for interfaceRows.Next() { + ifaces := []tc.ServerInterfaceInfo{} + var id int + if err = interfaceRows.Scan(pq.Array(&ifaces), &id); err != nil { + return nil, unfiltered, nil, fmt.Errorf("getting server interfaces: %v", err), http.StatusInternalServerError + } + + if s, ok := servers[id]; !ok { + log.Warnf("interfaces query returned interfaces for server #%d that was not in original query") + } else { + s.Interfaces = ifaces + servers[id] = s + } + } + + var returnable []tc.ServerNullable + for _, server := range servers { + returnable = append(returnable, server) } // if ds requested uses mid-tier caches, add those to the list as well if usesMids { - mids, userErr, sysErr, errCode := getMidServers(servers, tx) + mids, userErr, sysErr, errCode := getMidServers(returnable, tx) log.Debugf("getting mids: %v, %v, %s\n", userErr, sysErr, http.StatusText(errCode)) if userErr != nil || sysErr != nil { return nil, unfiltered, userErr, sysErr, errCode } - servers = append(servers, mids...) + returnable = append(returnable, mids...) } - return servers, unfiltered, nil, nil, http.StatusOK + return returnable, unfiltered, nil, nil, http.StatusOK } // getMidServers gets the mids used by the servers in this DS. @@ -396,7 +644,7 @@ func getMidServers(servers []tc.ServerNullable, tx *sqlx.Tx) ([]tc.ServerNullabl edgeIDs := strings.Join(ids, ",") // TODO: include secondary parent? - q := selectQuery() + ` + q := selectQuery + ` WHERE t.name = 'MID' AND s.cachegroup IN ( SELECT cg.parent_cachegroup_id FROM cachegroup AS cg WHERE cg.id IN ( @@ -421,81 +669,284 @@ WHERE s.id IN (` + edgeIDs + `))) return mids, nil, nil, http.StatusOK } -func (s *TOServer) Update() (error, error, int) { - if s.IP6Address != nil && len(strings.TrimSpace(*s.IP6Address)) == 0 { - s.IP6Address = nil +func Update(w http.ResponseWriter, r *http.Request) { + inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) + if userErr != nil || sysErr != nil { + api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr) + return } - // see if type changed - typeID := -1 - // see if cdn changed - cdnId := -1 + defer inf.Close() + + var server tc.ServerNullableV11 - if err := s.APIInfo().Tx.QueryRow("SELECT type, cdn_id FROM server WHERE id = $1", s.ID).Scan(&typeID, &cdnId); err != nil { + tx := inf.Tx.Tx + + if err := json.NewDecoder(r.Body).Decode(&server); err != nil { + api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) + return + } + + if err := validateV1(server, tx); err != nil { + api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) + return + } + + // see if cdn or type changed + var cdnID int + var typeID int + + if err := inf.Tx.QueryRow("SELECT type, cdn_id FROM server WHERE id = $1", server.ID).Scan(&typeID, &cdnID); err != nil { if err == sql.ErrNoRows { - return errors.New("no server found with this id"), nil, http.StatusNotFound + api.HandleErr(w, r, tx, http.StatusNotFound, errors.New("no server found with this ID"), nil) + return } - return nil, fmt.Errorf("getting current server type: %v", err), http.StatusInternalServerError + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("getting current server type: %v", err)) + return } - dsIDs := []int64{} - if err := s.APIInfo().Tx.QueryRowx("SELECT ARRAY(SELECT deliveryservice FROM deliveryservice_server WHERE server = $1)", s.ID).Scan(pq.Array(&dsIDs)); err != nil && err != sql.ErrNoRows { - return nil, fmt.Errorf("getting server assigned delivery services: %v", err), http.StatusInternalServerError + var dsIDs []int64 + if err := inf.Tx.QueryRowx("SELECT ARRAY(SELECT deliveryservice FROM deliveryservice_server WHERE server = $1)", server.ID).Scan(pq.Array(&dsIDs)); err != nil && err != sql.ErrNoRows { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("getting server assigned delivery services: %v", err)) + return } // Check to see if the user is trying to change the CDN of a server, which is already linked with a DS - if cdnId != *s.CDNID && len(dsIDs) != 0 { - return errors.New("server cdn can not be updated when it is currently assigned to delivery services"), nil, http.StatusConflict + if cdnID != *server.CDNID && len(dsIDs) != 0 { + api.HandleErr(w, r, tx, http.StatusConflict, errors.New("server cdn can not be updated when it is currently assigned to delivery services"), nil) + return } // If type is changing ensure it isn't assigned to any DSes. - if typeID != *s.TypeID { + if typeID != *server.TypeID { if len(dsIDs) != 0 { - return errors.New("server type can not be updated when it is currently assigned to delivery services"), nil, http.StatusConflict + api.HandleErr(w, r, tx, http.StatusConflict, errors.New("server type can not be updated when it is currently assigned to Delivery Services"), nil) + return } } - current := TOServer{} - err := s.ReqInfo.Tx.QueryRowx(selectV20UpdatesQuery()+` WHERE sv.id=$1`, strconv.Itoa(*s.ID)).StructScan(¤t) + // current := TOServer{} + // err := inf.Tx.QueryRowx(selectV20UpdatesQuery()+` WHERE sv.id=$1`, strconv.Itoa(*s.ID)).StructScan(¤t) + // if err != nil { + // return api.ParseDBError(err) + // } + // defaultIsService := true + // if s.IPIsService == nil { + // if current.IPIsService != nil { + // s.IPIsService = current.IPIsService + // } else { + // s.IPIsService = &defaultIsService + // } + // } + // if s.IP6IsService == nil { + // if current.IP6IsService != nil { + // s.IP6IsService = current.IP6IsService + // } else { + // s.IP6IsService = &defaultIsService + // } + // } + + rows, err := inf.Tx.NamedQuery(updateQuery, server) if err != nil { - return api.ParseDBError(err) + userErr, sysErr, errCode = api.ParseDBError(err) + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return } - defaultIsService := true - if s.IPIsService == nil { - if current.IPIsService != nil { - s.IPIsService = current.IPIsService - } else { - s.IPIsService = &defaultIsService + defer rows.Close() + + if !rows.Next() { + api.HandleErr(w, r, tx, http.StatusNotFound, errors.New("no server found with this id"), nil) + } + var lastUpdated tc.TimeNoMod + if err := rows.Scan(&lastUpdated); err != nil { + api.HandleErr(w, r, tx, http.StatusNotFound, nil, fmt.Errorf("scanning lastUpdated from server insert: %v", err)) + return + } + server.LastUpdated = &lastUpdated + + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server updated", server) +} + +func createInterfaces(s tc.ServerNullableV11, tx *sql.Tx) error { + if err := tx.QueryRow(insertInterfacesQuery, nil, true, s.InterfaceMtu, s.InterfaceName, s.ID).Scan(); err != nil && err != sql.ErrNoRows { + return fmt.Errorf("Inserting interface: %v", err) + } + + var ips []tc.ServerIpAddress + if s.IPAddress != nil && *s.IPAddress != "" { + ips = append(ips, tc.ServerIpAddress{*s.IPAddress, s.IPGateway, *s.InterfaceName, uint64(*s.ID), true}) + } + + if s.IP6Address != nil && *s.IP6Address != "" { + ips = append(ips, tc.ServerIpAddress{*s.IP6Address, s.IP6Gateway, *s.InterfaceName, uint64(*s.ID), true}) + } + + if err := tx.QueryRow(insertIPsQuery, pq.Array(&ips)).Scan(); err != nil && err != sql.ErrNoRows { + return fmt.Errorf("Inserting IPs: %v", err) + } + return nil +} + +func createV1(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { + var server tc.ServerNullableV11 + + tx := inf.Tx.Tx + + if err := json.NewDecoder(r.Body).Decode(&server); err != nil { + api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) + return + } + + if err := validateV1(server, tx); err != nil { + api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) + return + } + + resultRows, err := inf.Tx.NamedQuery(insertQuery, server) + if err != nil { + userErr, sysErr, errCode := api.ParseDBError(err) + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return + } + defer resultRows.Close() + + var id int + var lastUpdated tc.TimeNoMod + + rowsAffected := 0 + for resultRows.Next() { + rowsAffected++ + if err := resultRows.Scan(&id, &lastUpdated); err != nil { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("server create scanning: %v", err)) + return } } - if s.IP6IsService == nil { - if current.IP6IsService != nil { - s.IP6IsService = current.IP6IsService - } else { - s.IP6IsService = &defaultIsService + if rowsAffected == 0 { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, errors.New("server create: no server was inserted, no id was returned")) + return + } else if rowsAffected > 1 { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, errors.New("too many ids returned from server insert")) + } + server.ID = &id + server.LastUpdated = &lastUpdated + + if err := createInterfaces(server, tx); err != nil { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, err) + } + + alerts := tc.CreateAlerts(tc.SuccessLevel, "Server created") + api.WriteAlertsObj(w, r, http.StatusCreated, alerts, server) +} + +func createV2(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { + var server tc.ServerNullableV2 + + tx := inf.Tx.Tx + + if err := json.NewDecoder(r.Body).Decode(&server); err != nil { + api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) + return + } + + if err := validateV2(server, tx); err != nil { + api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) + return + } + + resultRows, err := inf.Tx.NamedQuery(insertQuery, server) + if err != nil { + userErr, sysErr, errCode := api.ParseDBError(err) + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return + } + defer resultRows.Close() + + + var id int + var lastUpdated tc.TimeNoMod + + rowsAffected := 0 + for resultRows.Next() { + rowsAffected++ + if err := resultRows.Scan(&id, &lastUpdated); err != nil { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("server create scanning: %v", err)) + return } } + if rowsAffected == 0 { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, errors.New("server create: no server was inserted, no id was returned")) + return + } else if rowsAffected > 1 { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, errors.New("too many ids returned from server insert")) + } + server.ID = &id + server.LastUpdated = &lastUpdated - return api.GenericUpdate(s) + alerts := tc.CreateAlerts(tc.SuccessLevel, "Server created") + api.WriteAlertsObj(w, r, http.StatusCreated, alerts, server) } -func (s *TOServer) Create() (error, error, int) { - // TODO put in Validate() - if s.IP6Address != nil && len(strings.TrimSpace(*s.IP6Address)) == 0 { - s.IP6Address = nil +func createV3(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { + var server tc.ServerNullableV2 + + tx := inf.Tx.Tx + + if err := json.NewDecoder(r.Body).Decode(&server); err != nil { + api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) + return } - if s.XMPPID == nil || *s.XMPPID == "" { - hostName := *s.HostName - s.XMPPID = &hostName + + if err := validateV3(server, tx); err != nil { + api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) + return } - // default the is service field to true if omitted and to upgrade version < 1.4 - defaultIsService := true - if s.IPIsService == nil { - s.IPIsService = &defaultIsService + resultRows, err := inf.Tx.NamedQuery(insertQuery, server) + if err != nil { + userErr, sysErr, errCode := api.ParseDBError(err) + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return + } + defer resultRows.Close() + + + var id int + var lastUpdated tc.TimeNoMod + + rowsAffected := 0 + for resultRows.Next() { + rowsAffected++ + if err := resultRows.Scan(&id, &lastUpdated); err != nil { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("server create scanning: %v", err)) + return + } + } + if rowsAffected == 0 { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, errors.New("server create: no server was inserted, no id was returned")) + return + } else if rowsAffected > 1 { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, errors.New("too many ids returned from server insert")) } - if s.IP6IsService == nil { - s.IP6IsService = &defaultIsService + server.ID = &id + server.LastUpdated = &lastUpdated + + alerts := tc.CreateAlerts(tc.SuccessLevel, "Server created") + api.WriteAlertsObj(w, r, http.StatusCreated, alerts, server) +} + +func Create(w http.ResponseWriter, r *http.Request) { + inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) + if userErr != nil || sysErr != nil { + api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr) + return } + defer inf.Close() - return api.GenericCreate(s) + switch { + case inf.Version.Major <= 1: + createV1(inf, w, r) + case inf.Version.Major == 2: + createV2(inf, w, r) + default: + createV3(inf, w, r) + } } func (s *TOServer) Delete() (error, error, int) { return api.GenericDelete(s) } @@ -508,179 +959,7 @@ FROM server sv` } -func selectQuery() string { - const JumboFrameBPS = 9000 - return ` -SELECT - cg.name AS cachegroup, - cdn.name AS cdn_name, - ARRAY(select deliveryservice from deliveryservice_server where server = s.id), - s.domain_name, - s.guid, - s.host_name, - s.https_port, - s.id, - s.ilo_ip_address, - s.ilo_ip_gateway, - s.ilo_ip_netmask, - s.ilo_password, - s.ilo_username, - ARRAY ( -SELECT ( json_build_object ( -'ipAddresses', ARRAY ( -SELECT ( json_build_object ( -'address', ip_address.address, -'gateway', ip_address.gateway, -'service_address', 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.offline_reason, - pl.name as phys_location, - p.name as profile, - p.description as profile_desc, - s.rack, - s.router_host_name, - s.router_port_name, - st.name as status, - s.tcp_port, - t.name as server_type, - s.xmpp_id, - s.xmpp_passwd -FROM server AS s -JOIN cachegroup cg ON s.cachegroup = cg.id -JOIN cdn cdn ON s.cdn_id = cdn.id -JOIN phys_location pl ON s.phys_location = pl.id -JOIN profile p ON s.profile = p.id -JOIN status st ON s.status = st.id -JOIN type t ON s.type = t.id` -} -func insertQuery() string { - query := `INSERT INTO server ( -cachegroup, -cdn_id, -domain_name, -host_name, -https_port, -ilo_ip_address, -ilo_ip_netmask, -ilo_ip_gateway, -ilo_username, -ilo_password, -interface_mtu, -interface_name, -ip6_address, -ip6_address_is_service, -ip6_gateway, -ip_address, -ip_address_is_service, -ip_netmask, -ip_gateway, -mgmt_ip_address, -mgmt_ip_netmask, -mgmt_ip_gateway, -offline_reason, -phys_location, -profile, -rack, -router_host_name, -router_port_name, -status, -tcp_port, -type, -upd_pending, -xmpp_id, -xmpp_passwd -) VALUES ( -:cachegroup_id, -:cdn_id, -:domain_name, -:host_name, -:https_port, -:ilo_ip_address, -:ilo_ip_netmask, -:ilo_ip_gateway, -:ilo_username, -:ilo_password, -:interface_mtu, -:interface_name, -:ip6_address, -:ip6_address_is_service, -:ip6_gateway, -:ip_address, -:ip_address_is_service, -:ip_netmask, -:ip_gateway, -:mgmt_ip_address, -:mgmt_ip_netmask, -:mgmt_ip_gateway, -:offline_reason, -:phys_location_id, -:profile_id, -:rack, -:router_host_name, -:router_port_name, -:status_id, -:tcp_port, -:server_type_id, -:upd_pending, -:xmpp_id, -:xmpp_passwd -) RETURNING id,last_updated` - return query -} - -func updateQuery() string { - query := `UPDATE -server SET -cachegroup=:cachegroup_id, -cdn_id=:cdn_id, -domain_name=:domain_name, -host_name=:host_name, -https_port=:https_port, -ilo_ip_address=:ilo_ip_address, -ilo_ip_netmask=:ilo_ip_netmask, -ilo_ip_gateway=:ilo_ip_gateway, -ilo_username=:ilo_username, -ilo_password=:ilo_password, -interface_mtu=:interface_mtu, -interface_name=:interface_name, -ip6_address=:ip6_address, -ip6_address_is_service=:ip6_address_is_service, -ip6_gateway=:ip6_gateway, -ip_address=:ip_address, -ip_address_is_service=:ip_address_is_service, -ip_netmask=:ip_netmask, -ip_gateway=:ip_gateway, -mgmt_ip_address=:mgmt_ip_address, -mgmt_ip_netmask=:mgmt_ip_netmask, -mgmt_ip_gateway=:mgmt_ip_gateway, -offline_reason=:offline_reason, -phys_location=:phys_location_id, -profile=:profile_id, -rack=:rack, -router_host_name=:router_host_name, -router_port_name=:router_port_name, -status=:status_id, -tcp_port=:tcp_port, -type=:server_type_id, -upd_pending=:upd_pending, -xmpp_id=:xmpp_id, -xmpp_passwd=:xmpp_passwd -WHERE id=:id RETURNING last_updated` - return query -} func deleteQuery() string { return `DELETE FROM server WHERE id = :id` From 204f9bba6b50ffcc5d31b9087cea2c066543395b Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 11 May 2020 15:40:34 -0600 Subject: [PATCH 05/87] Implemented POST --- lib/go-tc/servers.go | 25 +- .../traffic_ops_golang/server/servers.go | 392 ++++++++++++++---- 2 files changed, 322 insertions(+), 95 deletions(-) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index ffddd4b7ad..f8a5e3acc1 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -1,19 +1,13 @@ package tc import ( - // "bytes" "database/sql/driver" "encoding/json" - // "errors" "fmt" "net" - // "strconv" "time" "github.com/apache/trafficcontrol/lib/go-util" - "github.com/apache/trafficcontrol/lib/go-log" - - // "github.com/lib/pq" ) /* @@ -85,8 +79,8 @@ type ServerIpAddress struct { // ServerInterfaceInfo is the data associated with a server's interface. type ServerInterfaceInfo struct { - IpAddresses []ServerIpAddress `json:"ipAddresses" db:"ipAddresses"` - MaxBandwidth *int64 `json:"maxBandwidth" db:"max_bandwidth"` + IPAddresses []ServerIpAddress `json:"ipAddresses" db:"ipAddresses"` + MaxBandwidth *uint64 `json:"maxBandwidth" db:"max_bandwidth"` Monitor bool `json:"monitor" db:"monitor"` MTU *uint64 `json:"mtu" db:"mtu"` Name string `json:"name" db:"name"` @@ -107,8 +101,6 @@ func (sii *ServerInterfaceInfo) Scan(src interface{}) error { return fmt.Errorf("expected deliveryservice in byte array form; got %T", src) } - log.Debugf(string(b)) - return json.Unmarshal([]byte(b), sii) } @@ -200,13 +192,8 @@ func InterfaceInfoToLegacyInterfaces(serverInterfaces []ServerInterfaceInfo) (Le var legacyDetails LegacyInterfaceDetails for _, intFace := range serverInterfaces { - if intFace.MTU != nil { - legacyDetails.InterfaceMtu = util.IntPtr(int(*intFace.MTU)) - } - - legacyDetails.InterfaceName = &intFace.Name - for _, addr := range intFace.IpAddresses { + for _, addr := range intFace.IPAddresses { if !addr.ServiceAddress { continue } @@ -236,6 +223,12 @@ func InterfaceInfoToLegacyInterfaces(serverInterfaces []ServerInterfaceInfo) (Le legacyDetails.IPAddress = util.StrPtr(parsedIp.String()) legacyDetails.IPGateway = gateway } + + if intFace.MTU != nil { + legacyDetails.InterfaceMtu = util.IntPtr(int(*intFace.MTU)) + } + + legacyDetails.InterfaceName = &intFace.Name } } diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index f482af7c19..5629869f28 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -26,6 +26,7 @@ import ( "encoding/json" "errors" "fmt" + "net" "net/http" "strconv" "strings" @@ -137,6 +138,7 @@ INSERT INTO server ( ilo_ip_gateway, ilo_username, ilo_password, + interface_name, mgmt_ip_address, mgmt_ip_netmask, mgmt_ip_gateway, @@ -163,6 +165,7 @@ INSERT INTO server ( :ilo_ip_gateway, :ilo_username, :ilo_password, + :interface_name, :mgmt_ip_address, :mgmt_ip_netmask, :mgmt_ip_gateway, @@ -178,10 +181,44 @@ INSERT INTO server ( :upd_pending, :xmpp_id, :xmpp_passwd -) RETURNING id,last_updated +) RETURNING + (SELECT name FROM cachegroup WHERE cachegroup.id=server.cachegroup) AS cachegroup, + cachegroup AS cachegroup_id, + cdn_id, + (SELECT name FROM cdn WHERE cdn.id=server.cdn_id) AS cdn_name, + domain_name, + guid, + host_name, + https_port, + id, + ilo_ip_address, + ilo_ip_gateway, + ilo_ip_netmask, + ilo_password, + ilo_username, + last_updated, + mgmt_ip_address, + mgmt_ip_gateway, + mgmt_ip_netmask, + offline_reason, + (SELECT name FROM phys_location WHERE phys_location.id=server.phys_location) AS phys_location, + phys_location AS phys_location_id, + profile AS profile_id, + (SELECT description FROM profile WHERE profile.id=server.profile) AS profile_desc, + (SELECT name FROM profile WHERE profile.id=server.profile) AS profile, + rack, + reval_pending, + router_host_name, + router_port_name, + (SELECT name FROM status WHERE status.id=server.status) AS status, + status AS status_id, + tcp_port, + (SELECT name FROM type WHERE type.id=server.type) AS server_type, + type AS server_type_id, + upd_pending ` -const insertInterfacesQuery = ` +const insertInterfaceQuery = ` INSERT INTO interface ( max_bandwidth, monitor, @@ -197,15 +234,19 @@ INSERT INTO interface ( ) ` -const insertIPsQuery = ` +const insertIPQuery = ` INSERT INTO ip_address ( address, gateway, interface, server, service_address -) VALUES UNNEST ( - $1 +) VALUES ( + $1, + $2, + $3, + $4, + $5 ) ` @@ -240,46 +281,66 @@ WHERE id=:id RETURNING last_updated ` -func (s *TOServer) SetLastUpdated(t tc.TimeNoMod) { s.LastUpdated = &t } -func (*TOServer) InsertQuery() string { return insertQuery } -func (*TOServer) UpdateQuery() string { return updateQuery } -func (*TOServer) DeleteQuery() string { return deleteQuery() } - -func (TOServer) GetKeyFieldsInfo() []api.KeyFieldInfo { - return []api.KeyFieldInfo{{"id", api.GetIntKey}} -} - -func (s TOServer) GetKeys() (map[string]interface{}, bool) { - if s.ID == nil { - return map[string]interface{}{"id": 0}, false - } - return map[string]interface{}{"id": *s.ID}, true -} - -func (s *TOServer) SetKeys(keys map[string]interface{}) { - i, _ := keys["id"].(int) //this utilizes the non panicking type assertion, if the thrown away ok variable is false i will be the zero of the type, 0 here. - s.ID = &i -} - -func (s *TOServer) GetAuditName() string { - if s.DomainName != nil { - return *s.DomainName - } - if s.ID != nil { - return strconv.Itoa(*s.ID) - } - return "unknown" -} +const deleteServerQuery = ` +DELETE FROM server +WHERE id=$1 +RETURNING + (SELECT name FROM cachegroup WHERE cachegroup.id=server.cachegroup) AS cachegroup, + cachegroup AS cachegroup_id, + cdn_id, + (SELECT name FROM cdn WHERE cdn.id=server.cdn_id) AS cdn_name, + domain_name, + guid, + host_name, + https_port, + id, + ilo_ip_address, + ilo_ip_gateway, + ilo_ip_netmask, + ilo_password, + ilo_username, + last_updated, + mgmt_ip_address, + mgmt_ip_gateway, + mgmt_ip_netmask, + offline_reason, + (SELECT name FROM phys_location WHERE phys_location.id=server.phys_location) AS phys_location, + phys_location AS phys_location_id, + profile AS profile_id, + (SELECT description FROM profile WHERE profile.id=server.profile) AS profile_desc, + (SELECT name FROM profile WHERE profile.id=server.profile) AS profile, + rack, + reval_pending, + router_host_name, + router_port_name, + (SELECT name FROM status WHERE status.id=server.status) AS status, + status AS status_id, + tcp_port, + (SELECT name FROM type WHERE type.id=server.type) AS server_type, + type AS server_type_id, + upd_pending +` -func (s *TOServer) GetType() string { - return "server" -} +const deleteInterfacesQuery = ` +DELETE FROM interface +WHERE server=$1 +RETURNING + max_bandwidth, + monitor, + mtu, + name +` +const deleteIPsQuery = ` +DELETE FROM ip_address +WHERE server = $1 +RETURNING + address, + gateway, + interface, + serviceAddress +` -func (s *TOServer) Sanitize() { - if s.IP6Address != nil && *s.IP6Address == "" { - s.IP6Address = nil - } -} +func (*TOServer) DeleteQuery() string { return deleteQuery() } func validateCommon(s tc.CommonServerProperties, tx *sql.Tx) []error { if s.XMPPID == nil || *s.XMPPID == "" { @@ -360,31 +421,120 @@ func validateV1(s tc.ServerNullableV11, tx *sql.Tx) error { return util.JoinErrs(errs) } -func validateV2(s tc.ServerNullableV2, tx *sql.Tx) error { +func validateV2(s *tc.ServerNullableV2, tx *sql.Tx) error { var errs []error if err := validateV1(s.ServerNullableV11, tx); err != nil { return err } - if (s.IPIsService == nil || !*s.IPIsService) && (s.IP6IsService == nil || !*s.IP6IsService) { + // default boolean value is false + if s.IPIsService == nil { + s.IPIsService = new(bool) + } + if s.IP6IsService == nil { + s.IP6IsService = new(bool) + } + + if !*s.IPIsService && !*s.IP6IsService { errs = append(errs, tc.NeedsAtLeastOneServiceAddressError) } - if s.IPIsService != nil && *s.IPIsService && (s.IPAddress == nil) { + if *s.IPIsService && s.IPAddress == nil { errs = append(errs, tc.EmptyAddressCannotBeAServiceAddressError) } - if s.IP6IsService != nil && *s.IP6IsService && (s.IP6Address == nil) { + if *s.IP6IsService && s.IP6Address == nil { errs = append(errs, tc.EmptyAddressCannotBeAServiceAddressError) } return util.JoinErrs(errs) } -func validateV3(tc.ServerNullableV2, *sql.Tx) error { +func validateMTU(mtu interface{}) error { + m := mtu.(*uint64) + if m == nil { + return nil + } + + if *m < 1280 { + return errors.New("must be at least 1280") + } return nil } +func validateGateway(g interface{}) error { + if g == nil { + return nil + } + + if gtwy := net.ParseIP(*g.(*string)); gtwy == nil { + return errors.New("gateway not a valid IP address") + } + return nil +} + +func validateV3(s tc.ServerNullable, tx *sql.Tx) (string, error) { + + if len(s.Interfaces) == 0 { + return "", errors.New("a server must have at least one interface") + } + var errs []error + var serviceAddrV4Found bool + var serviceAddrV6Found bool + var serviceInterface string + for _, iface := range s.Interfaces { + + ruleName := fmt.Sprintf("interface '%s' ", iface.Name) + errs = append(errs, tovalidate.ToErrors(validation.Errors{ + ruleName + "name": validation.Validate(iface.Name, validation.Required), + ruleName + "mtu": validation.Validate(iface.MaxBandwidth, validation.By(validateMTU)), + ruleName + "ipAddresses": validation.Validate(iface.IPAddresses, validation.Required), + })...) + + for _, addr := range iface.IPAddresses { + ruleName += fmt.Sprintf("address '%s'", addr.Address) + + var parsedIP net.IP + var err error + if parsedIP, _, err = net.ParseCIDR(addr.Address); err != nil { + if parsedIP = net.ParseIP(addr.Address); parsedIP == nil { + errs = append(errs, fmt.Errorf("%s: address: %v", ruleName, err)) + continue + } + } + + if addr.Gateway != nil { + if gateway := net.ParseIP(*addr.Gateway); gateway == nil { + errs = append(errs, fmt.Errorf("%s: gateway: %v", ruleName, err)) + } else if (gateway.To4() == nil && parsedIP.To4() != nil) || (gateway.To4() != nil && parsedIP.To4() == nil) { + errs = append(errs, errors.New(ruleName + ": address family mismatch between address and gateway")) + } + } + + if addr.ServiceAddress { + if serviceInterface != "" && serviceInterface != iface.Name { + errs = append(errs, fmt.Errorf("interfaces: both %s and %s interfaces contain service addresses - only one service-address-containing-interface is allowed", serviceInterface, iface.Name)) + } + serviceInterface = iface.Name + if parsedIP.To4() != nil { + if serviceAddrV4Found { + errs = append(errs, fmt.Errorf("interfaces: address '%s' of interface '%s' is marked as a service address, but an IPv4 service address appears earlier in the list", addr.Address, iface.Name)) + } + serviceAddrV4Found = true + } else { + if serviceAddrV6Found { + errs = append(errs, fmt.Errorf("interfaces: address '%s' of interface '%s' is marked as a service address, but an IPv6 service address appears earlier in the list", addr.Address, iface.Name)) + } + serviceAddrV6Found = true + } + } + } + } + + errs = append(errs, validateCommon(s.CommonServerProperties, tx)...) + return serviceInterface, util.JoinErrs(errs) +} + // ChangeLogMessage implements the api.ChangeLogger interface for a custom log message func (s TOServer) ChangeLogMessage(action string) (string, error) { @@ -764,23 +914,29 @@ func Update(w http.ResponseWriter, r *http.Request) { api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server updated", server) } -func createInterfaces(s tc.ServerNullableV11, tx *sql.Tx) error { - if err := tx.QueryRow(insertInterfacesQuery, nil, true, s.InterfaceMtu, s.InterfaceName, s.ID).Scan(); err != nil && err != sql.ErrNoRows { - return fmt.Errorf("Inserting interface: %v", err) +func createInterfaces(s tc.ServerNullableV11, tx *sql.Tx, ipv4IsService, ipv6IsService bool) error { + if err := tx.QueryRow(insertInterfaceQuery, nil, true, s.InterfaceMtu, s.InterfaceName, s.ID).Scan(); err != nil && err != sql.ErrNoRows { + return fmt.Errorf("Inserting legacy interface: %v", err) } - var ips []tc.ServerIpAddress if s.IPAddress != nil && *s.IPAddress != "" { - ips = append(ips, tc.ServerIpAddress{*s.IPAddress, s.IPGateway, *s.InterfaceName, uint64(*s.ID), true}) + if s.IPGateway != nil && *s.IPGateway == "" { + s.IPGateway = nil + } + if err := tx.QueryRow(insertIPQuery, *s.IPAddress, s.IPGateway, *s.InterfaceName, uint64(*s.ID), ipv4IsService).Scan(); err != nil && err != sql.ErrNoRows { + return fmt.Errorf("Inserting legacy IPv4 address: %v", err) + } } if s.IP6Address != nil && *s.IP6Address != "" { - ips = append(ips, tc.ServerIpAddress{*s.IP6Address, s.IP6Gateway, *s.InterfaceName, uint64(*s.ID), true}) + if s.IP6Gateway != nil && *s.IP6Gateway == "" { + s.IP6Gateway = nil + } + if err := tx.QueryRow(insertIPQuery, *s.IP6Address, s.IP6Gateway, *s.InterfaceName, uint64(*s.ID), ipv6IsService).Scan(); err != nil && err != sql.ErrNoRows { + return fmt.Errorf("Inserting legacy IPv6 address: %v", err) + } } - if err := tx.QueryRow(insertIPsQuery, pq.Array(&ips)).Scan(); err != nil && err != sql.ErrNoRows { - return fmt.Errorf("Inserting IPs: %v", err) - } return nil } @@ -827,7 +983,7 @@ func createV1(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { server.ID = &id server.LastUpdated = &lastUpdated - if err := createInterfaces(server, tx); err != nil { + if err := createInterfaces(server, tx, true, true); err != nil { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, err) } @@ -845,7 +1001,8 @@ func createV2(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { return } - if err := validateV2(server, tx); err != nil { + + if err := validateV2(&server, tx); err != nil { api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) return } @@ -879,12 +1036,17 @@ func createV2(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { server.ID = &id server.LastUpdated = &lastUpdated + if err := createInterfaces(server.ServerNullableV11, tx, *server.IPIsService, *server.IP6IsService); err != nil { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, err) + return + } + alerts := tc.CreateAlerts(tc.SuccessLevel, "Server created") api.WriteAlertsObj(w, r, http.StatusCreated, alerts, server) } func createV3(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { - var server tc.ServerNullableV2 + var server tc.ServerNullable tx := inf.Tx.Tx @@ -893,12 +1055,21 @@ func createV3(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { return } - if err := validateV3(server, tx); err != nil { + serviceInterface, err := validateV3(server, tx) + if err != nil { api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) return } - resultRows, err := inf.Tx.NamedQuery(insertQuery, server) + v2Server, err := server.ToServerV2() + if err != nil { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, err) + return + } + + v2Server.InterfaceName = &serviceInterface + + resultRows, err := inf.Tx.NamedQuery(insertQuery, v2Server) if err != nil { userErr, sysErr, errCode := api.ParseDBError(err) api.HandleErr(w, r, tx, errCode, userErr, sysErr) @@ -907,13 +1078,13 @@ func createV3(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { defer resultRows.Close() - var id int - var lastUpdated tc.TimeNoMod + // var id int + // var lastUpdated tc.TimeNoMod rowsAffected := 0 for resultRows.Next() { rowsAffected++ - if err := resultRows.Scan(&id, &lastUpdated); err != nil { + if err := resultRows.StructScan(&server.CommonServerProperties); err != nil { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("server create scanning: %v", err)) return } @@ -924,8 +1095,73 @@ func createV3(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { } else if rowsAffected > 1 { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, errors.New("too many ids returned from server insert")) } - server.ID = &id - server.LastUpdated = &lastUpdated + // server.ID = &id + // server.LastUpdated = &lastUpdated + + ifaceQry := ` + INSERT INTO interface ( + max_bandwidth, + monitor, + mtu, + name, + server + ) VALUES + ` + ipQry := ` + INSERT INTO ip_address ( + address, + gateway, + interface, + server, + service_address + ) VALUES + ` + + ifaceQueryParts := make([]string, 0, len(server.Interfaces)) + ipQueryParts := make([]string, 0, len(server.Interfaces)) + ifaceArgs := make([]interface{}, 0, len(server.Interfaces)) + ipArgs := make([]interface{}, 0, len(server.Interfaces)) + for i, iface := range server.Interfaces { + argStart := i * 5 + ifaceQueryParts = append(ifaceQueryParts, fmt.Sprintf("($%d, $%d, $%d, $%d, $%d)", argStart+1, argStart+2, argStart+3, argStart+4, argStart+5)) + ifaceArgs = append(ifaceArgs, iface.MaxBandwidth, iface.Monitor, iface.MTU, iface.Name, server.ID) + for _, ip := range iface.IPAddresses { + argStart = len(ipArgs) + ipQueryParts = append(ipQueryParts, fmt.Sprintf("($%d, $%d, $%d, $%d, $%d)", argStart+1, argStart+2, argStart+3, argStart+4, argStart+5)) + ipArgs = append(ipArgs, ip.Address, ip.Gateway, iface.Name, server.ID, ip.ServiceAddress) + } + } + + ifaceQry += strings.Join(ifaceQueryParts, ",") + log.Debugf("Inserting interfaces for new server, query is: %s", ifaceQry) + + ifaceRows, err := tx.Query(ifaceQry, ifaceArgs...) + if err != nil { + log.Debugf("iface err: %v", err) + userErr, sysErr, errCode := api.ParseDBError(err) + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return + } + defer ifaceRows.Close() + insertedIfaces := 0 + for ifaceRows.Next() { + insertedIfaces++ + } + log.Debugf("Inserted %d interfaces", insertedIfaces) + + ipQry += strings.Join(ipQueryParts, ",") + log.Debugf("Inserting IP addresses for new server, query is: %s", ipQry) + + ipRows, err := tx.Query(ipQry, ipArgs...) + if err != nil { + log.Debugf("ip err: %v", err) + userErr, sysErr, errCode := api.ParseDBError(err) + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return + } + defer ipRows.Close() + + log.Debugf("%+v", server.Interfaces) alerts := tc.CreateAlerts(tc.SuccessLevel, "Server created") api.WriteAlertsObj(w, r, http.StatusCreated, alerts, server) @@ -949,18 +1185,16 @@ func Create(w http.ResponseWriter, r *http.Request) { } } -func (s *TOServer) Delete() (error, error, int) { return api.GenericDelete(s) } - -func selectV20UpdatesQuery() string { - return `SELECT -sv.ip_address_is_service, -sv.ip6_address_is_service -FROM - server sv` -} - +func Delete(w http.ResponseWriter, r *http.Request) { + inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) + if userErr != nil || sysErr != nil { + api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr) + return + } + defer inf.Close() + ipRows := inf.Tx.Queryx(deleteIPsQuery, inf.IntParams["id"]) -func deleteQuery() string { - return `DELETE FROM server WHERE id = :id` + var csp tc.CommonServerProperties + if err := inf.Tx.QueryRowx(deleteIPsQuery) } From 85b295db53e5b9edc0c04fdf1d2829f3852e8bdc Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 11 May 2020 16:07:43 -0600 Subject: [PATCH 06/87] Implemented DELETE --- .../traffic_ops_golang/routing/routes.go | 6 +- .../traffic_ops_golang/server/servers.go | 128 +++++++++--------- 2 files changed, 66 insertions(+), 68 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/routing/routes.go b/traffic_ops/traffic_ops_golang/routing/routes.go index db33b1ed5e..b00c51e957 100644 --- a/traffic_ops/traffic_ops_golang/routing/routes.go +++ b/traffic_ops/traffic_ops_golang/routing/routes.go @@ -322,7 +322,7 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) { {api.Version{3, 0}, http.MethodGet, `servers/?$`, server.Read, auth.PrivLevelReadOnly, Authenticated, nil, 27209592853, noPerlBypass}, {api.Version{3, 0}, http.MethodPut, `servers/{id}$`, server.Update, auth.PrivLevelOperations, Authenticated, nil, 2586341033, noPerlBypass}, {api.Version{3, 0}, http.MethodPost, `servers/?$`, server.Create, auth.PrivLevelOperations, Authenticated, nil, 22255580613, noPerlBypass}, - {api.Version{3, 0}, http.MethodDelete, `servers/{id}$`, api.DeleteHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 2923222333, noPerlBypass}, + {api.Version{3, 0}, http.MethodDelete, `servers/{id}$`, server.Delete, auth.PrivLevelOperations, Authenticated, nil, 2923222333, noPerlBypass}, //Server Capability {api.Version{3, 0}, http.MethodGet, `server_capabilities$`, api.ReadHandler(&servercapability.TOServerCapability{}), auth.PrivLevelReadOnly, Authenticated, nil, 2104073913, noPerlBypass}, @@ -686,7 +686,7 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) { {api.Version{2, 0}, http.MethodGet, `servers/?$`, server.Read, auth.PrivLevelReadOnly, Authenticated, nil, 2720959285, noPerlBypass}, {api.Version{2, 0}, http.MethodPut, `servers/{id}$`, server.Update, auth.PrivLevelOperations, Authenticated, nil, 258634103, noPerlBypass}, {api.Version{2, 0}, http.MethodPost, `servers/?$`, server.Create, auth.PrivLevelOperations, Authenticated, nil, 2225558061, noPerlBypass}, - {api.Version{2, 0}, http.MethodDelete, `servers/{id}$`, api.DeleteHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 292322233, noPerlBypass}, + {api.Version{2, 0}, http.MethodDelete, `servers/{id}$`, server.Delete, auth.PrivLevelOperations, Authenticated, nil, 292322233, noPerlBypass}, //Server Capability {api.Version{2, 0}, http.MethodGet, `server_capabilities$`, api.ReadHandler(&servercapability.TOServerCapability{}), auth.PrivLevelReadOnly, Authenticated, nil, 210407391, noPerlBypass}, @@ -1084,7 +1084,7 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) { {api.Version{1, 1}, http.MethodGet, `servers/{id}$`, server.ReadID, auth.PrivLevelReadOnly, Authenticated, nil, 1543122028, noPerlBypass}, {api.Version{1, 1}, http.MethodPut, `servers/{id}$`, server.Update, auth.PrivLevelOperations, Authenticated, nil, 958634103, noPerlBypass}, {api.Version{1, 1}, http.MethodPost, `servers/?$`, server.Create, auth.PrivLevelOperations, Authenticated, nil, 2025558061, noPerlBypass}, - {api.Version{1, 1}, http.MethodDelete, `servers/{id}$`, api.DeleteHandler(&server.TOServer{}), auth.PrivLevelOperations, Authenticated, nil, 192322233, noPerlBypass}, + {api.Version{1, 1}, http.MethodDelete, `servers/{id}$`, server.Delete, auth.PrivLevelOperations, Authenticated, nil, 192322233, noPerlBypass}, //Server Capability {api.Version{1, 4}, http.MethodGet, `server_capabilities$`, api.ReadHandler(&servercapability.TOServerCapability{}), auth.PrivLevelReadOnly, Authenticated, nil, 610407391, noPerlBypass}, diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 5629869f28..e9198c08f0 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -281,66 +281,9 @@ WHERE id=:id RETURNING last_updated ` -const deleteServerQuery = ` -DELETE FROM server -WHERE id=$1 -RETURNING - (SELECT name FROM cachegroup WHERE cachegroup.id=server.cachegroup) AS cachegroup, - cachegroup AS cachegroup_id, - cdn_id, - (SELECT name FROM cdn WHERE cdn.id=server.cdn_id) AS cdn_name, - domain_name, - guid, - host_name, - https_port, - id, - ilo_ip_address, - ilo_ip_gateway, - ilo_ip_netmask, - ilo_password, - ilo_username, - last_updated, - mgmt_ip_address, - mgmt_ip_gateway, - mgmt_ip_netmask, - offline_reason, - (SELECT name FROM phys_location WHERE phys_location.id=server.phys_location) AS phys_location, - phys_location AS phys_location_id, - profile AS profile_id, - (SELECT description FROM profile WHERE profile.id=server.profile) AS profile_desc, - (SELECT name FROM profile WHERE profile.id=server.profile) AS profile, - rack, - reval_pending, - router_host_name, - router_port_name, - (SELECT name FROM status WHERE status.id=server.status) AS status, - status AS status_id, - tcp_port, - (SELECT name FROM type WHERE type.id=server.type) AS server_type, - type AS server_type_id, - upd_pending -` - -const deleteInterfacesQuery = ` -DELETE FROM interface -WHERE server=$1 -RETURNING - max_bandwidth, - monitor, - mtu, - name -` -const deleteIPsQuery = ` -DELETE FROM ip_address -WHERE server = $1 -RETURNING - address, - gateway, - interface, - serviceAddress -` - -func (*TOServer) DeleteQuery() string { return deleteQuery() } +const deleteServerQuery = `DELETE FROM server WHERE id=$1` +const deleteInterfacesQuery = `DELETE FROM interface WHERE server=$1` +const deleteIPsQuery = `DELETE FROM ip_address WHERE server = $1` func validateCommon(s tc.CommonServerProperties, tx *sql.Tx) []error { if s.XMPPID == nil || *s.XMPPID == "" { @@ -1186,15 +1129,70 @@ func Create(w http.ResponseWriter, r *http.Request) { } func Delete(w http.ResponseWriter, r *http.Request) { - inf, userErr, sysErr, errCode := api.NewInfo(r, nil, []string{"id"}) + inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"id"}, []string{"id"}) + tx := inf.Tx.Tx if userErr != nil || sysErr != nil { - api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr) + api.HandleErr(w, r, tx, errCode, userErr, sysErr) return } defer inf.Close() - ipRows := inf.Tx.Queryx(deleteIPsQuery, inf.IntParams["id"]) + id := inf.IntParams["id"] + + var servers []tc.ServerNullable + servers, _, userErr, sysErr, errCode = getServers(map[string]string{"id": inf.Params["id"]}, inf.Tx, inf.User) + if userErr != nil || sysErr != nil { + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return + } + + if len(servers) < 1 { + api.HandleErr(w, r, tx, http.StatusNotFound, fmt.Errorf("No server exists by id #%d", id), nil) + return + } + if len(servers) > 1 { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("There are somehow two servers with id %d - cannot delete", id)) + return + } + + if err := tx.QueryRow(deleteIPsQuery, id).Scan(); err != nil && err != sql.ErrNoRows { + userErr, sysErr, errCode = api.ParseDBError(err) + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return + } + + if err := tx.QueryRow(deleteInterfacesQuery, id).Scan(); err != nil && err != sql.ErrNoRows { + userErr, sysErr, errCode = api.ParseDBError(err) + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return + } + + if err := tx.QueryRow(deleteServerQuery, id).Scan(); err != nil && err != sql.ErrNoRows { + userErr, sysErr, errCode = api.ParseDBError(err) + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return + } + + server := servers[0] + + + + + if inf.Version.Major >= 3 { + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server deleted", server) + return + } + + serverV2, err := server.ToServerV2() + if err != nil { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, err) + return + } + + if inf.Version.Major <= 1 { + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server deleted", serverV2.ServerNullableV11) + return + } - var csp tc.CommonServerProperties - if err := inf.Tx.QueryRowx(deleteIPsQuery) + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server deleted", serverV2) } From e116f08212952238830e2eac5153e349efdbd833 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 11 May 2020 16:32:13 -0600 Subject: [PATCH 07/87] Added netmask parsing and changelogs --- .../traffic_ops_golang/server/servers.go | 49 +++++++++++++------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index e9198c08f0..37d5e7eb5f 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -866,7 +866,17 @@ func createInterfaces(s tc.ServerNullableV11, tx *sql.Tx, ipv4IsService, ipv6IsS if s.IPGateway != nil && *s.IPGateway == "" { s.IPGateway = nil } - if err := tx.QueryRow(insertIPQuery, *s.IPAddress, s.IPGateway, *s.InterfaceName, uint64(*s.ID), ipv4IsService).Scan(); err != nil && err != sql.ErrNoRows { + + ipStr := *s.IPAddress + if s.IPNetmask != nil && *s.IPNetmask != "" { + mask := net.ParseIP(*s.IPNetmask).To4() + if mask == nil { + return fmt.Errorf("Failed to parse netmask '%s'", *s.IPNetmask) + } + cidr, _ := net.IPv4Mask(mask[0], mask[1], mask[2], mask[3]).Size() + ipStr = fmt.Sprintf("%s/%d", ipStr, cidr) + } + if err := tx.QueryRow(insertIPQuery, ipStr, s.IPGateway, *s.InterfaceName, uint64(*s.ID), ipv4IsService).Scan(); err != nil && err != sql.ErrNoRows { return fmt.Errorf("Inserting legacy IPv4 address: %v", err) } } @@ -932,6 +942,9 @@ func createV1(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { alerts := tc.CreateAlerts(tc.SuccessLevel, "Server created") api.WriteAlertsObj(w, r, http.StatusCreated, alerts, server) + + changeLogMsg := fmt.Sprintf("SERVER: %s, ID: %d, ACTION: created", *server.HostName, *server.DomainName, *server.ID) + api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx) } func createV2(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { @@ -986,6 +999,9 @@ func createV2(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { alerts := tc.CreateAlerts(tc.SuccessLevel, "Server created") api.WriteAlertsObj(w, r, http.StatusCreated, alerts, server) + + changeLogMsg := fmt.Sprintf("SERVER: %s, ID: %d, ACTION: created", *server.HostName, *server.DomainName, *server.ID) + api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx) } func createV3(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { @@ -1108,6 +1124,9 @@ func createV3(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { alerts := tc.CreateAlerts(tc.SuccessLevel, "Server created") api.WriteAlertsObj(w, r, http.StatusCreated, alerts, server) + + changeLogMsg := fmt.Sprintf("SERVER: %s, ID: %d, ACTION: created", *server.HostName, *server.DomainName, *server.ID) + api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx) } func Create(w http.ResponseWriter, r *http.Request) { @@ -1175,24 +1194,22 @@ func Delete(w http.ResponseWriter, r *http.Request) { server := servers[0] - - - if inf.Version.Major >= 3 { api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server deleted", server) - return - } + } else { - serverV2, err := server.ToServerV2() - if err != nil { - api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, err) - return - } + serverV2, err := server.ToServerV2() + if err != nil { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, err) + return + } - if inf.Version.Major <= 1 { - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server deleted", serverV2.ServerNullableV11) - return + if inf.Version.Major <= 1 { + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server deleted", serverV2.ServerNullableV11) + } else { + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server deleted", serverV2) + } } - - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server deleted", serverV2) + changeLogMsg := fmt.Sprintf("SERVER: %s, ID: %d, ACTION: deleted", *server.HostName, *server.DomainName, *server.ID) + api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx) } From 99a6f87a98571220990b79710260093f23677d25 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 11 May 2020 19:09:15 -0600 Subject: [PATCH 08/87] Added method for converting legacy data to interface arrays --- lib/go-tc/servers.go | 122 +++++++++++++++++++------------------------ 1 file changed, 53 insertions(+), 69 deletions(-) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index f8a5e3acc1..ed6ee53df2 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -3,6 +3,7 @@ package tc import ( "database/sql/driver" "encoding/json" + "errors" "fmt" "net" "time" @@ -104,75 +105,6 @@ func (sii *ServerInterfaceInfo) Scan(src interface{}) error { return json.Unmarshal([]byte(b), sii) } -// Scan implements the sql.Scanner interface -// expects json.RawMessage and unmarshals to a deliveryservice struct -// func (sii *ServerInterfaceInfo) Scan(src interface{}) error { -// b, ok := src.([]byte) -// if !ok { -// return fmt.Errorf("expected deliveryservice in byte array form; got %T", src) -// } -// log.Debugf(string(b)) -// log.Debugf(fmt.Sprintf("%v", b)) - -// start := bytes.Index(b, []byte("\"")) -// if start < 0 { -// return errors.New("expected a '\"' to indicate beginning of array") -// } -// end := bytes.LastIndex(b, []byte("\"")) -// if end < 0 { -// return errors.New("expected a '\"' to indicate end of array") -// } -// if start >= end { -// return errors.New("expected a '\"' at the beginning and end of the array") -// } - -// log.Debugf("start=%d, end=%d", start, end) - -// var ips []ServerIpAddress -// if err := pq.Array(&ips).Scan(b[start+1:end]); err != nil { -// return fmt.Errorf("Scanning IP address array: %v", err) -// } - -// sii.IpAddresses = ips - -// rest := bytes.Split(b[end+1:], []byte(",")) -// if len(rest) != 4 { -// return fmt.Errorf("Expected 4 values to parse after ips, got %d (%v)", len(rest), rest) -// } - -// if len(rest[0]) == 0 { -// sii.MaxBandwidth = nil -// } else if mb, err := strconv.ParseInt(string(rest[0]), 10, 64); err != nil { -// return fmt.Errorf("Parsing max bandwidth: %v", err) -// } else { -// sii.MaxBandwidth = &mb -// } - -// if len(rest[1]) != 1 { -// return fmt.Errorf("Unknown boolean value encountered parsing 'monitor': %v", rest[1]) -// } -// if rest[1][0] == []byte("t")[0] { -// sii.Monitor = true -// } else if rest[1][0] == []byte("f")[0] { -// sii.Monitor = false -// } else { -// return fmt.Errorf("Unknown boolean value encountered parsing 'monitor': %v", rest[1]) -// } - -// if len(rest[2]) == 0 { -// sii.MTU = nil -// } else if mtu, err := strconv.ParseUint(string(rest[2]), 10, 64); err != nil { -// return fmt.Errorf("Parsing MTU: %v", err) -// } else { -// sii.MTU = &mtu -// } - -// sii.Name = string(bytes.TrimRight(rest[3], ")")) - -// // return json.Unmarshal([]byte(b), sii) -// return nil -// } - // LegacyInterfaceDetails is the details for interfaces on servers for API v1 and v2. type LegacyInterfaceDetails struct { InterfaceMtu *int `json:"interfaceMtu" db:"interface_mtu"` @@ -184,6 +116,57 @@ type LegacyInterfaceDetails struct { IPNetmask *string `json:"ipNetmask" db:"ip_netmask"` } +func (lid *LegacyInterfaceDetails) ToInterfaces(ipv4IsService, ipv6IsService bool) ([]ServerInterfaceInfo, error) { + var iface ServerInterfaceInfo + if lid.InterfaceMtu == nil { + return nil, errors.New("interfaceMtu is null") + } + mtu := uint64(*lid.InterfaceMtu) + iface.MTU = &mtu + + if lid.InterfaceName == nil { + return nil, errors.New("interfaceName is null") + } + iface.Name = *lid.InterfaceName + + var ips []ServerIpAddress + if lid.IPAddress != nil && *lid.IPAddress != "" { + if lid.IPGateway != nil && *lid.IPGateway == "" { + lid.IPGateway = nil + } + + ipStr := *lid.IPAddress + if lid.IPNetmask != nil && *lid.IPNetmask != "" { + mask := net.ParseIP(*lid.IPNetmask).To4() + if mask == nil { + return nil, fmt.Errorf("Failed to parse netmask '%s'", *lid.IPNetmask) + } + cidr, _ := net.IPv4Mask(mask[0], mask[1], mask[2], mask[3]).Size() + ipStr = fmt.Sprintf("%s/%d", ipStr, cidr) + } + + ips = append(ips, ServerIpAddress{ + Address: ipStr, + Gateway: lid.IPGateway, + ServiceAddress: ipv4IsService, + }) + } + + if lid.IP6Address != nil && *lid.IP6Address != "" { + if lid.IP6Gateway != nil && *lid.IP6Gateway == "" { + lid.IP6Gateway = nil + } + ips = append(ips, ServerIpAddress{ + Address: *lid.IP6Address, + Gateway: lid.IP6Gateway, + ServiceAddress: ipv6IsService, + }) + } + + iface.IPAddresses = ips + return []ServerInterfaceInfo{iface}, nil +} + // InterfaceInfoToLegacyInterfaces converts a ServerInterfaceInfo to an // equivalent LegacyInterfaceDetails structure. It does this by creating the // IP address fields using the "service" interface's IP addresses. All others @@ -235,6 +218,7 @@ func InterfaceInfoToLegacyInterfaces(serverInterfaces []ServerInterfaceInfo) (Le return legacyDetails, nil } + type Server struct { Cachegroup string `json:"cachegroup" db:"cachegroup"` CachegroupID int `json:"cachegroupId" db:"cachegroup_id"` From f7dbf6125af847858a62045e5d4fd960c479c57a Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 11 May 2020 19:09:35 -0600 Subject: [PATCH 09/87] Implemented PUT --- .../traffic_ops_golang/server/servers.go | 367 +++++++++--------- 1 file changed, 193 insertions(+), 174 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 37d5e7eb5f..28848c6c56 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -522,7 +522,7 @@ func Read(w http.ResponseWriter, r *http.Request) { return } - var servers []tc.ServerNullable + servers := []tc.ServerNullable{} var unfiltered uint64 servers, unfiltered, userErr, sysErr, errCode = getServers(inf.Params, inf.Tx, inf.User) @@ -551,7 +551,6 @@ func Read(w http.ResponseWriter, r *http.Request) { } legacyServers := make([]tc.ServerNullableV11, 0, len(servers)) - log.Debugf("servers len=%d", len(servers)) for _, server := range servers { legacyServer, err := server.ToServerV2() if err != nil { @@ -560,7 +559,6 @@ func Read(w http.ResponseWriter, r *http.Request) { } legacyServers = append(legacyServers, legacyServer.ServerNullableV11) } - log.Debugf("legacyServers len=%d", len(legacyServers)) api.WriteResp(w, r, legacyServers) } @@ -691,7 +689,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( } if s, ok := servers[id]; !ok { - log.Warnf("interfaces query returned interfaces for server #%d that was not in original query") + log.Warnf("interfaces query returned interfaces for server #%d that was not in original query", id) } else { s.Interfaces = ifaces servers[id] = s @@ -762,79 +760,182 @@ WHERE s.id IN (` + edgeIDs + `))) return mids, nil, nil, http.StatusOK } -func Update(w http.ResponseWriter, r *http.Request) { - inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) - if userErr != nil || sysErr != nil { - api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr) - return +func checkTypeChangeSafety(server tc.CommonServerProperties, tx *sqlx.Tx) (error, error, int) { + // see if cdn or type changed + var cdnID int + var typeID int + if err := tx.QueryRow("SELECT type, cdn_id FROM server WHERE id = $1", server.ID).Scan(&typeID, &cdnID); err != nil { + if err == sql.ErrNoRows { + return errors.New("no server found with this ID"), nil, http.StatusNotFound + } + return nil, fmt.Errorf("getting current server type: %v", err), http.StatusInternalServerError } - defer inf.Close() - var server tc.ServerNullableV11 + var dsIDs []int64 + if err := tx.QueryRowx("SELECT ARRAY(SELECT deliveryservice FROM deliveryservice_server WHERE server = $1)", server.ID).Scan(pq.Array(&dsIDs)); err != nil && err != sql.ErrNoRows { + return nil, fmt.Errorf("getting server assigned delivery services: %v", err), http.StatusInternalServerError + } + // If type is changing ensure it isn't assigned to any DSes. + if typeID != *server.TypeID { + if len(dsIDs) != 0 { + return errors.New("server type can not be updated when it is currently assigned to Delivery Services"), nil, http.StatusConflict + } + } + // Check to see if the user is trying to change the CDN of a server, which is already linked with a DS + if cdnID != *server.CDNID && len(dsIDs) != 0 { + return errors.New("server cdn can not be updated when it is currently assigned to delivery services"), nil, http.StatusConflict + } - tx := inf.Tx.Tx + return nil, nil, http.StatusOK +} - if err := json.NewDecoder(r.Body).Decode(&server); err != nil { - api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) - return +func createInterfaces(id int, interfaces []tc.ServerInterfaceInfo, tx *sql.Tx) (error, error, int) { + ifaceQry := ` + INSERT INTO interface ( + max_bandwidth, + monitor, + mtu, + name, + server + ) VALUES + ` + ipQry := ` + INSERT INTO ip_address ( + address, + gateway, + interface, + server, + service_address + ) VALUES + ` + + ifaceQueryParts := make([]string, 0, len(interfaces)) + ipQueryParts := make([]string, 0, len(interfaces)) + ifaceArgs := make([]interface{}, 0, len(interfaces)) + ipArgs := make([]interface{}, 0, len(interfaces)) + for i, iface := range interfaces { + argStart := i * 5 + ifaceQueryParts = append(ifaceQueryParts, fmt.Sprintf("($%d, $%d, $%d, $%d, $%d)", argStart+1, argStart+2, argStart+3, argStart+4, argStart+5)) + ifaceArgs = append(ifaceArgs, iface.MaxBandwidth, iface.Monitor, iface.MTU, iface.Name, id) + for _, ip := range iface.IPAddresses { + argStart = len(ipArgs) + ipQueryParts = append(ipQueryParts, fmt.Sprintf("($%d, $%d, $%d, $%d, $%d)", argStart+1, argStart+2, argStart+3, argStart+4, argStart+5)) + ipArgs = append(ipArgs, ip.Address, ip.Gateway, iface.Name, id, ip.ServiceAddress) + } } - if err := validateV1(server, tx); err != nil { - api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) - return + ifaceQry += strings.Join(ifaceQueryParts, ",") + log.Debugf("Inserting interfaces for new server, query is: %s", ifaceQry) + + ifaceRows, err := tx.Query(ifaceQry, ifaceArgs...) + if err != nil { + return api.ParseDBError(err) } + defer ifaceRows.Close() + insertedIfaces := 0 + for ifaceRows.Next() { + insertedIfaces++ + } + log.Debugf("Inserted %d interfaces", insertedIfaces) - // see if cdn or type changed - var cdnID int - var typeID int + ipQry += strings.Join(ipQueryParts, ",") + log.Debugf("Inserting IP addresses for new server, query is: %s", ipQry) - if err := inf.Tx.QueryRow("SELECT type, cdn_id FROM server WHERE id = $1", server.ID).Scan(&typeID, &cdnID); err != nil { - if err == sql.ErrNoRows { - api.HandleErr(w, r, tx, http.StatusNotFound, errors.New("no server found with this ID"), nil) - return - } - api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("getting current server type: %v", err)) - return + ipRows, err := tx.Query(ipQry, ipArgs...) + if err != nil { + return api.ParseDBError(err) } + defer ipRows.Close() - var dsIDs []int64 - if err := inf.Tx.QueryRowx("SELECT ARRAY(SELECT deliveryservice FROM deliveryservice_server WHERE server = $1)", server.ID).Scan(pq.Array(&dsIDs)); err != nil && err != sql.ErrNoRows { - api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("getting server assigned delivery services: %v", err)) - return + return nil, nil, http.StatusOK +} + +func deleteInterfaces(id int, tx *sql.Tx) (error, error, int) { + if err := tx.QueryRow(deleteIPsQuery, id).Scan(); err != nil && err != sql.ErrNoRows { + return api.ParseDBError(err) } - // Check to see if the user is trying to change the CDN of a server, which is already linked with a DS - if cdnID != *server.CDNID && len(dsIDs) != 0 { - api.HandleErr(w, r, tx, http.StatusConflict, errors.New("server cdn can not be updated when it is currently assigned to delivery services"), nil) + + if err := tx.QueryRow(deleteInterfacesQuery, id).Scan(); err != nil && err != sql.ErrNoRows { + return api.ParseDBError(err) + } + + return nil, nil, http.StatusOK +} + +func Update(w http.ResponseWriter, r *http.Request) { + inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"id"}, []string{"id"}) + tx := inf.Tx.Tx + if userErr != nil || sysErr != nil { + api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr) return } - // If type is changing ensure it isn't assigned to any DSes. - if typeID != *server.TypeID { - if len(dsIDs) != 0 { - api.HandleErr(w, r, tx, http.StatusConflict, errors.New("server type can not be updated when it is currently assigned to Delivery Services"), nil) + defer inf.Close() + + + var server tc.ServerNullableV2 + var interfaces []tc.ServerInterfaceInfo + if inf.Version.Major >= 3 { + var newServer tc.ServerNullable + if err := json.NewDecoder(r.Body).Decode(&newServer); err != nil { + api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) + return + } + serviceInterface, err := validateV3(newServer, tx) + if err != nil { + api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) + return + } + + server, err = newServer.ToServerV2() + if err != nil { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Converting v3 server to v2 for update: %v", err)) + return + } + server.InterfaceName = util.StrPtr(serviceInterface) + interfaces = newServer.Interfaces + } else if inf.Version.Major == 2 { + if err := json.NewDecoder(r.Body).Decode(&server); err != nil { + api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) return } + + err := validateV2(&server, tx) + if err != nil { + api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) + return + } + interfaces, err = server.LegacyInterfaceDetails.ToInterfaces(*server.IPIsService, *server.IP6IsService) + if err != nil { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Converting server legacy interfaces to interface array: %v", err)) + } + } else { + var legacyServer tc.ServerNullableV11 + if err := json.NewDecoder(r.Body).Decode(&legacyServer); err != nil { + api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) + return + } + + err := validateV1(legacyServer, tx) + if err != nil { + api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) + return + } + + interfaces, err = server.LegacyInterfaceDetails.ToInterfaces(true, true) + if err != nil { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Converting server legacy interfaces to interface array: %v", err)) + } + server = tc.ServerNullableV2{ + ServerNullableV11: legacyServer, + IPIsService: util.BoolPtr(true), + IP6IsService: util.BoolPtr(true), + } } - // current := TOServer{} - // err := inf.Tx.QueryRowx(selectV20UpdatesQuery()+` WHERE sv.id=$1`, strconv.Itoa(*s.ID)).StructScan(¤t) - // if err != nil { - // return api.ParseDBError(err) - // } - // defaultIsService := true - // if s.IPIsService == nil { - // if current.IPIsService != nil { - // s.IPIsService = current.IPIsService - // } else { - // s.IPIsService = &defaultIsService - // } - // } - // if s.IP6IsService == nil { - // if current.IP6IsService != nil { - // s.IP6IsService = current.IP6IsService - // } else { - // s.IP6IsService = &defaultIsService - // } - // } + if userErr, sysErr, errCode = checkTypeChangeSafety(server.CommonServerProperties, inf.Tx); userErr != nil || sysErr != nil { + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return + } rows, err := inf.Tx.NamedQuery(updateQuery, server) if err != nil { @@ -854,43 +955,26 @@ func Update(w http.ResponseWriter, r *http.Request) { } server.LastUpdated = &lastUpdated - api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server updated", server) -} - -func createInterfaces(s tc.ServerNullableV11, tx *sql.Tx, ipv4IsService, ipv6IsService bool) error { - if err := tx.QueryRow(insertInterfaceQuery, nil, true, s.InterfaceMtu, s.InterfaceName, s.ID).Scan(); err != nil && err != sql.ErrNoRows { - return fmt.Errorf("Inserting legacy interface: %v", err) + if userErr, sysErr, errCode = deleteInterfaces(inf.IntParams["id"], tx); userErr != nil || sysErr != nil { + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return } - if s.IPAddress != nil && *s.IPAddress != "" { - if s.IPGateway != nil && *s.IPGateway == "" { - s.IPGateway = nil - } - - ipStr := *s.IPAddress - if s.IPNetmask != nil && *s.IPNetmask != "" { - mask := net.ParseIP(*s.IPNetmask).To4() - if mask == nil { - return fmt.Errorf("Failed to parse netmask '%s'", *s.IPNetmask) - } - cidr, _ := net.IPv4Mask(mask[0], mask[1], mask[2], mask[3]).Size() - ipStr = fmt.Sprintf("%s/%d", ipStr, cidr) - } - if err := tx.QueryRow(insertIPQuery, ipStr, s.IPGateway, *s.InterfaceName, uint64(*s.ID), ipv4IsService).Scan(); err != nil && err != sql.ErrNoRows { - return fmt.Errorf("Inserting legacy IPv4 address: %v", err) - } + if userErr, sysErr, errCode = createInterfaces(inf.IntParams["id"], interfaces, tx); userErr != nil || sysErr != nil { + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return } - if s.IP6Address != nil && *s.IP6Address != "" { - if s.IP6Gateway != nil && *s.IP6Gateway == "" { - s.IP6Gateway = nil - } - if err := tx.QueryRow(insertIPQuery, *s.IP6Address, s.IP6Gateway, *s.InterfaceName, uint64(*s.ID), ipv6IsService).Scan(); err != nil && err != sql.ErrNoRows { - return fmt.Errorf("Inserting legacy IPv6 address: %v", err) - } + if inf.Version.Major >= 3 { + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server updated", tc.ServerNullable{CommonServerProperties: server.CommonServerProperties, Interfaces: interfaces}) + } else if inf.Version.Minor <= 1 { + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server updated", server.ServerNullableV11) + } else { + api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server updated", server) } - return nil + changeLogMsg := fmt.Sprintf("SERVER: %s.%s, ID: %d, ACTION: updated", *server.HostName, *server.DomainName, *server.ID) + api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx) } func createV1(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { @@ -936,14 +1020,20 @@ func createV1(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { server.ID = &id server.LastUpdated = &lastUpdated - if err := createInterfaces(server, tx, true, true); err != nil { + ifaces, err := server.LegacyInterfaceDetails.ToInterfaces(true, true) + if err != nil { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, err) } + if userErr, sysErr, errCode := createInterfaces(id, ifaces, tx); err != nil { + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return + } + alerts := tc.CreateAlerts(tc.SuccessLevel, "Server created") api.WriteAlertsObj(w, r, http.StatusCreated, alerts, server) - changeLogMsg := fmt.Sprintf("SERVER: %s, ID: %d, ACTION: created", *server.HostName, *server.DomainName, *server.ID) + changeLogMsg := fmt.Sprintf("SERVER: %s.%s, ID: %d, ACTION: created", *server.HostName, *server.DomainName, *server.ID) api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx) } @@ -992,15 +1082,20 @@ func createV2(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { server.ID = &id server.LastUpdated = &lastUpdated - if err := createInterfaces(server.ServerNullableV11, tx, *server.IPIsService, *server.IP6IsService); err != nil { + ifaces, err := server.LegacyInterfaceDetails.ToInterfaces(*server.IPIsService, *server.IP6IsService) + if err != nil { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, err) + } + + if userErr, sysErr, errCode := createInterfaces(id, ifaces, tx); err != nil { + api.HandleErr(w, r, tx, errCode, userErr, sysErr) return } alerts := tc.CreateAlerts(tc.SuccessLevel, "Server created") api.WriteAlertsObj(w, r, http.StatusCreated, alerts, server) - changeLogMsg := fmt.Sprintf("SERVER: %s, ID: %d, ACTION: created", *server.HostName, *server.DomainName, *server.ID) + changeLogMsg := fmt.Sprintf("SERVER: %s.%s, ID: %d, ACTION: created", *server.HostName, *server.DomainName, *server.ID) api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx) } @@ -1036,10 +1131,6 @@ func createV3(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { } defer resultRows.Close() - - // var id int - // var lastUpdated tc.TimeNoMod - rowsAffected := 0 for resultRows.Next() { rowsAffected++ @@ -1053,79 +1144,19 @@ func createV3(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { return } else if rowsAffected > 1 { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, errors.New("too many ids returned from server insert")) - } - // server.ID = &id - // server.LastUpdated = &lastUpdated - - ifaceQry := ` - INSERT INTO interface ( - max_bandwidth, - monitor, - mtu, - name, - server - ) VALUES - ` - ipQry := ` - INSERT INTO ip_address ( - address, - gateway, - interface, - server, - service_address - ) VALUES - ` - - ifaceQueryParts := make([]string, 0, len(server.Interfaces)) - ipQueryParts := make([]string, 0, len(server.Interfaces)) - ifaceArgs := make([]interface{}, 0, len(server.Interfaces)) - ipArgs := make([]interface{}, 0, len(server.Interfaces)) - for i, iface := range server.Interfaces { - argStart := i * 5 - ifaceQueryParts = append(ifaceQueryParts, fmt.Sprintf("($%d, $%d, $%d, $%d, $%d)", argStart+1, argStart+2, argStart+3, argStart+4, argStart+5)) - ifaceArgs = append(ifaceArgs, iface.MaxBandwidth, iface.Monitor, iface.MTU, iface.Name, server.ID) - for _, ip := range iface.IPAddresses { - argStart = len(ipArgs) - ipQueryParts = append(ipQueryParts, fmt.Sprintf("($%d, $%d, $%d, $%d, $%d)", argStart+1, argStart+2, argStart+3, argStart+4, argStart+5)) - ipArgs = append(ipArgs, ip.Address, ip.Gateway, iface.Name, server.ID, ip.ServiceAddress) - } - } - - ifaceQry += strings.Join(ifaceQueryParts, ",") - log.Debugf("Inserting interfaces for new server, query is: %s", ifaceQry) - - ifaceRows, err := tx.Query(ifaceQry, ifaceArgs...) - if err != nil { - log.Debugf("iface err: %v", err) - userErr, sysErr, errCode := api.ParseDBError(err) - api.HandleErr(w, r, tx, errCode, userErr, sysErr) return } - defer ifaceRows.Close() - insertedIfaces := 0 - for ifaceRows.Next() { - insertedIfaces++ - } - log.Debugf("Inserted %d interfaces", insertedIfaces) - ipQry += strings.Join(ipQueryParts, ",") - log.Debugf("Inserting IP addresses for new server, query is: %s", ipQry) - - ipRows, err := tx.Query(ipQry, ipArgs...) - if err != nil { - log.Debugf("ip err: %v", err) - userErr, sysErr, errCode := api.ParseDBError(err) + userErr, sysErr, errCode := createInterfaces(*server.ID, server.Interfaces, tx) + if userErr != nil || sysErr != nil { api.HandleErr(w, r, tx, errCode, userErr, sysErr) return } - defer ipRows.Close() - - log.Debugf("%+v", server.Interfaces) alerts := tc.CreateAlerts(tc.SuccessLevel, "Server created") api.WriteAlertsObj(w, r, http.StatusCreated, alerts, server) - changeLogMsg := fmt.Sprintf("SERVER: %s, ID: %d, ACTION: created", *server.HostName, *server.DomainName, *server.ID) + changeLogMsg := fmt.Sprintf("SERVER: %s.%s, ID: %d, ACTION: created", *server.HostName, *server.DomainName, *server.ID) api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx) } @@ -1174,18 +1205,6 @@ func Delete(w http.ResponseWriter, r *http.Request) { return } - if err := tx.QueryRow(deleteIPsQuery, id).Scan(); err != nil && err != sql.ErrNoRows { - userErr, sysErr, errCode = api.ParseDBError(err) - api.HandleErr(w, r, tx, errCode, userErr, sysErr) - return - } - - if err := tx.QueryRow(deleteInterfacesQuery, id).Scan(); err != nil && err != sql.ErrNoRows { - userErr, sysErr, errCode = api.ParseDBError(err) - api.HandleErr(w, r, tx, errCode, userErr, sysErr) - return - } - if err := tx.QueryRow(deleteServerQuery, id).Scan(); err != nil && err != sql.ErrNoRows { userErr, sysErr, errCode = api.ParseDBError(err) api.HandleErr(w, r, tx, errCode, userErr, sysErr) @@ -1210,6 +1229,6 @@ func Delete(w http.ResponseWriter, r *http.Request) { api.WriteRespAlertObj(w, r, tc.SuccessLevel, "Server deleted", serverV2) } } - changeLogMsg := fmt.Sprintf("SERVER: %s, ID: %d, ACTION: deleted", *server.HostName, *server.DomainName, *server.ID) + changeLogMsg := fmt.Sprintf("SERVER: %s.%s, ID: %d, ACTION: deleted", *server.HostName, *server.DomainName, *server.ID) api.CreateChangeLogRawTx(api.ApiChange, changeLogMsg, inf.User, tx) } From 9f2c5a4b7c9f6af87aad94ce908699a136aa482d Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 12 May 2020 08:56:58 -0600 Subject: [PATCH 10/87] Fixed a couple unit tests --- .../traffic_ops_golang/server/servers_test.go | 99 +++++++++++++------ 1 file changed, 67 insertions(+), 32 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers_test.go b/traffic_ops/traffic_ops_golang/server/servers_test.go index a8c91f2ec6..3f8e18bcb3 100644 --- a/traffic_ops/traffic_ops_golang/server/servers_test.go +++ b/traffic_ops/traffic_ops_golang/server/servers_test.go @@ -33,8 +33,13 @@ import ( "gopkg.in/DATA-DOG/go-sqlmock.v1" ) -func getTestServers() []tc.Server { - servers := []tc.Server{} +type ServerAndInterfaces struct { + Server tc.Server + Interfaces []tc.ServerInterfaceInfo +} + +func getTestServers() []ServerAndInterfaces { + servers := []ServerAndInterfaces{} testServer := tc.Server{ Cachegroup: "Cachegroup", CachegroupID: 1, @@ -82,17 +87,37 @@ func getTestServers() []tc.Server { XMPPID: "xmppId", XMPPPasswd: "xmppPasswd", } - servers = append(servers, testServer) + + mtu := uint64(testServer.InterfaceMtu) + + interfaces := []tc.ServerInterfaceInfo{ + tc.ServerInterfaceInfo{ + IPAddresses: []tc.ServerIpAddress{ + tc.ServerIpAddress{ + Address: testServer.IPAddress, + Gateway: &testServer.IPGateway, + ServiceAddress: testServer.IPIsService, + }, + }, + MaxBandwidth: nil, + Monitor: true, + MTU: &mtu, + Name: testServer.InterfaceName, + }, + } + servers = append(servers, ServerAndInterfaces{Server: testServer, Interfaces: interfaces}) testServer2 := testServer testServer2.Cachegroup = "cachegroup2" testServer2.HostName = "server2" - servers = append(servers, testServer2) + testServer2.ID = 2 + servers = append(servers, ServerAndInterfaces{Server: testServer2, Interfaces: interfaces}) testServer3 := testServer testServer3.Cachegroup = "cachegroup3" testServer3.HostName = "server3" - servers = append(servers, testServer2) + testServer3.ID = 3 + servers = append(servers, ServerAndInterfaces{Server: testServer3, Interfaces: interfaces}) return servers } @@ -167,12 +192,19 @@ func TestGetServersByCachegroup(t *testing.T) { defer db.Close() testServers := getTestServers() - cols := test.ColsFromStructByTag("db", tc.Server{}) + + unfilteredCols := []string{"count"} + unfilteredRows := sqlmock.NewRows(unfilteredCols).AddRow(len(testServers)) + + cols := test.ColsFromStructByTag("db", tc.CommonServerProperties{}) + interfaceCols := []string{"interfaces", "id"} rows := sqlmock.NewRows(cols) + interfaceRows := sqlmock.NewRows(interfaceCols) //TODO: drichardson - build helper to add these Rows from the struct values // or by CSV if types get in the way - for _, ts := range testServers { + for _, srv := range testServers { + ts := srv.Server rows = rows.AddRow( ts.Cachegroup, ts.CachegroupID, @@ -188,15 +220,6 @@ func TestGetServersByCachegroup(t *testing.T) { ts.ILOIPNetmask, ts.ILOPassword, ts.ILOUsername, - ts.InterfaceMtu, - ts.InterfaceName, - ts.IP6Address, - ts.IP6IsService, - ts.IP6Gateway, - ts.IPAddress, - ts.IPIsService, - ts.IPNetmask, - ts.IPGateway, ts.LastUpdated, ts.MgmtIPAddress, ts.MgmtIPGateway, @@ -220,14 +243,23 @@ func TestGetServersByCachegroup(t *testing.T) { ts.XMPPID, ts.XMPPPasswd, ) + interfaceRows = interfaceRows.AddRow( + srv.Interfaces, + ts.ID, + ) } + + mock.ExpectBegin() + mock.ExpectQuery("SELECT COUNT\\(server.id\\) FROM server").WillReturnRows(unfilteredRows) mock.ExpectQuery("SELECT").WillReturnRows(rows) + mock.ExpectQuery("SELECT").WillReturnRows(interfaceRows) + v := map[string]string{"cachegroup": "2"} user := auth.CurrentUser{} - servers, userErr, sysErr, errCode := getServers(v, db.MustBegin(), &user) + servers, _, userErr, sysErr, errCode := getServers(v, db.MustBegin(), &user) if userErr != nil || sysErr != nil { t.Errorf("getServers expected: no errors, actual: %v %v with status: %s", userErr, sysErr, http.StatusText(errCode)) } @@ -251,14 +283,20 @@ func TestGetMidServers(t *testing.T) { testServers := getTestServers() testServers = testServers[0:2] - testServers[1].Cachegroup = "parentCacheGroup" - testServers[1].CachegroupID = 2 - testServers[1].Type = "MID" + testServers[1].Server.Cachegroup = "parentCacheGroup" + testServers[1].Server.CachegroupID = 2 + testServers[1].Server.Type = "MID" - cols := test.ColsFromStructByTag("db", tc.Server{}) + unfilteredCols := []string{"count"} + unfilteredRows := sqlmock.NewRows(unfilteredCols).AddRow(len(testServers)) + + cols := test.ColsFromStructByTag("db", tc.CommonServerProperties{}) + interfaceCols := []string{"interfaces", "id"} rows := sqlmock.NewRows(cols) + interfaceRows := sqlmock.NewRows(interfaceCols) - for _, ts := range testServers { + for _, srv := range testServers { + ts := srv.Server rows = rows.AddRow( ts.Cachegroup, ts.CachegroupID, @@ -306,14 +344,20 @@ func TestGetMidServers(t *testing.T) { ts.XMPPID, ts.XMPPPasswd, ) + interfaceRows = interfaceRows.AddRow( + srv.Interfaces, + ts.ID, + ) } mock.ExpectBegin() + mock.ExpectQuery("SELECT COUNT\\(server.id\\) FROM server").WillReturnRows(unfilteredRows) mock.ExpectQuery("SELECT").WillReturnRows(rows) + mock.ExpectQuery("SELECT").WillReturnRows(interfaceRows) v := map[string]string{} user := auth.CurrentUser{} - servers, userErr, sysErr, errCode := getServers(v, db.MustBegin(), &user) + servers, _, userErr, sysErr, errCode := getServers(v, db.MustBegin(), &user) if userErr != nil || sysErr != nil { t.Errorf("getServers expected: no errors, actual: %v %v with status: %s", userErr, sysErr, http.StatusText(errCode)) @@ -381,15 +425,6 @@ func TestGetMidServers(t *testing.T) { ts.ILOIPNetmask, ts.ILOPassword, ts.ILOUsername, - ts.InterfaceMtu, - ts.InterfaceName, - ts.IP6Address, - ts.IP6IsService, - ts.IP6Gateway, - ts.IPAddress, - ts.IPIsService, - ts.IPNetmask, - ts.IPGateway, ts.LastUpdated, ts.MgmtIPAddress, ts.MgmtIPGateway, From d642c548cdc10a1413228fb7c4b66f8c620ea6e2 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 12 May 2020 10:48:22 -0600 Subject: [PATCH 11/87] Finished fixing unit tests --- .../traffic_ops_golang/server/detail_test.go | 8 +- .../traffic_ops_golang/server/servers_test.go | 83 +++++++------------ 2 files changed, 36 insertions(+), 55 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/detail_test.go b/traffic_ops/traffic_ops_golang/server/detail_test.go index d88b4b577b..41fc1d5928 100644 --- a/traffic_ops/traffic_ops_golang/server/detail_test.go +++ b/traffic_ops/traffic_ops_golang/server/detail_test.go @@ -126,16 +126,16 @@ func TestGetDetailServers(t *testing.T) { 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)) + 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) + if !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/traffic_ops_golang/server/servers_test.go b/traffic_ops/traffic_ops_golang/server/servers_test.go index 3f8e18bcb3..0c10ba5209 100644 --- a/traffic_ops/traffic_ops_golang/server/servers_test.go +++ b/traffic_ops/traffic_ops_golang/server/servers_test.go @@ -20,7 +20,6 @@ package server */ import ( - "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" "net/http" "testing" "time" @@ -28,14 +27,14 @@ import ( "github.com/apache/trafficcontrol/lib/go-tc" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/auth" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/test" - "github.com/jmoiron/sqlx" + "github.com/jmoiron/sqlx" "gopkg.in/DATA-DOG/go-sqlmock.v1" ) type ServerAndInterfaces struct { Server tc.Server - Interfaces []tc.ServerInterfaceInfo + Interfaces []byte } func getTestServers() []ServerAndInterfaces { @@ -88,23 +87,27 @@ func getTestServers() []ServerAndInterfaces { XMPPPasswd: "xmppPasswd", } - mtu := uint64(testServer.InterfaceMtu) - - interfaces := []tc.ServerInterfaceInfo{ - tc.ServerInterfaceInfo{ - IPAddresses: []tc.ServerIpAddress{ - tc.ServerIpAddress{ - Address: testServer.IPAddress, - Gateway: &testServer.IPGateway, - ServiceAddress: testServer.IPIsService, - }, - }, - MaxBandwidth: nil, - Monitor: true, - MTU: &mtu, - Name: testServer.InterfaceName, - }, - } + // mtu := uint64(testServer.InterfaceMtu) + + // interfaces := []byte(fmt.Sprintf("{\"{\"ipAddresses\" : [{\"address\" : \"76.0.23.56\", \"gateway\" : null, \"service_address\" : true}], \"max_bandwidth\" : null, \"monitor\" : true, \"mtu\" : 1500, \"name\" : \"eth0\"}\"}", testServer.IPAddress, testServer.InterfaceMtu, testServer.InterfaceName)) + + interfaces := []byte(`{"{\"ipAddresses\" : [{\"address\" : \"76.0.23.56\", \"gateway\" : null, \"service_address\" : true}], \"max_bandwidth\" : null, \"monitor\" : true, \"mtu\" : 1500, \"name\" : \"eth0\"}"}`) + + // interfaces := []tc.ServerInterfaceInfo{ + // tc.ServerInterfaceInfo{ + // IPAddresses: []tc.ServerIpAddress{ + // tc.ServerIpAddress{ + // Address: testServer.IPAddress, + // Gateway: &testServer.IPGateway, + // ServiceAddress: testServer.IPIsService, + // }, + // }, + // MaxBandwidth: nil, + // Monitor: true, + // MTU: &mtu, + // Name: testServer.InterfaceName, + // }, + // } servers = append(servers, ServerAndInterfaces{Server: testServer, Interfaces: interfaces}) testServer2 := testServer @@ -137,7 +140,7 @@ func TestUpdateServer(t *testing.T) { rows := sqlmock.NewRows([]string{"type", "cdn_id"}) // note here that the cdnid is 5, which is not the same as the initial cdnid of the fist traffic server - rows.AddRow(testServers[0].TypeID, 5) + rows.AddRow(testServers[0].Server.TypeID, 5) // Make it return a list of atleast one associated ds dsrows := sqlmock.NewRows([]string{"array"}) dsrows.AddRow("{3}") @@ -146,32 +149,19 @@ func TestUpdateServer(t *testing.T) { mock.ExpectQuery("SELECT ARRAY").WillReturnRows(dsrows) snv := tc.ServerNullableV11{ - CDNID: &testServers[0].CDNID, - FqdnTime: time.Time{}, - TypeID: &testServers[0].TypeID, + CommonServerProperties: tc.CommonServerProperties{ + CDNID: &testServers[0].Server.CDNID, + FqdnTime: time.Time{}, + TypeID: &testServers[0].Server.TypeID, + }, } - sn := tc.ServerNullable{ + sn := tc.ServerNullableV2{ ServerNullableV11: snv, IPIsService: nil, IP6IsService: nil, } - s := &TOServer{ - APIInfoImpl: api.APIInfoImpl{ - ReqInfo: &api.APIInfo{ - Params: nil, - IntParams: nil, - User: nil, - ReqID: 0, - Version: nil, - Tx: db.MustBegin(), - Config: nil, - }, - }, - ServerNullable: sn, - } - - userErr, _, errCode := s.Update() + userErr, _, errCode := checkTypeChangeSafety(sn.CommonServerProperties, db.MustBegin()) if errCode != 409 { t.Errorf("Update servers: Expected error code of %v, but got %v", 409, errCode) } @@ -312,15 +302,6 @@ func TestGetMidServers(t *testing.T) { ts.ILOIPNetmask, ts.ILOPassword, ts.ILOUsername, - ts.InterfaceMtu, - ts.InterfaceName, - ts.IP6Address, - ts.IP6IsService, - ts.IP6Gateway, - ts.IPAddress, - ts.IPIsService, - ts.IPNetmask, - ts.IPGateway, ts.LastUpdated, ts.MgmtIPAddress, ts.MgmtIPGateway, @@ -363,7 +344,7 @@ func TestGetMidServers(t *testing.T) { t.Errorf("getServers expected: no errors, actual: %v %v with status: %s", userErr, sysErr, http.StatusText(errCode)) } - cols2 := test.ColsFromStructByTag("db", tc.Server{}) + cols2 := test.ColsFromStructByTag("db", tc.CommonServerProperties{}) rows2 := sqlmock.NewRows(cols2) cgs := []tc.CacheGroup{} From 63b9b91ddab5c9af48ead013a8e6b0b97c515c64 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 12 May 2020 10:51:55 -0600 Subject: [PATCH 12/87] Cleaned up old approaches left in comments --- .../traffic_ops_golang/server/servers_test.go | 24 +++---------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers_test.go b/traffic_ops/traffic_ops_golang/server/servers_test.go index 0c10ba5209..c1667c7014 100644 --- a/traffic_ops/traffic_ops_golang/server/servers_test.go +++ b/traffic_ops/traffic_ops_golang/server/servers_test.go @@ -20,6 +20,7 @@ package server */ import ( + "fmt" "net/http" "testing" "time" @@ -87,27 +88,8 @@ func getTestServers() []ServerAndInterfaces { XMPPPasswd: "xmppPasswd", } - // mtu := uint64(testServer.InterfaceMtu) - - // interfaces := []byte(fmt.Sprintf("{\"{\"ipAddresses\" : [{\"address\" : \"76.0.23.56\", \"gateway\" : null, \"service_address\" : true}], \"max_bandwidth\" : null, \"monitor\" : true, \"mtu\" : 1500, \"name\" : \"eth0\"}\"}", testServer.IPAddress, testServer.InterfaceMtu, testServer.InterfaceName)) - - interfaces := []byte(`{"{\"ipAddresses\" : [{\"address\" : \"76.0.23.56\", \"gateway\" : null, \"service_address\" : true}], \"max_bandwidth\" : null, \"monitor\" : true, \"mtu\" : 1500, \"name\" : \"eth0\"}"}`) - - // interfaces := []tc.ServerInterfaceInfo{ - // tc.ServerInterfaceInfo{ - // IPAddresses: []tc.ServerIpAddress{ - // tc.ServerIpAddress{ - // Address: testServer.IPAddress, - // Gateway: &testServer.IPGateway, - // ServiceAddress: testServer.IPIsService, - // }, - // }, - // MaxBandwidth: nil, - // Monitor: true, - // MTU: &mtu, - // Name: testServer.InterfaceName, - // }, - // } + interfaces := []byte(fmt.Sprintf(`{"{\"ipAddresses\" : [{\"address\" : \"%s\", \"gateway\" : null, \"service_address\" : true}], \"max_bandwidth\" : null, \"monitor\" : true, \"mtu\" : %d, \"name\" : \"%s\"}"}`, testServer.IPAddress, testServer.InterfaceMtu, testServer.InterfaceName)) + servers = append(servers, ServerAndInterfaces{Server: testServer, Interfaces: interfaces}) testServer2 := testServer From 24459c31e8cda7cd133763ce200781be1e5a0b6f Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 12 May 2020 16:05:21 -0600 Subject: [PATCH 13/87] Fixed server teardown for v1 tests --- traffic_ops/testing/api/v1/todb_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/traffic_ops/testing/api/v1/todb_test.go b/traffic_ops/testing/api/v1/todb_test.go index e1b40e5fcc..aa6ad9f94c 100644 --- a/traffic_ops/testing/api/v1/todb_test.go +++ b/traffic_ops/testing/api/v1/todb_test.go @@ -325,6 +325,8 @@ func Teardown(db *sql.DB) error { DELETE FROM deliveryservice_server; DELETE FROM deliveryservice; DELETE FROM origin; + DELETE FROM ip_address; + DELETE FROM interface; DELETE FROM server; DELETE FROM phys_location; DELETE FROM region; From 17c6b5e73a82d6b987a58b8dab6bdc89ef739abf Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 12 May 2020 16:06:06 -0600 Subject: [PATCH 14/87] Fixed broken POST handler for API versions < 3 Also removed some CRUDer boilerplate that is no longer used --- .../traffic_ops_golang/server/servers.go | 54 ++----------------- 1 file changed, 4 insertions(+), 50 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 28848c6c56..102be8fed1 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -48,13 +48,6 @@ import ( "github.com/lib/pq" ) -// TOServer combines data about a server with metadata from an API request and -// provides methods that implement several interfaces from the api package. -type TOServer struct { - api.APIInfoImpl `json:"-"` - tc.ServerNullableV2 -} - const unfilteredServersQuery = ` SELECT COUNT(server.id) FROM server @@ -478,34 +471,6 @@ func validateV3(s tc.ServerNullable, tx *sql.Tx) (string, error) { return serviceInterface, util.JoinErrs(errs) } -// ChangeLogMessage implements the api.ChangeLogger interface for a custom log message -func (s TOServer) ChangeLogMessage(action string) (string, error) { - - var status string - if s.Status != nil { - status = *s.Status - } - - var hostName string - if s.HostName != nil { - hostName = *s.HostName - } - - var domainName string - if s.DomainName != nil { - domainName = *s.DomainName - } - - var serverID string - if s.ID != nil { - serverID = strconv.Itoa(*s.ID) - } - - message := action + ` ` + status + ` server: { "hostName":"` + hostName + `", "domainName":"` + domainName + `", id:` + serverID + ` }` - - return message, nil -} - func Read(w http.ResponseWriter, r *http.Request) { inf, userErr, sysErr, errCode := api.NewInfo(r, nil, nil) tx := inf.Tx.Tx @@ -1000,13 +965,10 @@ func createV1(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { } defer resultRows.Close() - var id int - var lastUpdated tc.TimeNoMod - rowsAffected := 0 for resultRows.Next() { rowsAffected++ - if err := resultRows.Scan(&id, &lastUpdated); err != nil { + if err := resultRows.StructScan(&server.CommonServerProperties); err != nil { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("server create scanning: %v", err)) return } @@ -1017,15 +979,13 @@ func createV1(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { } else if rowsAffected > 1 { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, errors.New("too many ids returned from server insert")) } - server.ID = &id - server.LastUpdated = &lastUpdated ifaces, err := server.LegacyInterfaceDetails.ToInterfaces(true, true) if err != nil { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, err) } - if userErr, sysErr, errCode := createInterfaces(id, ifaces, tx); err != nil { + if userErr, sysErr, errCode := createInterfaces(*server.ID, ifaces, tx); err != nil { api.HandleErr(w, r, tx, errCode, userErr, sysErr) return } @@ -1061,14 +1021,10 @@ func createV2(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { } defer resultRows.Close() - - var id int - var lastUpdated tc.TimeNoMod - rowsAffected := 0 for resultRows.Next() { rowsAffected++ - if err := resultRows.Scan(&id, &lastUpdated); err != nil { + if err := resultRows.StructScan(&server.CommonServerProperties); err != nil { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("server create scanning: %v", err)) return } @@ -1079,15 +1035,13 @@ func createV2(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { } else if rowsAffected > 1 { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, errors.New("too many ids returned from server insert")) } - server.ID = &id - server.LastUpdated = &lastUpdated ifaces, err := server.LegacyInterfaceDetails.ToInterfaces(*server.IPIsService, *server.IP6IsService) if err != nil { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, err) } - if userErr, sysErr, errCode := createInterfaces(id, ifaces, tx); err != nil { + if userErr, sysErr, errCode := createInterfaces(*server.ID, ifaces, tx); err != nil { api.HandleErr(w, r, tx, errCode, userErr, sysErr) return } From cfbe9e60916845c43b31cdc633b4af7fd2da2ddc Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 14 May 2020 11:03:17 -0600 Subject: [PATCH 15/87] Fixed read query not returning IDs --- .../traffic_ops_golang/server/servers.go | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 102be8fed1..3260db3e76 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -56,7 +56,9 @@ FROM server const selectQuery = ` SELECT cg.name AS cachegroup, + s.cachegroup AS cachegroup_id, cdn.name AS cdn_name, + s.cdn_id, s.domain_name, s.guid, s.host_name, @@ -68,15 +70,19 @@ SELECT s.ilo_password, s.ilo_username, s.offline_reason, - pl.name as phys_location, - p.name as profile, - p.description as profile_desc, + pl.name AS phys_location, + s.phys_location AS phys_location_id, + s.profile AS profile_id, + p.name AS profile, + p.description AS profile_desc, s.rack, s.router_host_name, s.router_port_name, - st.name as status, + st.name AS status, + s.status AS status_id, s.tcp_port, - t.name as server_type, + t.name AS server_type, + s.type AS server_type_id, s.xmpp_id, s.xmpp_passwd FROM server AS s @@ -637,6 +643,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( return nil, unfiltered, nil, fmt.Errorf("found more than one server with ID #%d", *s.ID), http.StatusInternalServerError } servers[*s.ID] = s + log.Debugf("%+v", s) ids = append(ids, *s.ID) } @@ -656,6 +663,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( if s, ok := servers[id]; !ok { log.Warnf("interfaces query returned interfaces for server #%d that was not in original query", id) } else { + log.Debugf("%+v", s) s.Interfaces = ifaces servers[id] = s } From e172f5b42dcbaef301fa28cbabddd2231d3f705c Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 14 May 2020 11:51:50 -0600 Subject: [PATCH 16/87] fixed unmarshaling problems, some API tests --- lib/go-tc/servers.go | 2 +- traffic_ops/testing/api/v1/atsconfig_test.go | 1 + .../ats/atsprofile/profile.go | 3 + .../traffic_ops_golang/ats/atsserver/meta.go | 4 +- .../ats/atsserver/parentdotconfig.go | 109 ++++++++---------- .../ats/atsserver/remapdotconfig.go | 8 +- traffic_ops/traffic_ops_golang/ats/db.go | 37 ++++-- .../dbhelpers/db_helpers.go | 46 ++++++++ .../traffic_ops_golang/server/servers.go | 31 +++-- 9 files changed, 155 insertions(+), 86 deletions(-) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index ed6ee53df2..74aaf56639 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -80,7 +80,7 @@ type ServerIpAddress struct { // ServerInterfaceInfo is the data associated with a server's interface. type ServerInterfaceInfo struct { - IPAddresses []ServerIpAddress `json:"ipAddresses" db:"ipAddresses"` + IPAddresses []ServerIpAddress `json:"ipAddresses" db:"ip_addresses"` MaxBandwidth *uint64 `json:"maxBandwidth" db:"max_bandwidth"` Monitor bool `json:"monitor" db:"monitor"` MTU *uint64 `json:"mtu" db:"mtu"` diff --git a/traffic_ops/testing/api/v1/atsconfig_test.go b/traffic_ops/testing/api/v1/atsconfig_test.go index 8abea7a60a..037e54b6a0 100644 --- a/traffic_ops/testing/api/v1/atsconfig_test.go +++ b/traffic_ops/testing/api/v1/atsconfig_test.go @@ -84,6 +84,7 @@ func GetTestATSConfigs(t *testing.T) { "sysctl.conf", "volume.config", } + t.Logf("SERVER PROFILE: %v", server.Profile) for _, profileConfig := range profileConfigs { if _, _, err = TOSession.GetATSProfileConfig(server.ProfileID, profileConfig); err != nil { t.Errorf("Getting profile '" + server.Profile + "' config '" + profileConfig + "': " + err.Error() + "\n") diff --git a/traffic_ops/traffic_ops_golang/ats/atsprofile/profile.go b/traffic_ops/traffic_ops_golang/ats/atsprofile/profile.go index 5d2b563b7f..5e83283720 100644 --- a/traffic_ops/traffic_ops_golang/ats/atsprofile/profile.go +++ b/traffic_ops/traffic_ops_golang/ats/atsprofile/profile.go @@ -27,6 +27,8 @@ import ( "strings" "github.com/apache/trafficcontrol/lib/go-rfc" + "github.com/apache/trafficcontrol/lib/go-log" + "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/ats" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/config" @@ -53,6 +55,7 @@ func WithProfileData(w http.ResponseWriter, r *http.Request, contentType string, return } } + log.Debugf("aosnutehantoehuntoehau %s", profileNameOrID) fileName := strings.TrimSuffix(inf.Params["file"], ".json") diff --git a/traffic_ops/traffic_ops_golang/ats/atsserver/meta.go b/traffic_ops/traffic_ops_golang/ats/atsserver/meta.go index 26e741de2c..d6d94c3908 100644 --- a/traffic_ops/traffic_ops_golang/ats/atsserver/meta.go +++ b/traffic_ops/traffic_ops_golang/ats/atsserver/meta.go @@ -25,6 +25,8 @@ import ( "github.com/apache/trafficcontrol/lib/go-atscfg" "github.com/apache/trafficcontrol/lib/go-rfc" + "github.com/apache/trafficcontrol/lib/go-tc" + "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/ats" ) @@ -82,7 +84,7 @@ func GetConfigMetaData(w http.ResponseWriter, r *http.Request) { return } - txt := atscfg.MakeMetaConfig(serverName, server, tmParams.URL, tmParams.ReverseProxyURL, locationParams, uriSignedDSes, scopeParams, dsNames) + txt := atscfg.MakeMetaConfig(tc.CacheName(serverName), server, tmParams.URL, tmParams.ReverseProxyURL, locationParams, uriSignedDSes, scopeParams, dsNames) w.Header().Set(rfc.ContentType, rfc.ApplicationJSON) w.Write([]byte(txt)) } diff --git a/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go b/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go index c3223f11b1..e9aebac11c 100644 --- a/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go +++ b/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go @@ -22,6 +22,7 @@ package atsserver import ( "database/sql" "errors" + "fmt" "net/http" "strconv" "strings" @@ -31,6 +32,8 @@ import ( "github.com/apache/trafficcontrol/lib/go-tc" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/ats" + // "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers" + "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/server" "github.com/lib/pq" ) @@ -54,9 +57,9 @@ func GetParentDotConfig(w http.ResponseWriter, r *http.Request) { serverInfo, ok, err := &atscfg.ServerInfo{}, false, error(nil) if isHost { - serverInfo, ok, err = getServerInfoByHost(inf.Tx.Tx, hostName) + serverInfo, ok, err = ats.GetServerInfoByHost(inf.Tx.Tx, hostName) } else { - serverInfo, ok, err = getServerInfoByID(inf.Tx.Tx, id) + serverInfo, ok, err = ats.GetServerInfoByID(inf.Tx.Tx, id) } if err != nil { api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting server info: "+err.Error())) @@ -117,57 +120,6 @@ func (s ParentConfigDSSortByName) Less(i, j int) bool { return strings.Compare(string(s[i].Name), string(s[j].Name)) < 0 } -// getServerInfo returns the necessary info about the server, whether the server exists, and any error. -func getServerInfoByID(tx *sql.Tx, id int) (*atscfg.ServerInfo, bool, error) { - return getServerInfo(tx, ServerInfoQuery()+`WHERE s.id = $1`, []interface{}{id}) -} - -// getServerInfo returns the necessary info about the server, whether the server exists, and any error. -func getServerInfoByHost(tx *sql.Tx, host string) (*atscfg.ServerInfo, bool, error) { - return getServerInfo(tx, ServerInfoQuery()+` WHERE s.host_name = $1 `, []interface{}{host}) -} - -// getServerInfo returns the necessary info about the server, whether the server exists, and any error. -func getServerInfo(tx *sql.Tx, qry string, qryParams []interface{}) (*atscfg.ServerInfo, bool, error) { - s := atscfg.ServerInfo{} - if err := tx.QueryRow(qry, qryParams...).Scan(&s.CDN, &s.CDNID, &s.ID, &s.HostName, &s.DomainName, &s.IP, &s.ProfileID, &s.ProfileName, &s.Port, &s.Type, &s.CacheGroupID, &s.ParentCacheGroupID, &s.SecondaryParentCacheGroupID, &s.ParentCacheGroupType, &s.SecondaryParentCacheGroupType); err != nil { - if err == sql.ErrNoRows { - return nil, false, nil - } - return nil, false, errors.New("querying server info: " + err.Error()) - } - return &s, true, nil -} - -func ServerInfoQuery() string { - return ` -SELECT - c.name as cdn, - s.cdn_id, - s.id, - s.host_name, - c.domain_name, - s.ip_address, - s.profile AS profile_id, - p.name AS profile_name, - s.tcp_port, - t.name as type, - s.cachegroup, - COALESCE(cg.parent_cachegroup_id, ` + strconv.Itoa(atscfg.InvalidID) + `) as parent_cachegroup_id, - COALESCE(cg.secondary_parent_cachegroup_id, ` + strconv.Itoa(atscfg.InvalidID) + `) as secondary_parent_cachegroup_id, - COALESCE(parentt.name, '') as parent_cachegroup_type, - COALESCE(sparentt.name, '') as secondary_parent_cachegroup_type -FROM - server s - JOIN cdn c ON s.cdn_id = c.id - JOIN type t ON s.type = t.id - JOIN profile p ON p.id = s.profile - JOIN cachegroup cg on s.cachegroup = cg.id - LEFT JOIN type parentt on parentt.id = (select type from cachegroup where id = cg.parent_cachegroup_id) - LEFT JOIN type sparentt on sparentt.id = (select type from cachegroup where id = cg.secondary_parent_cachegroup_id) -` -} - // GetATSMajorVersion returns the major version of the given profile's package trafficserver parameter. // If no parameter exists, this does not return an error, but rather logs a warning and uses DefaultATSVersion. func GetATSMajorVersion(tx *sql.Tx, serverProfileID int) (int, error) { @@ -502,14 +454,14 @@ func getParentInfo(tx *sql.Tx, server *atscfg.ServerInfo) (map[atscfg.OriginHost } // getServerParentCacheGroupProfiles gets the profile information for servers belonging to the parent cachegroup, and secondary parent cachegroup, of the cachegroup of each server. -func getServerParentCacheGroupProfiles(tx *sql.Tx, server *atscfg.ServerInfo) (map[atscfg.ProfileID]atscfg.ProfileCache, map[atscfg.OriginHost][]atscfg.CGServer, error) { +func getServerParentCacheGroupProfiles(tx *sql.Tx, srv *atscfg.ServerInfo) (map[atscfg.ProfileID]atscfg.ProfileCache, map[atscfg.OriginHost][]atscfg.CGServer, error) { // TODO make this more efficient - should be a single query - this was transliterated from Perl - it's extremely inefficient. profileCaches := map[atscfg.ProfileID]atscfg.ProfileCache{} originServers := map[atscfg.OriginHost][]atscfg.CGServer{} // "deliveryServices" in Perl qry := "" - if server.IsTopLevelCache() { + if srv.IsTopLevelCache() { // multisite origins take all the org groups in to account qry = ` WITH parent_cachegroup_ids AS ( @@ -538,7 +490,6 @@ parent_cachegroup_ids AS ( SELECT s.id, s.host_name, - s.ip_address, s.tcp_port, s.cachegroup, s.status, @@ -563,10 +514,10 @@ WHERE // TODO move qry, qryParams to separate funcs/consts qryParams := []interface{}{} - if server.IsTopLevelCache() { - qryParams = []interface{}{server.CDN} + if srv.IsTopLevelCache() { + qryParams = []interface{}{srv.CDN} } else { - qryParams = []interface{}{server.CDN, server.ID} + qryParams = []interface{}{srv.CDN, srv.ID} } rows, err := tx.Query(qry, qryParams...) @@ -576,20 +527,54 @@ WHERE defer rows.Close() cgServerIDs := []int{} - cgServers := []atscfg.CGServer{} + cgServers := map[int]atscfg.CGServer{} for rows.Next() { s := atscfg.CGServer{Capabilities: map[atscfg.ServerCapability]struct{}{}} caps := []string{} - if err := rows.Scan(&s.ServerID, &s.ServerHost, &s.ServerIP, &s.ServerPort, &s.CacheGroupID, &s.Status, &s.Type, &s.ProfileID, &s.CDN, &s.TypeName, pq.Array(&caps), &s.Domain); err != nil { + if err := rows.Scan(&s.ServerID, &s.ServerHost, &s.ServerPort, &s.CacheGroupID, &s.Status, &s.Type, &s.ProfileID, &s.CDN, &s.TypeName, pq.Array(&caps), &s.Domain); err != nil { return nil, nil, errors.New("scanning: " + err.Error()) } + + + for _, cap := range caps { s.Capabilities[atscfg.ServerCapability(cap)] = struct{}{} } - cgServers = append(cgServers, s) + cgServers[int(s.ServerID)] = s cgServerIDs = append(cgServerIDs, int(s.ServerID)) } + interfaceRows, err := tx.Query(server.SelectInterfacesQuery, pq.Array(cgServerIDs)) + if err != nil { + return nil, nil, fmt.Errorf("querying for interfaces: %v", err) + } + defer interfaceRows.Close() + + for interfaceRows.Next() { + ifaces := []tc.ServerInterfaceInfo{} + var id int + if err := interfaceRows.Scan(pq.Array(&ifaces), &id); err != nil { + return nil, nil, fmt.Errorf("scanning server interfaces: %v", err) + } + + s, ok := cgServers[id]; + if !ok { + log.Warnf("interfaces query returned interfaces for server #%d that was not in original query", id) + continue + } + + legacyNet, err := tc.InterfaceInfoToLegacyInterfaces(ifaces) + if err != nil { + return nil, nil, fmt.Errorf("Converting interfaces for server #%d to legacy: %v", id, err) + } + + if legacyNet.IPAddress != nil { + s.ServerIP = *legacyNet.IPAddress + } + + cgServers[id] = s + } + serverCapabilities, err := ats.GetServerCapabilitiesByID(tx, cgServerIDs) if err != nil { return nil, nil, errors.New("getting server capabilities: " + err.Error()) diff --git a/traffic_ops/traffic_ops_golang/ats/atsserver/remapdotconfig.go b/traffic_ops/traffic_ops_golang/ats/atsserver/remapdotconfig.go index 9ce112b388..81610c27ca 100644 --- a/traffic_ops/traffic_ops_golang/ats/atsserver/remapdotconfig.go +++ b/traffic_ops/traffic_ops_golang/ats/atsserver/remapdotconfig.go @@ -26,6 +26,8 @@ import ( "github.com/apache/trafficcontrol/lib/go-atscfg" "github.com/apache/trafficcontrol/lib/go-rfc" + "github.com/apache/trafficcontrol/lib/go-tc" + "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/ats" ) @@ -50,13 +52,13 @@ func GetServerConfigRemap(w http.ResponseWriter, r *http.Request) { return } - atsMajorVersion, err := ats.GetATSMajorVersionFromServerName(inf.Tx.Tx, serverName) + atsMajorVersion, err := ats.GetATSMajorVersionFromServerName(inf.Tx.Tx, tc.CacheName(serverName)) if err != nil { api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting ATS major version: "+err.Error())) return } - cacheURLConfigParams, err := ats.GetServerProfileParamData(inf.Tx.Tx, serverName, "cacheurl.config") + cacheURLConfigParams, err := ats.GetServerProfileParamData(inf.Tx.Tx, tc.CacheName(serverName), "cacheurl.config") if err != nil { api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting cacheurl.config params: "+err.Error())) return @@ -86,7 +88,7 @@ func GetServerConfigRemap(w http.ResponseWriter, r *http.Request) { return } - txt := atscfg.MakeRemapDotConfig(serverName, toToolName, toURL, atsMajorVersion, cacheURLConfigParams, dsProfilesCacheKeyConfigParams, serverPackageParamData, serverInfo, remapDSData) + txt := atscfg.MakeRemapDotConfig(tc.CacheName(serverName), toToolName, toURL, atsMajorVersion, cacheURLConfigParams, dsProfilesCacheKeyConfigParams, serverPackageParamData, serverInfo, remapDSData) w.Header().Set(rfc.ContentType, rfc.ContentTypeTextPlain) io.WriteString(w, txt) diff --git a/traffic_ops/traffic_ops_golang/ats/db.go b/traffic_ops/traffic_ops_golang/ats/db.go index 3df87878dd..29a3405717 100644 --- a/traffic_ops/traffic_ops_golang/ats/db.go +++ b/traffic_ops/traffic_ops_golang/ats/db.go @@ -541,7 +541,7 @@ func GetServerNameFromID(tx *sql.Tx, id int) (tc.CacheName, bool, error) { // GetServerNameFromNameOrID returns the server name from a parameter which may be the name or ID. // This also checks and verifies the existence of the given server, and returns an appropriate user error if it doesn't exist. // Returns the name, any user error, any system error, and any error code. -func GetServerNameFromNameOrID(tx *sql.Tx, serverNameOrID string) (tc.CacheName, error, error, int) { +func GetServerNameFromNameOrID(tx *sql.Tx, serverNameOrID string) (string, error, error, int) { if serverID, err := strconv.Atoi(serverNameOrID); err == nil { serverName, ok, err := dbhelpers.GetServerNameFromID(tx, serverID) if err != nil { @@ -549,37 +549,51 @@ func GetServerNameFromNameOrID(tx *sql.Tx, serverNameOrID string) (tc.CacheName, } else if !ok { return "", errors.New("server not found"), nil, http.StatusNotFound } - return tc.CacheName(serverName), nil, nil, http.StatusOK + return serverName, nil, nil, http.StatusOK } - serverName := tc.CacheName(serverNameOrID) - if _, ok, err := dbhelpers.GetServerIDFromName(string(serverName), tx); err != nil { - return "", nil, fmt.Errorf("checking server name '%v' existence: %v", serverName, err), http.StatusInternalServerError + if _, ok, err := dbhelpers.GetServerIDFromName(serverNameOrID, tx); err != nil { + return "", nil, fmt.Errorf("checking server name '%v' existence: %v", serverNameOrID, err), http.StatusInternalServerError } else if !ok { return "", errors.New("server not found"), nil, http.StatusNotFound } - return serverName, nil, nil, http.StatusOK + return serverNameOrID, nil, nil, http.StatusOK } // GetServerInfoByID returns the necessary info about the server, whether the server exists, and any error. func GetServerInfoByID(tx *sql.Tx, id int) (*atscfg.ServerInfo, bool, error) { - return getServerInfo(tx, ServerInfoQuery()+`WHERE s.id = $1`, []interface{}{id}) + return GetServerInfo(tx, ServerInfoQuery()+`WHERE s.id = $1`, []interface{}{id}) } // GetServerInfoByHost returns the necessary info about the server, whether the server exists, and any error. -func GetServerInfoByHost(tx *sql.Tx, host tc.CacheName) (*atscfg.ServerInfo, bool, error) { - return getServerInfo(tx, ServerInfoQuery()+` WHERE s.host_name = $1 `, []interface{}{host}) +func GetServerInfoByHost(tx *sql.Tx, host string) (*atscfg.ServerInfo, bool, error) { + return GetServerInfo(tx, ServerInfoQuery()+` WHERE s.host_name = $1 `, []interface{}{host}) } // getServerInfo returns the necessary info about the server, whether the server exists, and any error. -func getServerInfo(tx *sql.Tx, qry string, qryParams []interface{}) (*atscfg.ServerInfo, bool, error) { +func GetServerInfo(tx *sql.Tx, qry string, qryParams []interface{}) (*atscfg.ServerInfo, bool, error) { s := atscfg.ServerInfo{} - if err := tx.QueryRow(qry, qryParams...).Scan(&s.CDN, &s.CDNID, &s.ID, &s.HostName, &s.DomainName, &s.IP, &s.ProfileID, &s.ProfileName, &s.Port, &s.HTTPSPort, &s.Type, &s.CacheGroupID, &s.ParentCacheGroupID, &s.SecondaryParentCacheGroupID, &s.ParentCacheGroupType, &s.SecondaryParentCacheGroupType); err != nil { + if err := tx.QueryRow(qry, qryParams...).Scan(&s.CDN, &s.CDNID, &s.ID, &s.HostName, &s.DomainName, &s.ProfileID, &s.ProfileName, &s.Port, &s.HTTPSPort, &s.Type, &s.CacheGroupID, &s.ParentCacheGroupID, &s.SecondaryParentCacheGroupID, &s.ParentCacheGroupType, &s.SecondaryParentCacheGroupType); err != nil { if err == sql.ErrNoRows { return nil, false, nil } return nil, false, errors.New("querying server info: " + err.Error()) } + + infs, err := dbhelpers.GetServerInterfaces(s.ID, tx) + if err != nil { + return nil, false, fmt.Errorf("querying server info interfaces: %v", err) + } + + legacyInfo, err := tc.InterfaceInfoToLegacyInterfaces(infs) + if err != nil { + return nil, false, fmt.Errorf("converting server info interfaces to legacy: %v", err) + } + + if legacyInfo.IPAddress != nil { + s.IP = *legacyInfo.IPAddress + } + return &s, true, nil } @@ -591,7 +605,6 @@ SELECT s.id, s.host_name, c.domain_name, - s.ip_address, s.profile AS profile_id, p.name AS profile_name, s.tcp_port, diff --git a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go index 0ce7be9c88..8ee6c28ead 100644 --- a/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go +++ b/traffic_ops/traffic_ops_golang/dbhelpers/db_helpers.go @@ -519,6 +519,52 @@ WHERE s.id = $1 return row, true, nil } +// GetServerInterfaces, given the ID of a server, returns all of its network +// interfaces, or an error if one occurs during retrieval. +func GetServerInterfaces(id int, tx *sql.Tx) ([]tc.ServerInterfaceInfo, error) { + q := ` + SELECT ( + json_build_object ( + 'ipAddresses', + ARRAY ( + SELECT ( + json_build_object ( + 'address', ip_address.address, + 'gateway', ip_address.gateway, + 'service_address', ip_address.service_address + ) + ) + FROM ip_address + WHERE ip_address.interface = interface.name + AND ip_address.server = $1 + ), + 'max_bandwidth', interface.max_bandwidth, + 'monitor', interface.monitor, + 'mtu', interface.mtu, + 'name', interface.name + ) + ) + FROM interface + WHERE interface.server = $1 + ` + rows, err := tx.Query(q, id) + if err != nil { + return nil, err + } + defer rows.Close() + + infs := []tc.ServerInterfaceInfo{} + for rows.Next() { + var inf tc.ServerInterfaceInfo + if err = rows.Scan(&inf); err != nil { + return nil, err + } + infs = append(infs, inf) + } + + return infs, nil +} + // GetStatusByID returns a Status struct, a bool for whether or not a status of the given ID exists, and an error (if one occurs). func GetStatusByID(id int, tx *sql.Tx) (tc.StatusNullable, bool, error) { q := ` diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 3260db3e76..a2584f02bc 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -94,7 +94,7 @@ JOIN status st ON s.status = st.id JOIN type t ON s.type = t.id ` -const selectInterfacesQuery = ` +const SelectInterfacesQuery = ` SELECT ( ARRAY ( SELECT ( json_build_object ( @@ -104,14 +104,14 @@ SELECT ( json_build_object ( 'address', ip_address.address, 'gateway', ip_address.gateway, - 'service_address', ip_address.service_address + 'serviceAddress', ip_address.service_address ) ) FROM ip_address WHERE ip_address.interface = interface.name AND ip_address.server = server.id ), - 'max_bandwidth', interface.max_bandwidth, + 'maxBandwidth', interface.max_bandwidth, 'monitor', interface.monitor, 'mtu', interface.mtu, 'name', interface.name @@ -543,10 +543,22 @@ func ReadID(w http.ResponseWriter, r *http.Request) { } defer inf.Close() - var servers []tc.ServerNullable + servers := []tc.ServerNullable{} servers, _, userErr, sysErr, errCode = getServers(inf.Params, inf.Tx, inf.User) - legacyServers := make([]tc.ServerNullableV11, len(servers)) + if len(servers) > 1 { + api.HandleDeprecatedErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("ID '%d' matched more than one server (%d total)", inf.IntParams["id"], len(servers)), &alternative) + return + } + + deprecationAlerts := api.CreateDeprecationAlerts(&alternative) + + // No need to bother converting if there's no data + if len(servers) < 1 { + api.WriteAlertsObj(w, r, http.StatusOK, deprecationAlerts, servers) + } + + legacyServers := make([]tc.ServerNullableV11, 0, len(servers)) for _, server := range servers { legacyServer, err := server.ToServerV2() if err != nil { @@ -555,7 +567,6 @@ func ReadID(w http.ResponseWriter, r *http.Request) { } legacyServers = append(legacyServers, legacyServer.ServerNullableV11) } - deprecationAlerts := api.CreateDeprecationAlerts(&alternative) api.WriteAlertsObj(w, r, http.StatusOK, deprecationAlerts, legacyServers) } @@ -647,7 +658,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( ids = append(ids, *s.ID) } - interfaceRows, err := tx.Tx.Query(selectInterfacesQuery, pq.Array(ids)) + interfaceRows, err := tx.Tx.Query(SelectInterfacesQuery, pq.Array(ids)) if err != nil { return nil, unfiltered, nil, fmt.Errorf("querying for interfaces: %v", err), http.StatusInternalServerError } @@ -1167,6 +1178,12 @@ func Delete(w http.ResponseWriter, r *http.Request) { return } + userErr, sysErr, errCode = deleteInterfaces(id, tx) + if userErr != nil || sysErr != nil { + api.HandleErr(w, r, tx, errCode, userErr, sysErr) + return + } + if err := tx.QueryRow(deleteServerQuery, id).Scan(); err != nil && err != sql.ErrNoRows { userErr, sysErr, errCode = api.ParseDBError(err) api.HandleErr(w, r, tx, errCode, userErr, sysErr) From 355c6ef6067c4ab99ffb4aaac43be84b49eae9fa Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 14 May 2020 15:06:12 -0600 Subject: [PATCH 17/87] Fixed ip_allow.config for server interfaces --- .../ats/atsserver/ipallowdotconfig.go | 84 +++++++++++++------ 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/ats/atsserver/ipallowdotconfig.go b/traffic_ops/traffic_ops_golang/ats/atsserver/ipallowdotconfig.go index 520200b135..bab067edcf 100644 --- a/traffic_ops/traffic_ops_golang/ats/atsserver/ipallowdotconfig.go +++ b/traffic_ops/traffic_ops_golang/ats/atsserver/ipallowdotconfig.go @@ -22,6 +22,7 @@ package atsserver import ( "database/sql" "errors" + "fmt" "net/http" "strings" @@ -29,6 +30,8 @@ import ( "github.com/apache/trafficcontrol/lib/go-tc" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/ats" + + "github.com/lib/pq" ) func GetIPAllowDotConfig(w http.ResponseWriter, r *http.Request) { @@ -77,26 +80,45 @@ func GetIPAllowDotConfig(w http.ResponseWriter, r *http.Request) { // GetChildServers returns the child servers of the given Mid serverName. This should not be called with an Edge server. func GetChildServers(tx *sql.Tx, serverName tc.CacheName) (map[tc.CacheName]atscfg.IPAllowServer, error) { qry := ` -SELECT - s.host_name, - s.ip_address, - COALESCE(s.ip6_address, '') -FROM - server s - JOIN type tp on tp.id = s.type - JOIN cachegroup cg on cg.id = s.cachegroup -WHERE - (tp.name = '` + tc.MonitorTypeName + `' OR ( tp.name LIKE '` + tc.EdgeTypePrefix + `%') - AND cg.id IN ( - SELECT - cg2.id - FROM - server s2 - JOIN cachegroup cg2 ON (cg2.parent_cachegroup_id = s2.cachegroup OR cg2.secondary_parent_cachegroup_id = s2.cachegroup) - WHERE - s2.host_name = $1 ) - ) -` + SELECT + s.host_name, + 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 + ), + 'maxBandwidth', interface.max_bandwidth, + 'monitor', interface.monitor, + 'mtu', interface.mtu, + 'name', interface.name + ) + ) + FROM interface + WHERE interface.server = s.id + ) AS interfaces + FROM server s + JOIN type tp on tp.id = s.type + JOIN cachegroup cg on cg.id = s.cachegroup + WHERE + (tp.name = 'RASCAL' OR ( tp.name LIKE 'EDGE%') + AND cg.id IN ( + SELECT cg2.id + FROM server s2 + JOIN cachegroup cg2 ON (cg2.parent_cachegroup_id = s2.cachegroup OR cg2.secondary_parent_cachegroup_id = s2.cachegroup) + WHERE s2.host_name = $1 + ) + )` rows, err := tx.Query(qry, serverName) if err != nil { return nil, errors.New("querying: " + err.Error()) @@ -105,12 +127,26 @@ WHERE servers := map[tc.CacheName]atscfg.IPAllowServer{} for rows.Next() { - svName := tc.CacheName("") - sv := atscfg.IPAllowServer{} - if err := rows.Scan(&svName, &sv.IPAddress, &sv.IP6Address); err != nil { + var svName string + var ifaces []tc.ServerInterfaceInfo + if err := rows.Scan(&svName, pq.Array(&ifaces)); err != nil { return nil, errors.New("scanning: " + err.Error()) } - servers[svName] = sv + + var sv atscfg.IPAllowServer + legacyNet, err := tc.InterfaceInfoToLegacyInterfaces(ifaces) + if err != nil { + return nil, fmt.Errorf("Converting server '%s' interfaces to legacy info: %v", svName, err) + } + + if legacyNet.IPAddress != nil { + sv.IPAddress = *legacyNet.IPAddress + } + if legacyNet.IP6Address != nil { + sv.IP6Address = *legacyNet.IP6Address + } + + servers[tc.CacheName(svName)] = sv } return servers, nil } From c645c9e5f50fcf32d60327dffe7d0f38b246fcf1 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 14 May 2020 15:14:41 -0600 Subject: [PATCH 18/87] Fixed PUT not returning proper names --- .../traffic_ops_golang/server/servers.go | 71 +++++++++++++++---- 1 file changed, 58 insertions(+), 13 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index a2584f02bc..3cbab189bf 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -277,7 +277,41 @@ UPDATE server SET xmpp_id=:xmpp_id, xmpp_passwd=:xmpp_passwd WHERE id=:id -RETURNING last_updated +RETURNING + (SELECT name FROM cachegroup WHERE cachegroup.id=server.cachegroup) AS cachegroup, + cachegroup AS cachegroup_id, + cdn_id, + (SELECT name FROM cdn WHERE cdn.id=server.cdn_id) AS cdn_name, + domain_name, + guid, + host_name, + https_port, + id, + ilo_ip_address, + ilo_ip_gateway, + ilo_ip_netmask, + ilo_password, + ilo_username, + last_updated, + mgmt_ip_address, + mgmt_ip_gateway, + mgmt_ip_netmask, + offline_reason, + (SELECT name FROM phys_location WHERE phys_location.id=server.phys_location) AS phys_location, + phys_location AS phys_location_id, + profile AS profile_id, + (SELECT description FROM profile WHERE profile.id=server.profile) AS profile_desc, + (SELECT name FROM profile WHERE profile.id=server.profile) AS profile, + rack, + reval_pending, + router_host_name, + router_port_name, + (SELECT name FROM status WHERE status.id=server.status) AS status, + status AS status_id, + tcp_port, + (SELECT name FROM type WHERE type.id=server.type) AS server_type, + type AS server_type_id, + upd_pending ` const deleteServerQuery = `DELETE FROM server WHERE id=$1` @@ -720,12 +754,12 @@ func getMidServers(servers []tc.ServerNullable, tx *sqlx.Tx) ([]tc.ServerNullabl edgeIDs := strings.Join(ids, ",") // TODO: include secondary parent? q := selectQuery + ` -WHERE t.name = 'MID' AND s.cachegroup IN ( -SELECT cg.parent_cachegroup_id FROM cachegroup AS cg -WHERE cg.id IN ( -SELECT s.cachegroup FROM server AS s -WHERE s.id IN (` + edgeIDs + `))) -` + WHERE t.name = 'MID' AND s.cachegroup IN ( + SELECT cg.parent_cachegroup_id FROM cachegroup AS cg + WHERE cg.id IN ( + SELECT s.cachegroup FROM server AS s + WHERE s.id IN (` + edgeIDs + `))) + ` rows, err := tx.Queryx(q) if err != nil { return nil, err, nil, http.StatusBadRequest @@ -748,7 +782,7 @@ func checkTypeChangeSafety(server tc.CommonServerProperties, tx *sqlx.Tx) (error // see if cdn or type changed var cdnID int var typeID int - if err := tx.QueryRow("SELECT type, cdn_id FROM server WHERE id = $1", server.ID).Scan(&typeID, &cdnID); err != nil { + if err := tx.QueryRow("SELECT type, cdn_id FROM server WHERE id = $1", *server.ID).Scan(&typeID, &cdnID); err != nil { if err == sql.ErrNoRows { return errors.New("no server found with this ID"), nil, http.StatusNotFound } @@ -916,6 +950,9 @@ func Update(w http.ResponseWriter, r *http.Request) { } } + server.ID = new(int) + *server.ID = inf.IntParams["id"] + if userErr, sysErr, errCode = checkTypeChangeSafety(server.CommonServerProperties, inf.Tx); userErr != nil || sysErr != nil { api.HandleErr(w, r, tx, errCode, userErr, sysErr) return @@ -929,15 +966,23 @@ func Update(w http.ResponseWriter, r *http.Request) { } defer rows.Close() - if !rows.Next() { + rowsAffected := 0 + for rows.Next() { + if err := rows.StructScan(&server); err != nil { + api.HandleErr(w, r, tx, http.StatusNotFound, nil, fmt.Errorf("scanning lastUpdated from server insert: %v", err)) + return + } + rowsAffected++ + } + + if rowsAffected < 1 { api.HandleErr(w, r, tx, http.StatusNotFound, errors.New("no server found with this id"), nil) + return } - var lastUpdated tc.TimeNoMod - if err := rows.Scan(&lastUpdated); err != nil { - api.HandleErr(w, r, tx, http.StatusNotFound, nil, fmt.Errorf("scanning lastUpdated from server insert: %v", err)) + if rowsAffected > 1 { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("update for server #%d affected too many rows (%d)", *server.ID, rowsAffected)) return } - server.LastUpdated = &lastUpdated if userErr, sysErr, errCode = deleteInterfaces(inf.IntParams["id"], tx); userErr != nil || sysErr != nil { api.HandleErr(w, r, tx, errCode, userErr, sysErr) From 40a2c09e8867028150ec566d799c73db991cb4d8 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 14 May 2020 16:46:32 -0600 Subject: [PATCH 19/87] Fixed using unitialized data in PUT 1.1/servers handler --- traffic_ops/traffic_ops_golang/server/servers.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 3cbab189bf..9c79188d1d 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -688,7 +688,6 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( return nil, unfiltered, nil, fmt.Errorf("found more than one server with ID #%d", *s.ID), http.StatusInternalServerError } servers[*s.ID] = s - log.Debugf("%+v", s) ids = append(ids, *s.ID) } @@ -708,7 +707,6 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( if s, ok := servers[id]; !ok { log.Warnf("interfaces query returned interfaces for server #%d that was not in original query", id) } else { - log.Debugf("%+v", s) s.Interfaces = ifaces servers[id] = s } @@ -922,9 +920,11 @@ func Update(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) return } + interfaces, err = server.LegacyInterfaceDetails.ToInterfaces(*server.IPIsService, *server.IP6IsService) if err != nil { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Converting server legacy interfaces to interface array: %v", err)) + return } } else { var legacyServer tc.ServerNullableV11 @@ -939,9 +939,10 @@ func Update(w http.ResponseWriter, r *http.Request) { return } - interfaces, err = server.LegacyInterfaceDetails.ToInterfaces(true, true) + interfaces, err = legacyServer.LegacyInterfaceDetails.ToInterfaces(true, true) if err != nil { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Converting server legacy interfaces to interface array: %v", err)) + return } server = tc.ServerNullableV2{ ServerNullableV11: legacyServer, From 82e24aecddd56c7578b1f1c62d5921f17395f3af Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 14 May 2020 16:52:24 -0600 Subject: [PATCH 20/87] Fixed/improved error messages --- traffic_ops/testing/api/v1/serverupdatestatus_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/traffic_ops/testing/api/v1/serverupdatestatus_test.go b/traffic_ops/testing/api/v1/serverupdatestatus_test.go index 3a2bced1ef..b326a5bd63 100644 --- a/traffic_ops/testing/api/v1/serverupdatestatus_test.go +++ b/traffic_ops/testing/api/v1/serverupdatestatus_test.go @@ -86,16 +86,16 @@ func TestServerUpdateStatus(t *testing.T) { // assert that updates were queued for the proper EDGE servers getServers() if !edge1cdn1.UpdPending { - t.Errorf("expected: child %s to have updates pending, actual: no updates pending", edge1cdn1.HostName) + t.Errorf("expected: child %s (%d) to have updates pending, actual: no updates pending", edge1cdn1.HostName, edge1cdn1.ID) } if !edge2cdn1.UpdPending { - t.Errorf("expected: child %s to have updates pending, actual: no updates pending", edge2cdn1.HostName) + t.Errorf("expected: child %s (%d) to have updates pending, actual: no updates pending", edge2cdn1.HostName, edge2cdn1.ID) } if mid1cdn1.UpdPending { - t.Errorf("expected: server %s with updated status to have no updates pending, actual: updates pending", mid1cdn1.HostName) + t.Errorf("expected: server %s (%d) with updated status to have no updates pending, actual: updates pending", mid1cdn1.HostName, mid1cdn1.ID) } if edge1cdn2.UpdPending { - t.Errorf("expected: server %s in different CDN than server with updated status to have no updates pending, actual: updates pending", edge2cdn1.HostName) + t.Errorf("expected: server %s (%d) in different CDN than server with updated status to have no updates pending, actual: updates pending", edge1cdn2.HostName, edge1cdn2.ID) } // update status of MID server to OFFLINE via status ID From dd7d7e87b35d3df2b65821ec92f3a13d9fef039a Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Fri, 15 May 2020 13:17:51 -0600 Subject: [PATCH 21/87] Fixed select query --- traffic_ops/traffic_ops_golang/server/servers.go | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 9c79188d1d..278addba3a 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -57,8 +57,8 @@ const selectQuery = ` SELECT cg.name AS cachegroup, s.cachegroup AS cachegroup_id, - cdn.name AS cdn_name, s.cdn_id, + cdn.name AS cdn_name, s.domain_name, s.guid, s.host_name, @@ -69,13 +69,18 @@ SELECT s.ilo_ip_netmask, s.ilo_password, s.ilo_username, + s.last_updated, + s.mgmt_ip_address, + s.mgmt_ip_gateway, + s.mgmt_ip_netmask, s.offline_reason, pl.name AS phys_location, s.phys_location AS phys_location_id, - s.profile AS profile_id, p.name AS profile, p.description AS profile_desc, + s.profile AS profile_id, s.rack, + s.reval_pending, s.router_host_name, s.router_port_name, st.name AS status, @@ -83,6 +88,7 @@ SELECT s.tcp_port, t.name AS server_type, s.type AS server_type_id, + s.upd_pending AS upd_pending, s.xmpp_id, s.xmpp_passwd FROM server AS s From d036aad0df6e2472b2a6e1903a94f1613139ad1e Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 11:02:10 -0600 Subject: [PATCH 22/87] Fixed downgraded servers not setting ipIsService and ip6IsService --- lib/go-tc/servers.go | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index 74aaf56639..612f69f3e1 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -389,11 +389,20 @@ func (s *ServerNullable) ToServerV2() (ServerNullableV2, error) { ServerNullableV11: ServerNullableV11{ CommonServerProperties: s.CommonServerProperties, }, + IPIsService: new(bool), + IP6IsService: new(bool), } var err error legacyServer.LegacyInterfaceDetails, err = InterfaceInfoToLegacyInterfaces(s.Interfaces) - return legacyServer, err + if err != nil { + return legacyServer, err + } + + *legacyServer.IPIsService = legacyServer.LegacyInterfaceDetails.IPAddress != nil && *legacyServer.LegacyInterfaceDetails.IPAddress != "" + *legacyServer.IP6IsService = legacyServer.LegacyInterfaceDetails.IP6Address != nil && *legacyServer.LegacyInterfaceDetails.IP6Address != "" + + return legacyServer, nil } type ServerUpdateStatus struct { From 29e8b330c6bf99a3b4f6904a064621e9dd2de27a Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 11:02:52 -0600 Subject: [PATCH 23/87] Fixed GET v1 servers returning v2 servers and vice-versa --- traffic_ops/traffic_ops_golang/server/servers.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 278addba3a..649acd4c51 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -548,27 +548,27 @@ func Read(w http.ResponseWriter, r *http.Request) { } if version.Major <= 1 { - legacyServers := make([]tc.ServerNullableV2, 0, len(servers)) + legacyServers := make([]tc.ServerNullableV11, 0, len(servers)) for _, server := range servers { legacyServer, err := server.ToServerV2() if err != nil { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Failed to convert servers to legacy format: %v", err)) return } - legacyServers = append(legacyServers, legacyServer) + legacyServers = append(legacyServers, legacyServer.ServerNullableV11) } api.WriteResp(w, r, legacyServers) return } - legacyServers := make([]tc.ServerNullableV11, 0, len(servers)) + legacyServers := make([]tc.ServerNullableV2, 0, len(servers)) for _, server := range servers { legacyServer, err := server.ToServerV2() if err != nil { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Failed to convert servers to legacy format: %v", err)) return } - legacyServers = append(legacyServers, legacyServer.ServerNullableV11) + legacyServers = append(legacyServers, legacyServer) } api.WriteResp(w, r, legacyServers) } From f06b25de68b0c06da40930acc47fe96b5d6f6e00 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 11:35:07 -0600 Subject: [PATCH 24/87] Changed responses to reference new API version, updated old client methods to use old structures --- lib/go-tc/servers.go | 9 ++++++++- traffic_ops/v2-client/server.go | 8 ++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index 612f69f3e1..1dcf870a10 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -30,8 +30,15 @@ import ( * under the License. */ -// ServersResponse is a list of Servers as a response. +// ServersResponse is the format of a response to a GET request for /servers. type ServersResponse struct { + Response []ServerNullable `json:"response"` + Alerts +} + + +// ServersV2Response is a list of Servers as a response to an API v2 request. +type ServersV2Response struct { Response []Server `json:"response"` Alerts } diff --git a/traffic_ops/v2-client/server.go b/traffic_ops/v2-client/server.go index eb50dcb35d..fe24b6c699 100644 --- a/traffic_ops/v2-client/server.go +++ b/traffic_ops/v2-client/server.go @@ -146,7 +146,7 @@ func (to *Session) GetServers() ([]tc.Server, ReqInf, error) { } defer resp.Body.Close() - var data tc.ServersResponse + var data tc.ServersV2Response err = json.NewDecoder(resp.Body).Decode(&data) return data.Response, reqInf, nil } @@ -161,7 +161,7 @@ func (to *Session) GetServerByID(id int) ([]tc.Server, ReqInf, error) { } defer resp.Body.Close() - var data tc.ServersResponse + var data tc.ServersV2Response if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { return nil, reqInf, err } @@ -182,7 +182,7 @@ func (to *Session) GetServerByHostName(hostName string) ([]tc.Server, ReqInf, er } defer resp.Body.Close() - var data tc.ServersResponse + var data tc.ServersV2Response if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { return nil, reqInf, err } @@ -237,7 +237,7 @@ func (to *Session) GetServersByType(qparams url.Values) ([]tc.Server, ReqInf, er } defer resp.Body.Close() - var data tc.ServersResponse + var data tc.ServersV2Response if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { return nil, reqInf, err } From 89d54fb50ad7c79610621ed1818ef7ece48540a6 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 11:48:24 -0600 Subject: [PATCH 25/87] Updated client to send/return new server structure --- lib/go-tc/servers.go | 3 + traffic_ops/client/server.go | 214 +++++++++++++++-------------------- 2 files changed, 95 insertions(+), 122 deletions(-) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index 1dcf870a10..6690b0f223 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -33,6 +33,9 @@ import ( // ServersResponse is the format of a response to a GET request for /servers. type ServersResponse struct { Response []ServerNullable `json:"response"` + Summary struct { + Count uint64 `json:"count"` + } `json:"summary"` Alerts } diff --git a/traffic_ops/client/server.go b/traffic_ops/client/server.go index 9f688ecbf1..3b414a98b5 100644 --- a/traffic_ops/client/server.go +++ b/traffic_ops/client/server.go @@ -35,157 +35,139 @@ const ( ) // CreateServer creates a Server. -func (to *Session) CreateServer(server tc.Server) (tc.Alerts, ReqInf, error) { +func (to *Session) CreateServer(server tc.ServerNullable) (tc.Alerts, ReqInf, error) { + var alerts tc.Alerts var remoteAddr net.Addr reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} - if server.CachegroupID == 0 && server.Cachegroup != "" { - cg, _, err := to.GetCacheGroupNullableByName(server.Cachegroup) + if (server.CachegroupID == nil || *server.CachegroupID == 0) && server.Cachegroup != nil && *server.Cachegroup != "" { + cg, _, err := to.GetCacheGroupNullableByName(*server.Cachegroup) if err != nil { - return tc.Alerts{}, ReqInf{}, errors.New("no cachegroup named " + server.Cachegroup + ":" + err.Error()) + return alerts, reqInf, fmt.Errorf("no cachegroup named %s: %v", *server.Cachegroup, err) } if len(cg) == 0 { - return tc.Alerts{}, ReqInf{}, errors.New("no cachegroup named " + server.Cachegroup) + return alerts, reqInf, fmt.Errorf("no cachegroup named %s", *server.Cachegroup) } if cg[0].ID == nil { - return tc.Alerts{}, ReqInf{}, errors.New("Cachegroup named " + server.Cachegroup + " has a nil ID") + return alerts, reqInf, fmt.Errorf("Cachegroup named %s has a nil ID", *server.Cachegroup) } - server.CachegroupID = *cg[0].ID + server.CachegroupID = cg[0].ID } - if server.CDNID == 0 && server.CDNName != "" { - c, _, err := to.GetCDNByName(server.CDNName) + if (server.CDNID == nil || *server.CDNID == 0) && server.CDNName != nil && *server.CDNName != "" { + c, _, err := to.GetCDNByName(*server.CDNName) if err != nil { - return tc.Alerts{}, ReqInf{}, errors.New("no CDN named " + server.CDNName + ":" + err.Error()) + return alerts, reqInf, fmt.Errorf("no CDN named %s: %v", *server.CDNName, err) } if len(c) == 0 { - return tc.Alerts{}, ReqInf{}, errors.New("no CDN named " + server.CDNName) + return alerts, reqInf, fmt.Errorf("no CDN named %s", *server.CDNName) } - server.CDNID = c[0].ID + server.CDNID = &c[0].ID } - if server.PhysLocationID == 0 && server.PhysLocation != "" { - ph, _, err := to.GetPhysLocationByName(server.PhysLocation) + if (server.PhysLocationID == nil || *server.PhysLocationID == 0) && server.PhysLocation != nil && *server.PhysLocation != "" { + ph, _, err := to.GetPhysLocationByName(*server.PhysLocation) if err != nil { - return tc.Alerts{}, ReqInf{}, errors.New("no physlocation named " + server.PhysLocation + ":" + err.Error()) + return alerts, reqInf, fmt.Errorf("no physlocation named %s: %v", *server.PhysLocation, err) } if len(ph) == 0 { - return tc.Alerts{}, ReqInf{}, errors.New("no physlocation named " + server.PhysLocation) + return alerts, reqInf, fmt.Errorf("no physlocation named %s", *server.PhysLocation) } - server.PhysLocationID = ph[0].ID + server.PhysLocationID = &ph[0].ID } - if server.ProfileID == 0 && server.Profile != "" { - pr, _, err := to.GetProfileByName(server.Profile) + if (server.ProfileID == nil || *server.ProfileID == 0) && server.Profile != nil && *server.Profile != "" { + pr, _, err := to.GetProfileByName(*server.Profile) if err != nil { - return tc.Alerts{}, ReqInf{}, errors.New("no profile named " + server.Profile + ":" + err.Error()) + return alerts, reqInf, fmt.Errorf("no profile named %s: %v", *server.Profile, err) } if len(pr) == 0 { - return tc.Alerts{}, ReqInf{}, errors.New("no profile named " + server.Profile) + return alerts, reqInf, fmt.Errorf("no profile named %s", *server.Profile) } - server.ProfileID = pr[0].ID + server.ProfileID = &pr[0].ID } - if server.StatusID == 0 && server.Status != "" { - st, _, err := to.GetStatusByName(server.Status) + if (server.StatusID == nil || *server.StatusID == 0) && server.Status != nil && *server.Status != "" { + st, _, err := to.GetStatusByName(*server.Status) if err != nil { - return tc.Alerts{}, ReqInf{}, errors.New("no status named " + server.Status + ":" + err.Error()) + return alerts, reqInf, fmt.Errorf("no status named %s: %v", *server.Status, err) } if len(st) == 0 { - return tc.Alerts{}, ReqInf{}, errors.New("no status named " + server.Status) + return alerts, reqInf, fmt.Errorf("no status named %s", *server.Status) } - server.StatusID = st[0].ID + server.StatusID = &st[0].ID } - if server.TypeID == 0 && server.Type != "" { + if (server.TypeID == nil || *server.TypeID == 0) && server.Type != "" { ty, _, err := to.GetTypeByName(server.Type) if err != nil { - return tc.Alerts{}, ReqInf{}, errors.New("no type named " + server.Type + ":" + err.Error()) + return alerts, reqInf, fmt.Errorf("no type named %s: %v", server.Type, err) } if len(ty) == 0 { - return tc.Alerts{}, ReqInf{}, errors.New("no type named " + server.Type) + return alerts, reqInf, fmt.Errorf("no type named %s", server.Type) } - server.TypeID = ty[0].ID + server.TypeID = &ty[0].ID } + reqBody, err := json.Marshal(server) if err != nil { - return tc.Alerts{}, reqInf, err + return alerts, reqInf, err } resp, remoteAddr, err := to.request(http.MethodPost, API_SERVERS, reqBody) + reqInf.RemoteAddr = remoteAddr if err != nil { - return tc.Alerts{}, reqInf, err + return alerts, reqInf, err } defer resp.Body.Close() - var alerts tc.Alerts + err = json.NewDecoder(resp.Body).Decode(&alerts) - return alerts, reqInf, nil + return alerts, reqInf, err } // UpdateServerByID updates a Server by ID. -func (to *Session) UpdateServerByID(id int, server tc.Server) (tc.Alerts, ReqInf, error) { - +func (to *Session) UpdateServerByID(id int, server tc.ServerNullable) (tc.Alerts, ReqInf, error) { + var alerts tc.Alerts var remoteAddr net.Addr - reqBody, err := json.Marshal(server) reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} + + reqBody, err := json.Marshal(server) if err != nil { - return tc.Alerts{}, reqInf, err + return alerts, reqInf, err } + route := fmt.Sprintf("%s/%d", API_SERVERS, id) resp, remoteAddr, err := to.request(http.MethodPut, route, reqBody) + reqInf.RemoteAddr = remoteAddr if err != nil { - return tc.Alerts{}, reqInf, err + return alerts, reqInf, err } defer resp.Body.Close() - var alerts tc.Alerts + err = json.NewDecoder(resp.Body).Decode(&alerts) - return alerts, reqInf, nil + return alerts, reqInf, err } // GetServers returns a list of Servers. -func (to *Session) GetServers() ([]tc.Server, ReqInf, error) { - resp, remoteAddr, err := to.request(http.MethodGet, API_SERVERS, nil) - reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} - if err != nil { - return nil, reqInf, err +// The 'params' parameter can be used to optionally pass URL "query string +// parameters" in the request. +// It returns, in order, the requested servers, any Alerts the API returned, +// the returned summary.count value, a request info object, and any error that +// occurred. +func (to *Session) GetServers(params *url.Values) ([]tc.ServerNullable, tc.Alerts, uint64, ReqInf, error) { + route := API_SERVERS + if params != nil { + route += "?" + params.Encode() } - defer resp.Body.Close() - var data tc.ServersResponse - err = json.NewDecoder(resp.Body).Decode(&data) - return data.Response, reqInf, nil -} + var alerts tc.Alerts -// GetServerByID GETs a Server by the Server ID. -func (to *Session) GetServerByID(id int) ([]tc.Server, ReqInf, error) { - route := fmt.Sprintf("%s?id=%d", API_SERVERS, id) resp, remoteAddr, err := to.request(http.MethodGet, route, nil) reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} if err != nil { - return nil, reqInf, err - } - defer resp.Body.Close() - - var data tc.ServersResponse - if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { - return nil, reqInf, err - } - - return data.Response, reqInf, nil -} - -// GetServerByHostName GETs Servers by the Server hostname. -func (to *Session) GetServerByHostName(hostName string) ([]tc.Server, ReqInf, error) { - url := fmt.Sprintf("%s?hostName=%s", API_SERVERS, hostName) - resp, remoteAddr, err := to.request(http.MethodGet, url, nil) - reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} - if err != nil { - return nil, reqInf, err + return nil, alerts, 0, reqInf, err } defer resp.Body.Close() var data tc.ServersResponse - if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { - return nil, reqInf, err - } - - return data.Response, reqInf, nil + err = json.NewDecoder(resp.Body).Decode(&data) + return data.Response, data.Alerts, data.Summary.Count, reqInf, err } // GetServerDetailsByHostName GETs Servers by the Server hostname. @@ -223,70 +205,58 @@ func (to *Session) DeleteServerByID(id int) (tc.Alerts, ReqInf, error) { return alerts, reqInf, nil } -// GetServersByType returns all servers that match the given query parameter filters, NOT -// - as the name might imply - all servers of a specific type (though type can be specified -// in the query parameters). -func (to *Session) GetServersByType(qparams url.Values) ([]tc.Server, ReqInf, error) { - url := fmt.Sprintf("%s?%s", API_SERVERS, qparams.Encode()) - resp, remoteAddr, err := to.request(http.MethodGet, url, nil) - reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} - if err != nil { - return nil, reqInf, err - } - defer resp.Body.Close() - - var data tc.ServersResponse - if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { - return nil, reqInf, err - } - - return data.Response, reqInf, nil -} - -// GetServerFQDN returns the Fully Qualified Domain Name (FQDN) of the first server found to -// have the Host Name 'n'. -func (to *Session) GetServerFQDN(n string) (string, ReqInf, error) { +// GetServerFQDN returns the Fully Qualified Domain Name (FQDN) of the first +// server found to have the Host Name 'n'. +func (to *Session) GetServerFQDN(n string) (string, tc.Alerts, ReqInf, error) { // TODO fix to only request one server - fdn := "" - servers, reqInf, err := to.GetServers() + var params url.Values + params.Add("hostName", n) + + servers, alerts, _, reqInf, err := to.GetServers(¶ms) if err != nil { - return "Error", reqInf, err + return "", alerts, reqInf, err } + var fdn string for _, server := range servers { - if server.HostName == n { - fdn = fmt.Sprintf("%s.%s", server.HostName, server.DomainName) + if server.HostName != nil && server.DomainName != nil { + fdn = fmt.Sprintf("%s.%s", *server.HostName, *server.DomainName) } } + if fdn == "" { - return "Error", reqInf, fmt.Errorf("No Server %s found", n) + err = fmt.Errorf("No Server %s found", n) } - return fdn, reqInf, nil + + return fdn, alerts, reqInf, err } -// GetServersShortNameSearch returns all of the Host Names of servers that contain 'shortname'. -func (to *Session) GetServersShortNameSearch(shortname string) ([]string, ReqInf, error) { +// GetServersShortNameSearch returns all of the Host Names of servers that +// contain 'shortname'. +func (to *Session) GetServersShortNameSearch(shortname string) ([]string, tc.Alerts, ReqInf, error) { var serverlst []string - servers, reqInf, err := to.GetServers() + servers, alerts, _, reqInf, err := to.GetServers(nil) if err != nil { - serverlst = append(serverlst, "N/A") - return serverlst, reqInf, err + return serverlst, alerts, reqInf, err } + for _, server := range servers { - if strings.Contains(server.HostName, shortname) { - serverlst = append(serverlst, server.HostName) + if server.HostName != nil && strings.Contains(*server.HostName, shortname) { + serverlst = append(serverlst, *server.HostName) } } + if len(serverlst) == 0 { - serverlst = append(serverlst, "N/A") - return serverlst, reqInf, fmt.Errorf("No Servers Found") + err = errors.New("No Servers Found") } - return serverlst, reqInf, nil + + return serverlst, alerts, reqInf, err } -// AssignDeliveryServiceIDsToServerID assigns a set of Delivery Services to a single server, optionally -// replacing any and all existing assignments. 'server' should be the requested server's ID, 'dsIDs' -// should be a slice of the requested Delivery Services' IDs. If 'replace' is 'true', existing +// AssignDeliveryServiceIDsToServerID assigns a set of Delivery Services to a +// single server, optionally replacing any and all existing assignments. +// 'server' should be the requested server's ID, 'dsIDs' should be a slice of +// the requested Delivery Services' IDs. If 'replace' is 'true', existing // assignments to the server will be replaced. func (to *Session) AssignDeliveryServiceIDsToServerID(server int, dsIDs []int, replace bool) (tc.Alerts, ReqInf, error) { // datatypes here match the library tc.Server's and tc.DeliveryService's ID fields From caaa6ad1ca256a5a61c91982c96f402cfc436a79 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 13:09:14 -0600 Subject: [PATCH 26/87] Changed tc-fixtures to use new server objects --- traffic_ops/testing/api/v3/tc-fixtures.json | 470 ++++++++++++++------ 1 file changed, 335 insertions(+), 135 deletions(-) diff --git a/traffic_ops/testing/api/v3/tc-fixtures.json b/traffic_ops/testing/api/v3/tc-fixtures.json index b1007a3baf..b2117cf76d 100644 --- a/traffic_ops/testing/api/v3/tc-fixtures.json +++ b/traffic_ops/testing/api/v3/tc-fixtures.json @@ -1629,14 +1629,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 9000, - "interfaceName": "bond0", - "ip6Address": "2345:1234:12:8::1/64", - "ip6Gateway": "2345:1234:12:8::1", - "ipAddress": "127.0.0.21", - "ipGateway": "127.0.0.21", - "ipIsService": true, - "ipNetmask": "255.255.255.252", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "127.0.0.21/30", + "gateway": "127.0.0.21", + "serviceAddress": true + }, + { + "address": "2345:1234:12:8::1/64", + "gateway": "2345:1234:12:8::1", + "serviceAddress": false + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 9000, + "name": "bond0" + } + ], "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", @@ -1667,14 +1679,21 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 1500, - "interfaceName": "eth0", - "ip6Address": "", - "ip6Gateway": "", - "ipAddress": "0.0.0.0", - "ipGateway": "0.0.0.0", - "ipIsService": true, - "ipNetmask": "0.0.0.0", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "0.0.0.0/0", + "gateway": "0.0.0.0", + "serviceAddress": true + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 1500, + "name": "eth0" + } + ], "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", @@ -1705,14 +1724,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 1500, - "interfaceName": "eth1", - "ip6Address": "2345:1234:12:8::2/64", - "ip6Gateway": "2345:1234:12:8::2", - "ipAddress": "127.0.0.11", - "ipGateway": "127.0.0.11", - "ipIsService": true, - "ipNetmask": "255.255.252.0", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "127.0.0.11/22", + "gateway": "127.0.0.11", + "serviceAddress": true + }, + { + "address": "2345:1234:12:8::2/64", + "gateway": "2345:1234:12:8::2", + "serviceAddress": false + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 1500, + "name": "eth1" + } + ], "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", @@ -1743,14 +1774,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 9000, - "interfaceName": "bond0", - "ip6Address": "2345:1234:12:8::3/64", - "ip6Gateway": "2345:1234:12:8::3", - "ipAddress": "127.0.0.12", - "ipGateway": "127.0.0.1", - "ipIsService": true, - "ipNetmask": "255.255.255.252", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "127.0.0.12/30", + "gateway": "127.0.0.1", + "serviceAddress": true + }, + { + "address": "2345:1234:12:8::3/64", + "gateway": "2345:1234:12:8::3", + "serviceAddress": false + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 9000, + "name": "bond0" + } + ], "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", @@ -1781,14 +1824,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 9000, - "interfaceName": "bond0", - "ip6Address": "2345:1234:12:2::4/64", - "ip6Gateway": "2345:1234:12:8::4", - "ipAddress": "127.0.0.13", - "ipGateway": "127.0.0.1", - "ipIsService": true, - "ipNetmask": "255.255.255.252", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "2345:1234:12:2::4/64", + "gateway": "2345:1234:12:2::4", + "serviceAddress": false + }, + { + "address": "127.0.0.13/30", + "gateway": "127.0.0.1", + "serviceAddress": true + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 9000, + "name": "bond0" + } + ], "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", @@ -1819,14 +1874,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 9000, - "interfaceName": "bond0", - "ip6Address": "2345:1234:12:8::5/64", - "ip6Gateway": "2345:1234:12:8::5", - "ipAddress": "127.0.0.14", - "ipGateway": "127.0.0.1", - "ipIsService": true, - "ipNetmask": "255.255.255.252", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "2345:1234:12:8::5/64", + "gateway": "2345:1234:12:8::5", + "serviceAddress": false + }, + { + "address": "127.0.0.14/30", + "gateway": "127.0.0.1", + "serviceAddress": true + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 9000, + "name": "bond0" + } + ], "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", @@ -1857,13 +1924,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 9000, - "interfaceName": "bond0", - "ip6Address": "2345:1234:12:d::6/64", - "ip6Gateway": "2345:1234:12:d::6", - "ipAddress": "127.0.0.15", - "ipGateway": "127.0.0.7", - "ipIsService": true, + "interfaces": [ + { + "ipAddresses": [ + { + "address": "2345:1234:12:d::6/64", + "gateway": "2345:1234:12:d::6", + "serviceAddress": false + }, + { + "address": "127.0.0.15/30", + "gateway": "127.0.0.7", + "serviceAddress": true + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 9000, + "name": "bond0" + } + ], "ipNetmask": "255.255.255.252", "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", @@ -1895,14 +1975,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 9000, - "interfaceName": "bond0", - "ip6Address": "2345:1234:12:d::7/64", - "ip6Gateway": "2345:1234:12:d::7", - "ipAddress": "127.0.0.16", - "ipGateway": "127.0.0.7", - "ipIsService": true, - "ipNetmask": "255.255.255.252", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "2345:1234:12:d::7/64", + "gateway": "2345:1234:12:d::7", + "serviceAddress": false + }, + { + "address": "127.0.0.16/30", + "gateway": "127.0.0.7", + "serviceAddress": true + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 9000, + "name": "bond0" + } + ], "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", @@ -1933,14 +2025,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 9000, - "interfaceName": "bond0", - "ip6Address": "2345:1234:12:d::8/64", - "ip6Gateway": "2345:1234:12:d::8", - "ipAddress": "127.0.0.17", - "ipGateway": "127.0.0.17", - "ipIsService": true, - "ipNetmask": "255.255.255.252", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "2345:1234:12:d::8/64", + "gateway": "2345:1234:12:d::8", + "serviceAddress": false + }, + { + "address": "127.0.0.17/30", + "gateway": "127.0.0.17", + "serviceAddress": true + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 9000, + "name": "bond0" + } + ], "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", @@ -1971,14 +2075,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 9000, - "interfaceName": "bond0", - "ip6Address": "2345:1234:12:d::9/64", - "ip6Gateway": "2345:1234:12:d::9", - "ipAddress": "127.0.0.18", - "ipGateway": "127.0.0.18", - "ipIsService": true, - "ipNetmask": "255.255.255.252", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "127.0.0.18/30", + "gateway": "127.0.0.18", + "serviceAddress": true + }, + { + "address": "2345:1234:12:d::9/64", + "gateway": "2345:1234:12:d::9", + "serviceAddress": false + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 9000, + "name": "bond0" + } + ], "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", @@ -2009,14 +2125,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 9000, - "interfaceName": "bond0", - "ip6Address": "2345:1234:12:9::10/64", - "ip6Gateway": "2345:1234:12:9::10", - "ipAddress": "127.0.0.2", - "ipGateway": "127.0.0.2", - "ipIsService": true, - "ipNetmask": "255.255.255.252", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "127.0.0.2/30", + "gateway": "127.0.0.2", + "serviceAddress": true + }, + { + "address": "2345:1234:12:9::10/64", + "gateway": "2345:1234:12:9::10", + "serviceAddress": false + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 9000, + "name": "bond0" + } + ], "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", @@ -2047,14 +2175,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 9000, - "interfaceName": "bond0", - "ip6Address": "2345:1234:12:b::11/64", - "ip6Gateway": "2345:1234:12:b::11", - "ipAddress": "127.0.0.4", - "ipIsService": true, - "ipGateway": "127.0.0.4", - "ipNetmask": "255.255.255.252", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "127.0.0.4/30", + "gateway": "127.0.0.4", + "serviceAddress": true + }, + { + "address": "2345:1234:12:b::11/64", + "gateway": "2345:1234:12:b::11", + "serviceAddress": false + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 9000, + "name": "bond0" + } + ], "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", @@ -2085,14 +2225,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 9000, - "interfaceName": "bond0", - "ip6Address": "2345:1234:12:b::13/64", - "ip6Gateway": "2345:1234:12:b::13", - "ipAddress": "127.0.0.31", - "ipIsService": true, - "ipGateway": "127.0.0.4", - "ipNetmask": "255.255.255.0", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "127.0.0.31/24", + "gateway": "127.0.0.4", + "serviceAddress": true + }, + { + "address": "2345:1234:12:b::13/64", + "gateway": "2345:1234:12:b::13", + "serviceAddress": false + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 9000, + "name": "bond0" + } + ], "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -2122,14 +2274,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 1500, - "interfaceName": "eth1", - "ip6Address": "2345:1234:12:b::12/64", - "ip6Gateway": "2345:1234:12:b::12", - "ipAddress": "127.0.0.1", - "ipIsService": true, - "ipGateway": "127.0.0.1", - "ipNetmask": "255.255.252.0", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "127.0.0.1/22", + "gateway": "127.0.0.1", + "serviceAddress": true + }, + { + "address": "2345:1234:12:b::12/64", + "gateway": "2345:1234:12:b::12", + "serviceAddress": false + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 1500, + "name": "eth1" + } + ], "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", @@ -2160,14 +2324,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 9000, - "interfaceName": "bond0", - "ip6Address": "2345:1234:12:8::20/64", - "ip6Gateway": "2345:1234:12:8::20", - "ipAddress": "127.0.0.1", - "ipIsService": true, - "ipGateway": "127.0.0.1", - "ipNetmask": "255.255.255.252", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "127.0.0.1/30", + "gateway": "127.0.0.1", + "serviceAddress": true + }, + { + "address": "2345:1234:12:8::20/64", + "gateway": "2345:1234:12:8::20", + "serviceAddress": false + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 9000, + "name": "bond0" + } + ], "lastUpdated": "2018-03-28T17:30:00.220351+00:00", "mgmtIpAddress": "", "mgmtIpGateway": "", @@ -2198,14 +2374,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 9000, - "interfaceName": "bond0", - "ip6Address": "::13/64", - "ip6Gateway": "2345:1234:12:b::13", - "ipAddress": "127.0.0.100", - "ipIsService": true, - "ipGateway": "127.0.0.4", - "ipNetmask": "255.255.255.0", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "::13/64", + "gateway": "2345:1234:12:b::13", + "serviceAddress": false + }, + { + "address": "127.0.0.100/24", + "gateway": "127.0.0.4", + "serviceAddress": true + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 9000, + "name": "bond0" + } + ], "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", @@ -2235,14 +2423,26 @@ "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 9000, - "interfaceName": "bond0", - "ip6Address": "::14/64", - "ip6Gateway": "2345:1234:12:b::13", - "ipAddress": "127.0.0.101", - "ipIsService": true, - "ipGateway": "127.0.0.4", - "ipNetmask": "255.255.255.0", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "::14/64", + "gateway": "2345:1234:12:b::13", + "serviceAddress": false + }, + { + "address": "127.0.0.101/24", + "gateway": "127.0.0.4", + "serviceAddress": true + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 9000, + "name": "bond0" + } + ], "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", From 52a4a08701d730243aaa343fd34e38584f74c2c5 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 16:13:36 -0600 Subject: [PATCH 27/87] made TS use v2 client --- traffic_stats/traffic_stats.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traffic_stats/traffic_stats.go b/traffic_stats/traffic_stats.go index 0ee4076cb3..dc15582635 100644 --- a/traffic_stats/traffic_stats.go +++ b/traffic_stats/traffic_stats.go @@ -38,7 +38,7 @@ import ( "github.com/apache/trafficcontrol/lib/go-tc" "github.com/apache/trafficcontrol/lib/go-util" - "github.com/apache/trafficcontrol/traffic_ops/client" + "github.com/apache/trafficcontrol/traffic_ops/v2-client" log "github.com/cihub/seelog" influx "github.com/influxdata/influxdb/client/v2" ) From 4f83eafbbc2ba1cc0dc6a0ebb8e28402c157b139 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 16:56:56 -0600 Subject: [PATCH 28/87] Fixed teardowns --- traffic_ops/testing/api/v1/todb_test.go | 3 ++- traffic_ops/testing/api/v2/todb_test.go | 3 ++- traffic_ops/testing/api/v3/todb_test.go | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/traffic_ops/testing/api/v1/todb_test.go b/traffic_ops/testing/api/v1/todb_test.go index aa6ad9f94c..e86cec406c 100644 --- a/traffic_ops/testing/api/v1/todb_test.go +++ b/traffic_ops/testing/api/v1/todb_test.go @@ -306,7 +306,6 @@ func Teardown(db *sql.DB) error { DELETE FROM api_capability; DELETE FROM deliveryservices_required_capability; DELETE FROM server_server_capability; - DELETE FROM server_server_capability; DELETE FROM server_capability; DELETE FROM to_extension; DELETE FROM staticdnsentry; @@ -327,6 +326,8 @@ func Teardown(db *sql.DB) error { DELETE FROM origin; DELETE FROM ip_address; DELETE FROM interface; + DELETE FROM ip_address; + DELETE FROM interface; DELETE FROM server; DELETE FROM phys_location; DELETE FROM region; diff --git a/traffic_ops/testing/api/v2/todb_test.go b/traffic_ops/testing/api/v2/todb_test.go index 4c54d47d40..b8e7246385 100644 --- a/traffic_ops/testing/api/v2/todb_test.go +++ b/traffic_ops/testing/api/v2/todb_test.go @@ -306,7 +306,6 @@ func Teardown(db *sql.DB) error { DELETE FROM api_capability; DELETE FROM deliveryservices_required_capability; DELETE FROM server_server_capability; - DELETE FROM server_server_capability; DELETE FROM server_capability; DELETE FROM to_extension; DELETE FROM staticdnsentry; @@ -325,6 +324,8 @@ func Teardown(db *sql.DB) error { DELETE FROM deliveryservice_server; DELETE FROM deliveryservice; DELETE FROM origin; + DELETE FROM ip_address; + DELETE FROM interface; DELETE FROM server; DELETE FROM phys_location; DELETE FROM region; diff --git a/traffic_ops/testing/api/v3/todb_test.go b/traffic_ops/testing/api/v3/todb_test.go index d0511d1755..abec74acfe 100644 --- a/traffic_ops/testing/api/v3/todb_test.go +++ b/traffic_ops/testing/api/v3/todb_test.go @@ -306,7 +306,6 @@ func Teardown(db *sql.DB) error { DELETE FROM api_capability; DELETE FROM deliveryservices_required_capability; DELETE FROM server_server_capability; - DELETE FROM server_server_capability; DELETE FROM server_capability; DELETE FROM to_extension; DELETE FROM staticdnsentry; @@ -325,6 +324,8 @@ func Teardown(db *sql.DB) error { DELETE FROM deliveryservice_server; DELETE FROM deliveryservice; DELETE FROM origin; + DELETE FROM ip_address; + DELETE FROM interface; DELETE FROM server; DELETE FROM phys_location; DELETE FROM region; From ed4667538842c152300ae8f9c3bbe684588773bb Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 16:58:21 -0600 Subject: [PATCH 29/87] Fixed renaming a struct which breaks a vendored version of the client for ORT..... --- lib/go-tc/servers.go | 10 +++++----- traffic_ops/client/server.go | 2 +- traffic_ops/v2-client/server.go | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index 6690b0f223..b0a072f4f4 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -30,8 +30,8 @@ import ( * under the License. */ -// ServersResponse is the format of a response to a GET request for /servers. -type ServersResponse struct { +// ServersResponsev3 is the format of a response to a GET request for /servers. +type ServersResponsev3 struct { Response []ServerNullable `json:"response"` Summary struct { Count uint64 `json:"count"` @@ -39,9 +39,9 @@ type ServersResponse struct { Alerts } - -// ServersV2Response is a list of Servers as a response to an API v2 request. -type ServersV2Response struct { +// ServersResponse is a list of Servers as a response to an API v2 request. +// This can't change because it will break ORT. Unfortunately. +type ServersResponse struct { Response []Server `json:"response"` Alerts } diff --git a/traffic_ops/client/server.go b/traffic_ops/client/server.go index 3b414a98b5..0c8fb728ea 100644 --- a/traffic_ops/client/server.go +++ b/traffic_ops/client/server.go @@ -165,7 +165,7 @@ func (to *Session) GetServers(params *url.Values) ([]tc.ServerNullable, tc.Alert } defer resp.Body.Close() - var data tc.ServersResponse + var data tc.ServersResponsev3 err = json.NewDecoder(resp.Body).Decode(&data) return data.Response, data.Alerts, data.Summary.Count, reqInf, err } diff --git a/traffic_ops/v2-client/server.go b/traffic_ops/v2-client/server.go index fe24b6c699..eb50dcb35d 100644 --- a/traffic_ops/v2-client/server.go +++ b/traffic_ops/v2-client/server.go @@ -146,7 +146,7 @@ func (to *Session) GetServers() ([]tc.Server, ReqInf, error) { } defer resp.Body.Close() - var data tc.ServersV2Response + var data tc.ServersResponse err = json.NewDecoder(resp.Body).Decode(&data) return data.Response, reqInf, nil } @@ -161,7 +161,7 @@ func (to *Session) GetServerByID(id int) ([]tc.Server, ReqInf, error) { } defer resp.Body.Close() - var data tc.ServersV2Response + var data tc.ServersResponse if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { return nil, reqInf, err } @@ -182,7 +182,7 @@ func (to *Session) GetServerByHostName(hostName string) ([]tc.Server, ReqInf, er } defer resp.Body.Close() - var data tc.ServersV2Response + var data tc.ServersResponse if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { return nil, reqInf, err } @@ -237,7 +237,7 @@ func (to *Session) GetServersByType(qparams url.Values) ([]tc.Server, ReqInf, er } defer resp.Body.Close() - var data tc.ServersV2Response + var data tc.ServersResponse if err := json.NewDecoder(resp.Body).Decode(&data); err != nil { return nil, reqInf, err } From 66ec6de6afc156e60c65b421341b7a2392ed6c03 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 16:59:00 -0600 Subject: [PATCH 30/87] Fixed bad error message in v3 validation --- traffic_ops/traffic_ops_golang/server/servers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 649acd4c51..2f77c8ec7c 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -487,7 +487,7 @@ func validateV3(s tc.ServerNullable, tx *sql.Tx) (string, error) { if addr.Gateway != nil { if gateway := net.ParseIP(*addr.Gateway); gateway == nil { - errs = append(errs, fmt.Errorf("%s: gateway: %v", ruleName, err)) + errs = append(errs, fmt.Errorf("%s: gateway: could not parse '%s' as a network gateway", ruleName, *addr.Gateway)) } else if (gateway.To4() == nil && parsedIP.To4() != nil) || (gateway.To4() != nil && parsedIP.To4() == nil) { errs = append(errs, errors.New(ruleName + ": address family mismatch between address and gateway")) } From 666f4d4f7be5b8ec67d4168ba2824ef34daa5ba2 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 17:42:04 -0600 Subject: [PATCH 31/87] Fixed possible segfault in test failure state --- traffic_ops/testing/api/v3/cachegroups_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/traffic_ops/testing/api/v3/cachegroups_test.go b/traffic_ops/testing/api/v3/cachegroups_test.go index 726ee3945f..7fe45f3e10 100644 --- a/traffic_ops/testing/api/v3/cachegroups_test.go +++ b/traffic_ops/testing/api/v3/cachegroups_test.go @@ -45,6 +45,7 @@ func CreateTestCacheGroups(t *testing.T) { resp, _, err = TOSession.CreateCacheGroupNullable(cg) if err != nil { t.Errorf("could not CREATE cachegroups: %v, request: %v", err, cg) + continue } // Testing 'join' fields during create From 6a2e912dd2f7848ee14f1db04b94bab56424f60e Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 20:13:09 -0600 Subject: [PATCH 32/87] Fixed null response for no servers --- traffic_ops/traffic_ops_golang/server/servers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 2f77c8ec7c..a6f663db00 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -718,7 +718,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( } } - var returnable []tc.ServerNullable + returnable := make([]tc.ServerNullable, 0, len(servers)) for _, server := range servers { returnable = append(returnable, server) } From 69ecadda1355987949c71cd34eb432b177534db5 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 22:11:38 -0600 Subject: [PATCH 33/87] Fixed v3 tests for new server model --- .../testing/api/v3/cachegroups_test.go | 2 + .../v3/cachegroupsdeliveryservices_test.go | 11 +- traffic_ops/testing/api/v3/crconfig_test.go | 6 +- ...veryservices_required_capabilities_test.go | 12 +- .../api/v3/deliveryserviceservers_test.go | 43 +++-- traffic_ops/testing/api/v3/servers_test.go | 143 ++++++++++++--- ...vers_to_deliveryservice_assignment_test.go | 45 +++-- .../api/v3/serverservercapability_test.go | 22 ++- .../testing/api/v3/serverupdatestatus_test.go | 170 +++++++++++++----- .../testing/api/v3/traffic_control_test.go | 2 +- 10 files changed, 344 insertions(+), 112 deletions(-) diff --git a/traffic_ops/testing/api/v3/cachegroups_test.go b/traffic_ops/testing/api/v3/cachegroups_test.go index 7fe45f3e10..c69bd86ed2 100644 --- a/traffic_ops/testing/api/v3/cachegroups_test.go +++ b/traffic_ops/testing/api/v3/cachegroups_test.go @@ -314,6 +314,8 @@ func DeleteTestCacheGroups(t *testing.T) { if err != nil { t.Errorf("cannot DELETE CacheGroup by name: '%s' %v", *respCG.Name, err) } + + t.Logf("Deleted Cache Group '%s'", *respCG.Name) // Retrieve the CacheGroup to see if it got deleted cgs, _, err := TOSession.GetCacheGroupNullableByName(*cg.Name) if err != nil { diff --git a/traffic_ops/testing/api/v3/cachegroupsdeliveryservices_test.go b/traffic_ops/testing/api/v3/cachegroupsdeliveryservices_test.go index f245328d66..1ae098db52 100644 --- a/traffic_ops/testing/api/v3/cachegroupsdeliveryservices_test.go +++ b/traffic_ops/testing/api/v3/cachegroupsdeliveryservices_test.go @@ -17,6 +17,7 @@ package v3 import ( "net/http" + "net/url" "testing" ) @@ -103,8 +104,10 @@ func CreateTestCachegroupsDeliveryServices(t *testing.T) { t.Fatal("setting cachegroup delivery services returned success, but no servers set") } + params := url.Values{} for _, serverName := range resp.Response.ServerNames { - servers, _, err := TOSession.GetServerByHostName(string(serverName)) + params.Set("hostName", string(serverName)) + servers, _, _, _, err := TOSession.GetServers(¶ms) if err != nil { t.Fatalf("getting server: %v", err) } @@ -112,7 +115,11 @@ func CreateTestCachegroupsDeliveryServices(t *testing.T) { t.Fatalf("getting servers: expected 1 got %v", len(servers)) } server := servers[0] - serverID := server.ID + if server.ID == nil { + t.Errorf("Server %s had nil ID", serverName) + continue + } + serverID := *server.ID serverDSes, _, err := TOSession.GetDeliveryServicesByServer(serverID) diff --git a/traffic_ops/testing/api/v3/crconfig_test.go b/traffic_ops/testing/api/v3/crconfig_test.go index d4e3309369..b65edd63fb 100644 --- a/traffic_ops/testing/api/v3/crconfig_test.go +++ b/traffic_ops/testing/api/v3/crconfig_test.go @@ -51,14 +51,14 @@ func UpdateTestCRConfigSnapshot(t *testing.T) { } // create an ANY_MAP DS assignment to verify that it doesn't show up in the CRConfig - servers, _, err := TOSession.GetServers() + servers, _, _, _, err := TOSession.GetServers(nil) if err != nil { t.Errorf("GetServers err expected nil, actual %+v", err) } serverID := 0 for _, server := range servers { - if server.Type == "EDGE" && server.CDNName == "cdn1" { - serverID = server.ID + if server.Type == "EDGE" && server.CDNName != nil && *server.CDNName == "cdn1" && server.ID != nil { + serverID = *server.ID break } } diff --git a/traffic_ops/testing/api/v3/deliveryservices_required_capabilities_test.go b/traffic_ops/testing/api/v3/deliveryservices_required_capabilities_test.go index 61f6fd4008..36179d33f7 100644 --- a/traffic_ops/testing/api/v3/deliveryservices_required_capabilities_test.go +++ b/traffic_ops/testing/api/v3/deliveryservices_required_capabilities_test.go @@ -17,6 +17,7 @@ package v3 import ( "fmt" + "net/url" "strings" "testing" @@ -181,7 +182,10 @@ func InvalidDeliveryServicesRequiredCapabilityAddition(t *testing.T) { } // First assign current capabilities to edge server so we can assign it to the DS - servers, _, err := TOSession.GetServerByHostName("atlanta-edge-01") + // TODO: DON'T hard-code hostnames! + params := url.Values{} + params.Add("hostName", "atlanta-edge-01") + servers, _, _, _, err := TOSession.GetServers(¶ms) if err != nil { t.Fatalf("cannot GET Server by hostname: %v", err) } @@ -189,8 +193,12 @@ func InvalidDeliveryServicesRequiredCapabilityAddition(t *testing.T) { t.Fatal("need at least one server to test invalid ds required capability assignment") } + if servers[0].ID == nil { + t.Fatal("server 'atlanta-edge-01' had nil ID") + } + dsID := capabilities[0].DeliveryServiceID - sID := servers[0].ID + sID := *servers[0].ID serverCaps := []tc.ServerServerCapability{} for _, cap := range capabilities { diff --git a/traffic_ops/testing/api/v3/deliveryserviceservers_test.go b/traffic_ops/testing/api/v3/deliveryserviceservers_test.go index 9b0f444b01..d936cd327a 100644 --- a/traffic_ops/testing/api/v3/deliveryserviceservers_test.go +++ b/traffic_ops/testing/api/v3/deliveryserviceservers_test.go @@ -18,6 +18,7 @@ package v3 import ( "errors" "net/http" + "net/url" "strings" "testing" @@ -120,24 +121,29 @@ func CreateTestDeliveryServiceServersWithRequiredCapabilities(t *testing.T) { for _, ctc := range testCases { t.Run(ctc.description, func(t *testing.T) { - servers, _, err := TOSession.GetServerByHostName(ctc.serverName) + params := url.Values{} + params.Add("hostName", ctc.serverName) + servers, _, _, _, err := TOSession.GetServers(¶ms) if err != nil { t.Fatalf("cannot GET Server by hostname: %v", err) } server := servers[0] + if server.ID == nil { + t.Fatalf("server %s had nil ID", ctc.serverName) + } _, _, err = TOSession.CreateDeliveryServicesRequiredCapability(ctc.capability) if err != nil { t.Fatalf("*POST delivery service required capability: %v", err) } - ctc.ssc.ServerID = &server.ID + ctc.ssc.ServerID = server.ID _, _, err = TOSession.CreateServerServerCapability(ctc.ssc) if err != nil { t.Fatalf("could not POST the server capability %v to server %v: %v", *ctc.ssc.ServerCapability, *ctc.ssc.Server, err) } - _, _, got := TOSession.CreateDeliveryServiceServers(*ctc.capability.DeliveryServiceID, []int{server.ID}, true) + _, _, got := TOSession.CreateDeliveryServiceServers(*ctc.capability.DeliveryServiceID, []int{*server.ID}, true) if (ctc.err == nil && got != nil) || (ctc.err != nil && !strings.Contains(got.Error(), ctc.err.Error())) { t.Fatalf("expected ctc.err to contain %v, got %v", ctc.err, got) } @@ -161,8 +167,10 @@ func CreateTestMSODSServerWithReqCap(t *testing.T) { } // Associate origin server to msods1 even though it does not have req cap - - servers, _, err := TOSession.GetServerByHostName("denver-mso-org-01") + // TODO: DON'T hard-code server hostnames! + params := url.Values{} + params.Add("hostName", "denver-mso-org-01") + servers, _, _, _, err := TOSession.GetServers(¶ms) if err != nil { t.Fatalf("GET server denver-mso-org-01: %v", err) } @@ -171,9 +179,12 @@ func CreateTestMSODSServerWithReqCap(t *testing.T) { } s := servers[0] + if s.ID == nil { + t.Fatal("server 'denver-mso-org-01' had nil ID") + } // Make sure server has no caps to ensure test correctness - sccs, _, err := TOSession.GetServerServerCapabilities(&s.ID, nil, nil) + sccs, _, err := TOSession.GetServerServerCapabilities(s.ID, nil, nil) if err != nil { t.Fatalf("GET server server capabilities for denver-mso-org-01: %v", err) } @@ -197,7 +208,7 @@ func CreateTestMSODSServerWithReqCap(t *testing.T) { t.Fatal("expected to find origin server denver-mso-org-01 to be in eligible server return even though it is missing a required capability") } - if _, _, err = TOSession.CreateDeliveryServiceServers(*dsReqCap[0].DeliveryServiceID, []int{s.ID}, true); err != nil { + if _, _, err = TOSession.CreateDeliveryServiceServers(*dsReqCap[0].DeliveryServiceID, []int{*s.ID}, true); err != nil { t.Fatalf("POST delivery service origin servers without capabilities: %v", err) } @@ -228,8 +239,14 @@ func CreateTestMSODSServerWithReqCap(t *testing.T) { func DeleteTestDeliveryServiceServers(t *testing.T) { dses, servers := getServersAndDSes(t) ds, server := dses[0], servers[0] + if server.ID == nil { + t.Fatalf("Got a server with a nil ID: %+v", server) + } + if ds.ID == nil { + t.Fatalf("Got a delivery service with a nil ID %+v", ds) + } - _, _, err := TOSession.CreateDeliveryServiceServers(*ds.ID, []int{server.ID}, true) + _, _, err := TOSession.CreateDeliveryServiceServers(*ds.ID, []int{*server.ID}, true) if err != nil { t.Errorf("POST delivery service servers: %v", err) } @@ -241,7 +258,7 @@ func DeleteTestDeliveryServiceServers(t *testing.T) { found := false for _, dss := range dsServers.Response { - if *dss.DeliveryService == *ds.ID && *dss.Server == server.ID { + if dss.DeliveryService != nil && *dss.DeliveryService == *ds.ID && dss.Server != nil && *dss.Server == *server.ID { found = true break } @@ -250,7 +267,7 @@ func DeleteTestDeliveryServiceServers(t *testing.T) { t.Error("POST delivery service servers returned success, but ds-server not in GET") } - if _, _, err := TOSession.DeleteDeliveryServiceServer(*ds.ID, server.ID); err != nil { + if _, _, err := TOSession.DeleteDeliveryServiceServer(*ds.ID, *server.ID); err != nil { t.Errorf("DELETE delivery service server: %v", err) } @@ -261,7 +278,7 @@ func DeleteTestDeliveryServiceServers(t *testing.T) { found = false for _, dss := range dsServers.Response { - if *dss.DeliveryService == *ds.ID && *dss.Server == server.ID { + if dss.DeliveryService != nil && *dss.DeliveryService == *ds.ID && dss.Server != nil && *dss.Server == *server.ID { found = true break } @@ -271,7 +288,7 @@ func DeleteTestDeliveryServiceServers(t *testing.T) { } } -func getServersAndDSes(t *testing.T) ([]tc.DeliveryServiceNullable, []tc.Server) { +func getServersAndDSes(t *testing.T) ([]tc.DeliveryServiceNullable, []tc.ServerNullable) { dses, _, err := TOSession.GetDeliveryServicesNullable() if err != nil { t.Fatalf("cannot GET DeliveryServices: %v", err) @@ -280,7 +297,7 @@ func getServersAndDSes(t *testing.T) ([]tc.DeliveryServiceNullable, []tc.Server) t.Fatal("GET DeliveryServices returned no dses, must have at least 1 to test ds-servers") } - servers, _, err := TOSession.GetServers() + servers, _, _, _, err := TOSession.GetServers(nil) if err != nil { t.Fatalf("cannot GET Servers: %v", err) } diff --git a/traffic_ops/testing/api/v3/servers_test.go b/traffic_ops/testing/api/v3/servers_test.go index 84b6ae9339..79d63b8813 100644 --- a/traffic_ops/testing/api/v3/servers_test.go +++ b/traffic_ops/testing/api/v3/servers_test.go @@ -16,9 +16,8 @@ package v3 */ import ( + "net/url" "testing" - - "github.com/apache/trafficcontrol/lib/go-tc" ) func TestServers(t *testing.T) { @@ -33,6 +32,10 @@ func CreateTestServers(t *testing.T) { // loop through servers, assign FKs and create for _, server := range testData.Servers { + if server.HostName == nil { + t.Errorf("found server with nil hostname: %+v", server) + continue + } resp, _, err := TOSession.CreateServer(server) t.Log("Response: ", server.HostName, " ", resp) if err != nil { @@ -43,11 +46,20 @@ func CreateTestServers(t *testing.T) { } func GetTestServers(t *testing.T) { + serverCount := uint64(len(testData.Servers)) + params := url.Values{} for _, server := range testData.Servers { - resp, _, err := TOSession.GetServerByHostName(server.HostName) + if server.HostName == nil { + t.Errorf("found server with nil hostname: %+v", server) + continue + } + params.Set("hostName", *server.HostName) + _, alerts, count, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Errorf("cannot GET Server by name: %v - %v", err, resp) + t.Errorf("cannot GET Server by name '%s': %v - %v", *server.HostName, err, alerts) + } else if count != serverCount { + t.Errorf("incorrect server count, expected: %d, actual: %d", serverCount, count) } } } @@ -63,38 +75,92 @@ func GetTestServersDetails(t *testing.T) { } func UpdateTestServers(t *testing.T) { + if len(testData.Servers) < 1 { + t.Fatal("Need at least one server to test updating") + } firstServer := testData.Servers[0] - hostName := firstServer.HostName - // Retrieve the server by hostname so we can get the id for the Update - resp, _, err := TOSession.GetServerByHostName(hostName) + if firstServer.HostName == nil { + t.Fatalf("First test server had nil hostname: %+v", firstServer) + } + hostName := *firstServer.HostName + params := url.Values{} + params.Add("hostName", hostName) + + // Retrieve the server by hostname so we can get the id for the Update + resp, alerts, _, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Errorf("cannot GET Server by hostname: %v - %v", firstServer.HostName, err) + t.Fatalf("cannot GET Server by hostname '%s': %v - %v", hostName, err, alerts) } + if len(resp) < 1 { + t.Fatalf("Expected at least one server to exist by hostname '%s'", hostName) + } + if len(resp) > 1 { + t.Errorf("Expected exactly one server to exist by hostname '%s' - actual: %d", hostName, len(resp)) + t.Logf("Testing will proceed with server: %+v", resp[0]) + } + remoteServer := resp[0] + if remoteServer.ID == nil { + t.Fatalf("Got null ID for server '%s'", hostName) + } + + infs := remoteServer.Interfaces + if len(infs) < 1 { + t.Fatalf("Expected server '%s' to have at least one network interface", hostName) + } + inf := infs[0] + updatedServerInterface := "bond1" updatedServerRack := "RR 119.03" // update rack and interfaceName values on server - remoteServer.InterfaceName = updatedServerInterface - remoteServer.Rack = updatedServerRack - var alert tc.Alerts - alert, _, err = TOSession.UpdateServerByID(remoteServer.ID, remoteServer) + inf.Name = updatedServerInterface + infs[0] = inf + remoteServer.Interfaces = infs + remoteServer.Rack = &updatedServerRack + + alerts, _, err = TOSession.UpdateServerByID(*remoteServer.ID, remoteServer) if err != nil { - t.Errorf("cannot UPDATE Server by hostname: %v - %v", err, alert) + t.Fatalf("cannot UPDATE Server by ID %d (hostname '%s'): %v - %v", *remoteServer.ID, hostName, err, alerts) } // Retrieve the server to check rack and interfaceName values were updated - resp, _, err = TOSession.GetServerByID(remoteServer.ID) + resp, alerts, _, _, err = TOSession.GetServers(¶ms) if err != nil { t.Errorf("cannot GET Server by ID: %v - %v", remoteServer.HostName, err) } + if len(resp) < 1 { + t.Fatalf("Expected at least one server to exist by hostname '%s'", hostName) + } + if len(resp) > 1 { + t.Errorf("Expected exactly one server to exist by hostname '%s' - actual: %d", hostName, len(resp)) + t.Logf("Testing will proceed with server: %+v", resp[0]) + } respServer := resp[0] - if respServer.InterfaceName != updatedServerInterface || respServer.Rack != updatedServerRack { - t.Errorf("results do not match actual: %s, expected: %s", respServer.InterfaceName, updatedServerInterface) - t.Errorf("results do not match actual: %s, expected: %s", respServer.Rack, updatedServerRack) + infs = respServer.Interfaces + found := false + for _, inf = range infs { + if inf.Name == updatedServerInterface { + found = true + break + } + } + if !found { + t.Errorf("Expected server '%s' to have an interface named '%s' after update", hostName, updatedServerInterface) + t.Logf("Actual interfaces: %+v", infs) + } + + if respServer.Rack == nil { + t.Errorf("results do not match actual: null, expected: '%s'", updatedServerRack) + } else if *respServer.Rack != updatedServerRack { + t.Errorf("results do not match actual: '%s', expected: '%s'", *respServer.Rack, updatedServerRack) + } + + if remoteServer.TypeID == nil { + t.Fatalf("Cannot test server type change update; server '%s' had nil type ID", hostName) } // Assign server to DS and then attempt to update to a different type @@ -114,48 +180,69 @@ func UpdateTestServers(t *testing.T) { t.Fatal("GET Server Types returned less then 2 types, must have at least 2 to test invalid type server update") } for _, t := range serverTypes { - if t.ID != remoteServer.TypeID { - remoteServer.TypeID = t.ID + if t.ID != *remoteServer.TypeID { + remoteServer.TypeID = &t.ID break } } // Assign server to DS - _, _, err = TOSession.CreateDeliveryServiceServers(*dses[0].ID, []int{remoteServer.ID}, true) + _, _, err = TOSession.CreateDeliveryServiceServers(*dses[0].ID, []int{*remoteServer.ID}, true) if err != nil { t.Fatalf("POST delivery service servers: %v", err) } // Attempt Update - should fail - _, _, err = TOSession.UpdateServerByID(remoteServer.ID, remoteServer) + alerts, _, err = TOSession.UpdateServerByID(*remoteServer.ID, remoteServer) if err == nil { t.Errorf("expected error when updating Server Type of a server assigned to DSes") + } else { + t.Logf("type change update alerts: %+v", alerts) } } func DeleteTestServers(t *testing.T) { + params := url.Values{} for _, server := range testData.Servers { - resp, _, err := TOSession.GetServerByHostName(server.HostName) + if server.HostName == nil { + t.Errorf("found server with nil hostname: %+v", server) + continue + } + + params.Set("hostName", *server.HostName) + + resp, alerts, _, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Errorf("cannot GET Server by hostname: %v - %v", server.HostName, err) + t.Errorf("cannot GET Server by hostname '%s': %v - %v", *server.HostName, err, alerts) + continue } if len(resp) > 0 { + if len(resp) > 1 { + t.Errorf("Expected exactly one server by hostname '%s' - actual: %d", *server.HostName, len(resp)) + t.Logf("Testing will proceed with server: %+v", resp[0]) + } respServer := resp[0] - delResp, _, err := TOSession.DeleteServerByID(respServer.ID) + if respServer.ID == nil { + t.Errorf("Server '%s' had nil ID", *server.HostName) + continue + } + + delResp, _, err := TOSession.DeleteServerByID(*respServer.ID) if err != nil { - t.Errorf("cannot DELETE Server by ID: %v - %v", err, delResp) + t.Errorf("cannot DELETE Server by ID %d: %v - %v", *respServer.ID, err, delResp) + continue } // Retrieve the Server to see if it got deleted - serv, _, err := TOSession.GetServerByHostName(server.HostName) + serv, alerts, _, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Errorf("error deleting Server hostname: %s", err.Error()) + t.Errorf("error deleting Server hostname '%s': %v - %v", *server.HostName, err, alerts) } if len(serv) > 0 { - t.Errorf("expected Server hostname: %s to be deleted", server.HostName) + t.Errorf("expected Server hostname: %s to be deleted", *server.HostName) } } } diff --git a/traffic_ops/testing/api/v3/servers_to_deliveryservice_assignment_test.go b/traffic_ops/testing/api/v3/servers_to_deliveryservice_assignment_test.go index 8afd7ff654..62d638edd0 100644 --- a/traffic_ops/testing/api/v3/servers_to_deliveryservice_assignment_test.go +++ b/traffic_ops/testing/api/v3/servers_to_deliveryservice_assignment_test.go @@ -16,6 +16,7 @@ package v3 import ( "net/http" + "net/url" "testing" "github.com/apache/trafficcontrol/lib/go-tc" @@ -30,13 +31,28 @@ func TestAssignments(t *testing.T) { } func AssignTestDeliveryService(t *testing.T) { - rs, _, err := TOSession.GetServerByHostName(testData.Servers[0].HostName) + if len(testData.Servers) < 1 { + t.Fatal("Need at least one test server to test delivery service assignment") + } + + server := testData.Servers[0] + if server.HostName == nil { + t.Fatalf("First server had nil hostname: %+v", server) + } + + params := url.Values{} + params.Add("hostName", *server.HostName) + + rs, alerts, _, _, err := TOSession.GetServers(¶ms) if err != nil { t.Fatalf("Failed to fetch server information: %v", err) } else if len(rs) == 0 { t.Fatalf("Failed to fetch server information: No results returned!") } firstServer := rs[0] + if firstServer.ID == nil { + t.Fatalf("Server '%s' had nil ID", *server.HostName) + } rd, _, err := TOSession.GetDeliveryServiceByXMLIDNullable(*testData.DeliveryServices[0].XMLID) if err != nil { @@ -49,13 +65,13 @@ func AssignTestDeliveryService(t *testing.T) { if firstDS.ID == nil { t.Fatal("Fetch DS information returned unknown ID") } - alerts, _, err := TOSession.AssignDeliveryServiceIDsToServerID(firstServer.ID, []int{*firstDS.ID}, true) + alerts, _, err = TOSession.AssignDeliveryServiceIDsToServerID(*firstServer.ID, []int{*firstDS.ID}, true) if err != nil { t.Errorf("Couldn't assign DS '%+v' to server '%+v': %v (alerts: %v)", firstDS, firstServer, err, alerts) } t.Logf("alerts: %+v", alerts) - response, _, err := TOSession.GetServerIDDeliveryServices(firstServer.ID) + response, _, err := TOSession.GetServerIDDeliveryServices(*firstServer.ID) t.Logf("response: %+v", response) if err != nil { t.Fatalf("Couldn't get Delivery Services assigned to Server '%+v': %v", firstServer, err) @@ -75,24 +91,33 @@ func AssignTestDeliveryService(t *testing.T) { } func AssignIncorrectTestDeliveryService(t *testing.T) { - var server *tc.Server + var server *tc.ServerNullable for _, s := range testData.Servers { - if s.CDNName == "cdn2" { + if s.CDNName != nil && *s.CDNName == "cdn2" { server = &s break } } if server == nil { - t.Fatalf("Couldn't find a server in CDN 'cdn2'!") + t.Fatal("Couldn't find a server in CDN 'cdn2'!") + } + if server.HostName == nil { + t.Fatalf("Server found with nil hostname: %+v", *server) } + hostname := *server.HostName - rs, _, err := TOSession.GetServerByHostName(server.HostName) + params := url.Values{} + params.Add("hostName", hostname) + rs, alerts, _, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Fatalf("Failed to fetch server information: %v", err) + t.Fatalf("Failed to fetch server information: %v - %v", err, alerts) } else if len(rs) == 0 { t.Fatalf("Failed to fetch server information: No results returned!") } server = &rs[0] + if server.ID == nil { + t.Fatalf("Server '%s' has nil ID", hostname) + } rd, _, err := TOSession.GetDeliveryServiceByXMLIDNullable(*testData.DeliveryServices[0].XMLID) if err != nil { @@ -105,12 +130,12 @@ func AssignIncorrectTestDeliveryService(t *testing.T) { if firstDS.ID == nil { t.Fatal("Fetch DS information returned unknown ID") } - alerts, _, err := TOSession.AssignDeliveryServiceIDsToServerID(server.ID, []int{*firstDS.ID}, false) + alerts, _, err = TOSession.AssignDeliveryServiceIDsToServerID(*server.ID, []int{*firstDS.ID}, false) if err == nil { t.Errorf("Expected bad assignment to fail, but it didn't! (alerts: %v)", alerts) } - response, _, err := TOSession.GetServerIDDeliveryServices(server.ID) + response, _, err := TOSession.GetServerIDDeliveryServices(*server.ID) t.Logf("response: %+v", response) if err != nil { t.Fatalf("Couldn't get Delivery Services assigned to Server '%+v': %v", *server, err) diff --git a/traffic_ops/testing/api/v3/serverservercapability_test.go b/traffic_ops/testing/api/v3/serverservercapability_test.go index 457117e55e..ff14413728 100644 --- a/traffic_ops/testing/api/v3/serverservercapability_test.go +++ b/traffic_ops/testing/api/v3/serverservercapability_test.go @@ -16,6 +16,7 @@ package v3 */ import ( + "net/url" "testing" "github.com/apache/trafficcontrol/lib/go-tc" @@ -32,21 +33,26 @@ func CreateTestServerServerCapabilities(t *testing.T) { // Valid POSTs // loop through server ServerCapabilities, assign FKs and create + params := url.Values{} for _, ssc := range testData.ServerServerCapabilities { - servResp, _, err := TOSession.GetServerByHostName(*ssc.Server) + if ssc.Server == nil { + t.Fatalf("server-server-capability structure had nil server") + } + params.Set("hostName", *ssc.Server) + servResp, alerts, _, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Fatalf("cannot GET Server by hostname: %v - %v", *ssc.Server, err) + t.Fatalf("cannot GET Server by hostname '%s': %v - %v", *ssc.Server, err, alerts) } if len(servResp) != 1 { t.Fatalf("cannot GET Server by hostname: %v. Response did not include record.", *ssc.Server) } server := servResp[0] - ssc.ServerID = &server.ID + ssc.ServerID = server.ID resp, _, err := TOSession.CreateServerServerCapability(ssc) if err != nil { t.Errorf("could not POST the server capability %v to server %v: %v", *ssc.ServerCapability, *ssc.Server, err) } - t.Log("Response: ", server.HostName, " ", resp) + t.Log("Response: ", *ssc.Server, " ", resp) } // Invalid POSTs @@ -98,16 +104,18 @@ func CreateTestServerServerCapabilities(t *testing.T) { } // Attempt to assign a server capability to a non MID/EDGE server - servers, _, err := TOSession.GetServerByHostName("riak") + // TODO: DON'T hard-code server hostnames! + params.Set("hostName", "riak") + servers, alerts, _, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Fatalf("cannot GET Server by hostname: %v - %v", *ssc.Server, err) + t.Fatalf("cannot GET Server by hostname 'riak': %v - %v", err, alerts) } if len(servers) < 1 { t.Fatal("need at least one server to test invalid server type assignment") } sscInvalidType := tc.ServerServerCapability{ - ServerID: &servers[0].ID, + ServerID: servers[0].ID, ServerCapability: ssc.ServerCapability, } _, _, err = TOSession.CreateServerServerCapability(sscInvalidType) diff --git a/traffic_ops/testing/api/v3/serverupdatestatus_test.go b/traffic_ops/testing/api/v3/serverupdatestatus_test.go index 6794925d99..1c8aa50ffe 100644 --- a/traffic_ops/testing/api/v3/serverupdatestatus_test.go +++ b/traffic_ops/testing/api/v3/serverupdatestatus_test.go @@ -19,6 +19,7 @@ import ( "encoding/json" "fmt" "net/http" + "net/url" "testing" "github.com/apache/trafficcontrol/lib/go-tc" @@ -27,15 +28,18 @@ import ( func TestServerUpdateStatus(t *testing.T) { WithObjs(t, []TCObj{CDNs, Types, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers}, func() { - edge1cdn1 := tc.Server{} - edge2cdn1 := tc.Server{} - mid1cdn1 := tc.Server{} - edge1cdn2 := tc.Server{} + //TODO: DON'T hard-code server hostnames! + var edge1cdn1 tc.ServerNullable + var edge2cdn1 tc.ServerNullable + var mid1cdn1 tc.ServerNullable + var edge1cdn2 tc.ServerNullable + + params := url.Values{} getServers := func() { for _, s := range []struct { name string - server *tc.Server + server *tc.ServerNullable }{ { "atlanta-edge-01", @@ -54,29 +58,45 @@ func TestServerUpdateStatus(t *testing.T) { &edge1cdn2, }, } { - resp, _, err := TOSession.GetServerByHostName(s.name) + params.Set("hostName", s.name) + resp, alerts, _, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Errorf("cannot GET Server by hostname: %v - %v", s.name, err) + t.Errorf("cannot GET Server by hostname '%s': %v - %v", s.name, err, alerts) + } + if len(resp) < 1 { + t.Fatalf("Expected a server named '%s' to exist", s.name) + } + if len(resp) > 1 { + t.Errorf("Expected exactly one server named '%s' to exist - actual: %d", s.name, len(resp)) + t.Logf("Testing will proceed with server: %+v", resp[0]) } *s.server = resp[0] + if s.server.ID == nil { + t.Fatalf("server '%s' was returned with nil ID", s.name) + } + if s.server.HostName == nil { + t.Fatalf("server '%s' was returned with nil HostName", s.name) + } } } getServers() // assert that servers don't have updates pending - for _, s := range []tc.Server{ + for _, s := range []tc.ServerNullable{ edge1cdn1, edge2cdn1, mid1cdn1, edge1cdn2, } { - if s.UpdPending { + if s.UpdPending == nil { + t.Error("expected UpdPending: false, actual: null") + } else if *s.UpdPending { t.Error("expected UpdPending: false, actual: true") } } // update status of MID server to OFFLINE - _, _, err := TOSession.UpdateServerStatus(mid1cdn1.ID, tc.ServerPutStatus{ + _, _, err := TOSession.UpdateServerStatus(*mid1cdn1.ID, tc.ServerPutStatus{ Status: util.JSONNameOrIDStr{Name: util.StrPtr("OFFLINE")}, OfflineReason: util.StrPtr("testing")}) if err != nil { @@ -85,17 +105,27 @@ func TestServerUpdateStatus(t *testing.T) { // assert that updates were queued for the proper EDGE servers getServers() - if !edge1cdn1.UpdPending { - t.Errorf("expected: child %s to have updates pending, actual: no updates pending", edge1cdn1.HostName) + if edge1cdn1.UpdPending == nil { + t.Errorf("expected: child %s (%d) to have updates pending, actual: property was null (or missing)", *edge1cdn1.HostName, *edge1cdn1.ID) + } else if !*edge1cdn1.UpdPending { + t.Errorf("expected: child %s (%d) to have updates pending, actual: no updates pending", *edge1cdn1.HostName, *edge1cdn1.ID) } - if !edge2cdn1.UpdPending { - t.Errorf("expected: child %s to have updates pending, actual: no updates pending", edge2cdn1.HostName) + + if edge2cdn1.UpdPending == nil { + t.Errorf("expected: child %s (%d) to have updates pending, actual: property was null (or missing)", *edge2cdn1.HostName, *edge2cdn1.ID) + } else if !*edge2cdn1.UpdPending { + t.Errorf("expected: child %s (%d) to have updates pending, actual: no updates pending", *edge2cdn1.HostName, *edge2cdn1.ID) } - if mid1cdn1.UpdPending { - t.Errorf("expected: server %s with updated status to have no updates pending, actual: updates pending", mid1cdn1.HostName) + if mid1cdn1.UpdPending == nil { + t.Errorf("expected: server %s (%d) with updated status to have no updates pending, actual: property was null (or missing)", *mid1cdn1.HostName, *mid1cdn1.ID) + } else if *mid1cdn1.UpdPending { + t.Errorf("expected: server %s (%d) with updated status to have no updates pending, actual: updates pending", *mid1cdn1.HostName, *mid1cdn1.ID) } - if edge1cdn2.UpdPending { - t.Errorf("expected: server %s in different CDN than server with updated status to have no updates pending, actual: updates pending", edge2cdn1.HostName) + + if edge1cdn2.UpdPending == nil { + t.Errorf("expected: server %s (%d) in different CDN than server with updated status to have no updates pending, actual: updates pending", *edge1cdn2.HostName, *edge1cdn2.ID) + } else if *edge1cdn2.UpdPending { + t.Errorf("expected: server %s (%d) in different CDN than server with updated status to have no updates pending, actual: updates pending", *edge1cdn2.HostName, *edge1cdn2.ID) } // update status of MID server to OFFLINE via status ID @@ -104,7 +134,7 @@ func TestServerUpdateStatus(t *testing.T) { t.Fatalf("cannot GET status by name: %v", err) } _, _, err = TOSession.UpdateServerStatus( - mid1cdn1.ID, + *mid1cdn1.ID, tc.ServerPutStatus{ Status: util.JSONNameOrIDStr{ID: util.IntPtr(status[0].ID)}, OfflineReason: util.StrPtr("testing"), @@ -129,7 +159,7 @@ func TestServerUpdateStatus(t *testing.T) { // status does not exist _, _, err = TOSession.UpdateServerStatus( - mid1cdn1.ID, + *mid1cdn1.ID, tc.ServerPutStatus{ Status: util.JSONNameOrIDStr{Name: util.StrPtr("NOT_A_REAL_STATUS")}, OfflineReason: util.StrPtr("testing"), @@ -141,7 +171,7 @@ func TestServerUpdateStatus(t *testing.T) { // offlineReason required for OFFLINE status _, _, err = TOSession.UpdateServerStatus( - mid1cdn1.ID, + *mid1cdn1.ID, tc.ServerPutStatus{ Status: util.JSONNameOrIDStr{Name: util.StrPtr("OFFLINE")}, OfflineReason: nil, @@ -153,7 +183,7 @@ func TestServerUpdateStatus(t *testing.T) { // offlineReason required for ADMIN_DOWN status _, _, err = TOSession.UpdateServerStatus( - mid1cdn1.ID, + *mid1cdn1.ID, tc.ServerPutStatus{ Status: util.JSONNameOrIDStr{Name: util.StrPtr("ADMIN_DOWN")}, OfflineReason: nil, @@ -167,6 +197,7 @@ func TestServerUpdateStatus(t *testing.T) { func TestServerQueueUpdate(t *testing.T) { WithObjs(t, []TCObj{Divisions, Regions, PhysLocations, Statuses, Types, CacheGroups, CDNs, Profiles, Servers}, func() { + // TODO: DON'T hard-code server hostnames! const serverName = "atlanta-edge-01" queueUpdateActions := map[bool]string{ @@ -174,26 +205,42 @@ func TestServerQueueUpdate(t *testing.T) { true: "queue", } - var s tc.Server - resp, _, err := TOSession.GetServerByHostName(serverName) + var s tc.ServerNullable + params := url.Values{} + params.Add("hostName", serverName) + resp, alerts, _, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Fatalf("failed to GET Server by hostname: %v - %v", serverName, err) + t.Fatalf("failed to GET Server by hostname '%s': %v - %v", serverName, err, alerts) + } + if len(resp) < 1 { + t.Fatalf("Expected a server named '%s' to exist", serverName) + } + if len(resp) > 1 { + t.Errorf("Expected exactly one server named '%s' to exist", serverName) + t.Logf("Testing will proceed with server: %+v", resp[0]) } s = resp[0] // assert that servers don't have updates pending - if got, want := s.UpdPending, false; got != want { + if s.UpdPending == nil { + t.Fatalf("Server '%s' had null (or missing) updPending property", serverName) + } + if got, want := *s.UpdPending, false; got != want { t.Fatalf("unexpected UpdPending, got: %v, want: %v", got, want) } + if s.ID == nil { + t.Fatalf("Server '%s' had nil ID", serverName) + } + for _, setVal := range [...]bool{true, false} { t.Run(fmt.Sprint(setVal), func(t *testing.T) { // queue update and check response - quResp, _, err := TOSession.SetServerQueueUpdate(s.ID, setVal) + quResp, _, err := TOSession.SetServerQueueUpdate(*s.ID, setVal) if err != nil { t.Fatalf("failed to set queue update for server with ID %v to %v: %v", s.ID, setVal, err) } - if got, want := int(quResp.Response.ServerID), s.ID; got != want { + if got, want := int(quResp.Response.ServerID), *s.ID; got != want { t.Errorf("wrong serverId in response, got: %v, want: %v", got, want) } if got, want := quResp.Response.Action, queueUpdateActions[setVal]; got != want { @@ -201,12 +248,22 @@ func TestServerQueueUpdate(t *testing.T) { } // assert that the server has updates queued - resp, _, err = TOSession.GetServerByID(s.ID) + resp, alerts, _, _, err = TOSession.GetServers(¶ms) if err != nil { - t.Fatalf("failed to GET Server by ID: %v - %v", s.ID, err) + t.Fatalf("failed to GET Server by hostname '%s': %v - %v", serverName, err, alerts) + } + if len(resp) < 1 { + t.Fatalf("Expected a server named '%s' to exist", serverName) + } + if len(resp) > 1 { + t.Errorf("Expected exactly one server named '%s' to exist", serverName) + t.Logf("Testing will proceed with server: %+v", resp[0]) } s = resp[0] - if got, want := s.UpdPending, setVal; got != want { + if s.UpdPending == nil { + t.Fatalf("Server '%s' had null (or missing) updPending property", serverName) + } + if got, want := *s.UpdPending, setVal; got != want { t.Errorf("unexpected UpdPending, got: %v, want: %v", got, want) } }) @@ -224,7 +281,9 @@ func TestServerQueueUpdate(t *testing.T) { if err != nil { t.Fatalf("failed to encode request body: %v", err) } - path := fmt.Sprintf(TestAPIBase+"/servers/%d/queue_update", s.ID) + + // TODO: don't construct URLs like this, nor use "RawRequest" + path := fmt.Sprintf(TestAPIBase+"/servers/%d/queue_update", *s.ID) httpResp, _, err := TOSession.RawRequest(http.MethodPost, path, req) if err != nil { t.Fatalf("POST request failed: %v", err) @@ -242,42 +301,61 @@ func TestSetServerUpdateStatuses(t *testing.T) { t.Fatal("cannot GET Server: no test data") } testServer := testData.Servers[0] + if testServer.HostName == nil { + t.Fatalf("First test server had nil hostname: %+v", testServer) + } + params := url.Values{} + params.Add("hostName", *testServer.HostName) testVals := func(queue *bool, reval *bool) { - existingServer, _, err := TOSession.GetServerByHostName(testServer.HostName) + existingServer, alerts, _, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Errorf("cannot GET Server by name: %v - %v", err, existingServer) + t.Errorf("cannot GET Server by name '%s': %v - %v", *testServer.HostName, err, alerts) } else if len(existingServer) != 1 { t.Fatalf("GET Server expected 1, actual %v", len(existingServer)) } - if _, err := TOSession.SetUpdateServerStatuses(testServer.HostName, queue, reval); err != nil { + if existingServer[0].UpdPending == nil { + t.Fatalf("Server '%s' had nil UpdPending before update status change", *testServer.HostName) + } + if existingServer[0].RevalPending == nil { + t.Fatalf("Server '%s' had nil RevalPending before update status change", *testServer.HostName) + } + + if _, err := TOSession.SetUpdateServerStatuses(*testServer.HostName, queue, reval); err != nil { t.Fatalf("UpdateServerStatuses error expected: nil, actual: %v", err) } - newServer, _, err := TOSession.GetServerByHostName(testServer.HostName) + newServer, alerts, _, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Errorf("cannot GET Server by name: %v - %v", err, existingServer) + t.Errorf("cannot GET Server by name '%s': %v - %v", *testServer.HostName, err, alerts) } else if len(newServer) != 1 { t.Fatalf("GET Server expected 1, actual %v", len(newServer)) } + if newServer[0].UpdPending == nil { + t.Fatalf("Server '%s' had nil UpdPending after update status change", *testServer.HostName) + } + if newServer[0].RevalPending == nil { + t.Fatalf("Server '%s' had nil RevalPending after update status change", *testServer.HostName) + } + if queue != nil { - if newServer[0].UpdPending != *queue { - t.Errorf("set queue update pending to %v, but then got server %v", *queue, newServer[0].UpdPending) + if *newServer[0].UpdPending != *queue { + t.Errorf("set queue update pending to %v, but then got server %v", *queue, *newServer[0].UpdPending) } } else { - if newServer[0].UpdPending != existingServer[0].UpdPending { - t.Errorf("set queue update pending with nil (don't update), but then got server %v which didn't match pre-update value %v", newServer[0].UpdPending, existingServer[0].UpdPending) + if *newServer[0].UpdPending != *existingServer[0].UpdPending { + t.Errorf("set queue update pending with nil (don't update), but then got server %v which didn't match pre-update value %v", *newServer[0].UpdPending, *existingServer[0].UpdPending) } } if reval != nil { - if newServer[0].RevalPending != *reval { - t.Errorf("set reval update pending to %v, but then got server %v", *reval, newServer[0].RevalPending) + if *newServer[0].RevalPending != *reval { + t.Errorf("set reval update pending to %v, but then got server %v", *reval, *newServer[0].RevalPending) } } else { - if newServer[0].RevalPending != existingServer[0].RevalPending { - t.Errorf("set reval update pending with nil (don't update), but then got server %v which didn't match pre-update value %v", newServer[0].RevalPending, existingServer[0].RevalPending) + if *newServer[0].RevalPending != *existingServer[0].RevalPending { + t.Errorf("set reval update pending with nil (don't update), but then got server %v which didn't match pre-update value %v", *newServer[0].RevalPending, *existingServer[0].RevalPending) } } } @@ -290,7 +368,7 @@ func TestSetServerUpdateStatuses(t *testing.T) { testVals(util.BoolPtr(true), nil) testVals(util.BoolPtr(false), nil) - if _, err := TOSession.SetUpdateServerStatuses(testServer.HostName, nil, nil); err == nil { + if _, err := TOSession.SetUpdateServerStatuses(*testServer.HostName, nil, nil); err == nil { t.Errorf("UpdateServerStatuses with (nil,nil) expected error, actual nil") } }) diff --git a/traffic_ops/testing/api/v3/traffic_control_test.go b/traffic_ops/testing/api/v3/traffic_control_test.go index 4c400f2d6d..e090021943 100644 --- a/traffic_ops/testing/api/v3/traffic_control_test.go +++ b/traffic_ops/testing/api/v3/traffic_control_test.go @@ -42,7 +42,7 @@ type TrafficControl struct { PhysLocations []tc.PhysLocation `json:"physLocations"` Regions []tc.Region `json:"regions"` Roles []tc.Role `json:"roles"` - Servers []tc.Server `json:"servers"` + Servers []tc.ServerNullable `json:"servers"` ServerServerCapabilities []tc.ServerServerCapability `json:"serverServerCapabilities"` ServerCapabilities []tc.ServerCapability `json:"serverCapabilities"` Statuses []tc.StatusNullable `json:"statuses"` From 09ccdb6c3902a0d9ad3ddd668e98c03cd64f0891 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 22:11:59 -0600 Subject: [PATCH 34/87] Fixed possible nil panics from unitialized maps --- traffic_ops/client/capability.go | 2 +- traffic_ops/client/server.go | 2 +- traffic_ops/testing/api/v2/cachegroups_test.go | 2 ++ traffic_ops/v1-client/capability.go | 2 +- traffic_ops/v2-client/capability.go | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/traffic_ops/client/capability.go b/traffic_ops/client/capability.go index cb544a47f6..43bae247fe 100644 --- a/traffic_ops/client/capability.go +++ b/traffic_ops/client/capability.go @@ -39,7 +39,7 @@ func (to *Session) GetCapabilities() ([]tc.Capability, ReqInf, error) { // GetCapability retrieves only the capability named 'c'. func (to *Session) GetCapability(c string) (tc.Capability, ReqInf, error) { - var v url.Values + v := url.Values{} v.Add("name", c) endpoint := API_CAPABILITIES + "?" + v.Encode() resp, remoteAddr, err := to.request(http.MethodGet, endpoint, nil) diff --git a/traffic_ops/client/server.go b/traffic_ops/client/server.go index 0c8fb728ea..2edd55d375 100644 --- a/traffic_ops/client/server.go +++ b/traffic_ops/client/server.go @@ -209,7 +209,7 @@ func (to *Session) DeleteServerByID(id int) (tc.Alerts, ReqInf, error) { // server found to have the Host Name 'n'. func (to *Session) GetServerFQDN(n string) (string, tc.Alerts, ReqInf, error) { // TODO fix to only request one server - var params url.Values + params := url.Values{} params.Add("hostName", n) servers, alerts, _, reqInf, err := to.GetServers(¶ms) diff --git a/traffic_ops/testing/api/v2/cachegroups_test.go b/traffic_ops/testing/api/v2/cachegroups_test.go index ce9f2a9b30..cc6f391731 100644 --- a/traffic_ops/testing/api/v2/cachegroups_test.go +++ b/traffic_ops/testing/api/v2/cachegroups_test.go @@ -257,6 +257,8 @@ func DeleteTestCacheGroups(t *testing.T) { if err != nil { t.Errorf("cannot DELETE CacheGroup by name: '%s' %v", *respCG.Name, err) } + + t.Logf("Deleted Cache Group %s", *respCG.Name) // Retrieve the CacheGroup to see if it got deleted cgs, _, err := TOSession.GetCacheGroupNullableByName(*cg.Name) if err != nil { diff --git a/traffic_ops/v1-client/capability.go b/traffic_ops/v1-client/capability.go index 100c0fab29..d2ba6ed90c 100644 --- a/traffic_ops/v1-client/capability.go +++ b/traffic_ops/v1-client/capability.go @@ -62,7 +62,7 @@ func (to *Session) GetCapabilities() ([]tc.Capability, ReqInf, error) { // GetCapability retrieves only the capability named 'c' func (to *Session) GetCapability(c string) (tc.Capability, ReqInf, error) { - var v url.Values + v := url.Values{} v.Add("name", c) endpoint := API_v14_CAPABILITIES + "?" + v.Encode() resp, remoteAddr, err := to.request(http.MethodGet, endpoint, nil) diff --git a/traffic_ops/v2-client/capability.go b/traffic_ops/v2-client/capability.go index cb544a47f6..43bae247fe 100644 --- a/traffic_ops/v2-client/capability.go +++ b/traffic_ops/v2-client/capability.go @@ -39,7 +39,7 @@ func (to *Session) GetCapabilities() ([]tc.Capability, ReqInf, error) { // GetCapability retrieves only the capability named 'c'. func (to *Session) GetCapability(c string) (tc.Capability, ReqInf, error) { - var v url.Values + v := url.Values{} v.Add("name", c) endpoint := API_CAPABILITIES + "?" + v.Encode() resp, remoteAddr, err := to.request(http.MethodGet, endpoint, nil) From 436f1b29dbe2998950bc403836c861a347c7ba8f Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 23:10:58 -0600 Subject: [PATCH 35/87] Added unit tests for server handler --- traffic_ops/testing/api/v3/servers_test.go | 1 - .../traffic_ops_golang/server/servers.go | 11 +- .../traffic_ops_golang/server/servers_test.go | 175 +++++++++++++++++- 3 files changed, 180 insertions(+), 7 deletions(-) diff --git a/traffic_ops/testing/api/v3/servers_test.go b/traffic_ops/testing/api/v3/servers_test.go index 79d63b8813..4656c44305 100644 --- a/traffic_ops/testing/api/v3/servers_test.go +++ b/traffic_ops/testing/api/v3/servers_test.go @@ -29,7 +29,6 @@ func TestServers(t *testing.T) { } func CreateTestServers(t *testing.T) { - // loop through servers, assign FKs and create for _, server := range testData.Servers { if server.HostName == nil { diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index a6f663db00..060b0d8f98 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -325,10 +325,6 @@ const deleteInterfacesQuery = `DELETE FROM interface WHERE server=$1` const deleteIPsQuery = `DELETE FROM ip_address WHERE server = $1` func validateCommon(s tc.CommonServerProperties, tx *sql.Tx) []error { - if s.XMPPID == nil || *s.XMPPID == "" { - hostName := *s.HostName - s.XMPPID = &hostName - } noSpaces := validation.NewStringRule(tovalidate.NoSpaces, "cannot contain spaces") @@ -350,13 +346,18 @@ func validateCommon(s tc.CommonServerProperties, tx *sql.Tx) []error { return errs } + if s.XMPPID == nil || *s.XMPPID == "" { + hostName := *s.HostName + s.XMPPID = &hostName + } + if _, err := tc.ValidateTypeID(tx, s.TypeID, "server"); err != nil { errs = append(errs, err) } var cdnID int if err := tx.QueryRow("SELECT cdn from profile WHERE id=$1", s.ProfileID).Scan(&cdnID); err != nil { - log.Error.Printf("could not execute select cdnID from profile: %s\n", err) + log.Errorf("could not execute select cdnID from profile: %s\n", err) if err == sql.ErrNoRows { errs = append(errs, errors.New("associated profile must have a cdn associated")) } else { diff --git a/traffic_ops/traffic_ops_golang/server/servers_test.go b/traffic_ops/traffic_ops_golang/server/servers_test.go index c1667c7014..e67b33e4ba 100644 --- a/traffic_ops/traffic_ops_golang/server/servers_test.go +++ b/traffic_ops/traffic_ops_golang/server/servers_test.go @@ -26,6 +26,8 @@ import ( "time" "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/test" @@ -239,7 +241,6 @@ func TestGetServersByCachegroup(t *testing.T) { if len(servers) != 3 { t.Errorf("getServers expected: len(servers) == 3, actual: %v", len(servers)) } - } func TestGetMidServers(t *testing.T) { @@ -429,6 +430,178 @@ func TestGetMidServers(t *testing.T) { } } +func TestV3Validations(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() + + goodInterface := tc.ServerInterfaceInfo{ + IPAddresses: []tc.ServerIpAddress{ + tc.ServerIpAddress{ + Address: "127.0.0.1/32", + Gateway: nil, + ServiceAddress: true, + }, + }, + MaxBandwidth: nil, + Monitor: true, + MTU: nil, + Name: "eth0", + } + + testServer := tc.ServerNullable{ + CommonServerProperties: tc.CommonServerProperties{ + CDNID: util.IntPtr(1), + HostName: util.StrPtr("test"), + DomainName: util.StrPtr("quest"), + PhysLocationID: new(int), + ProfileID: new(int), + StatusID: new(int), + TypeID: new(int), + UpdPending: new(bool), + CachegroupID: new(int), + }, + Interfaces: []tc.ServerInterfaceInfo{goodInterface}, + } + + typeCols := []string{"name", "use_in_table"} + cdnCols := []string{"cdn"} + typeRows := sqlmock.NewRows(typeCols).AddRow("EDGE", "server") + cdnRows := sqlmock.NewRows(cdnCols).AddRow(*testServer.CDNID) + + mock.ExpectBegin() + mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) + mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) + + tx := db.MustBegin().Tx + + _, err = validateV3(testServer, tx) + if err != nil { + t.Errorf("Unexpected error validating test server: %v", err) + } + + testServer.Interfaces = []tc.ServerInterfaceInfo{} + + mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) + mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) + + _, err = validateV3(testServer, tx) + if err == nil { + t.Errorf("Expected a server with no interfaces to be invalid") + } else { + t.Logf("Got expected error validating server with no interfaces: %v", err) + } + + testServer.Interfaces = nil + + mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) + mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) + + _, err = validateV3(testServer, tx) + if err == nil { + t.Errorf("Expected a server with nil interfaces to be invalid") + } else { + t.Logf("Got expected error validating server with nil interfaces: %v", err) + } + + badIface := goodInterface + var badMTU uint64 = 1279 + badIface.MTU = &badMTU + testServer.Interfaces = []tc.ServerInterfaceInfo{badIface} + + mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) + mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) + + _, err = validateV3(testServer, tx) + if err == nil { + t.Errorf("Expected a server an MTU < 1280 to be invalid") + } else { + t.Logf("Got expected error validating server with an MTU < 1280: %v", err) + } + + badIface.MTU = nil + badIface.IPAddresses = []tc.ServerIpAddress{} + testServer.Interfaces = []tc.ServerInterfaceInfo{badIface} + + mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) + mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) + + _, err = validateV3(testServer, tx) + if err == nil { + t.Errorf("Expected a server with no IP addresses to be invalid") + } else { + t.Logf("Got expected error validating server with no IP addresses: %v", err) + } + + + badIface.IPAddresses = nil + testServer.Interfaces = []tc.ServerInterfaceInfo{badIface} + + mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) + mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) + + _, err = validateV3(testServer, tx) + if err == nil { + t.Errorf("Expected a server with nil IP addresses to be invalid") + } else { + t.Logf("Got expected error validating server with nil IP addresses: %v", err) + } + + badIface = goodInterface + badIP := tc.ServerIpAddress{ + Address: "127.0.0.1/32", + Gateway: nil, + ServiceAddress: false, + } + badIface.IPAddresses = []tc.ServerIpAddress{badIP} + testServer.Interfaces = []tc.ServerInterfaceInfo{badIface} + + mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) + mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) + + _, err = validateV3(testServer, tx) + if err == nil { + t.Errorf("Expected a server with no service addresses to be invalid") + } else { + t.Logf("Got expected error validating server with no service addresses: %v", err) + } + + testServer.Interfaces = []tc.ServerInterfaceInfo{goodInterface, goodInterface} + + mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) + mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) + + _, err = validateV3(testServer, tx) + if err == nil { + t.Errorf("Expected a server with too many interfaces with service addresses to be invalid") + } else { + t.Logf("Got expected error validating server with too many interfaces with service addresses: %v", err) + } + + badIface = goodInterface + badIface.IPAddresses = append(badIface.IPAddresses, tc.ServerIpAddress{ + Address: "1.2.3.4/1", + Gateway: nil, + ServiceAddress: true, + }) + testServer.Interfaces = []tc.ServerInterfaceInfo{badIface} + + mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) + mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) + + _, err = validateV3(testServer, tx) + if err == nil { + t.Errorf("Expected a server with no service addresses to be invalid") + } else { + t.Logf("Got expected error validating server with no service addresses: %v", err) + } +} + type SortableServers []tc.Server func (s SortableServers) Len() int { From 8b3fd99527d4fd6d2aaf86938786d75d22c5939f Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 23:27:49 -0600 Subject: [PATCH 36/87] Added test for ToInterfaces method --- lib/go-tc/servers.go | 4 +++ lib/go-tc/servers_test.go | 58 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 lib/go-tc/servers_test.go diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index b0a072f4f4..e5b7cdd1e2 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -126,6 +126,10 @@ type LegacyInterfaceDetails struct { IPNetmask *string `json:"ipNetmask" db:"ip_netmask"` } +// ToInterfaces converts a LegacyInterfaceDetails to a slice of +// ServerInterfaceInfo structures. No interfaces will be marked for monitoring, +// and it will generate service addresses according to the passed indicators +// for each address family. func (lid *LegacyInterfaceDetails) ToInterfaces(ipv4IsService, ipv6IsService bool) ([]ServerInterfaceInfo, error) { var iface ServerInterfaceInfo if lid.InterfaceMtu == nil { diff --git a/lib/go-tc/servers_test.go b/lib/go-tc/servers_test.go new file mode 100644 index 0000000000..a181522d6d --- /dev/null +++ b/lib/go-tc/servers_test.go @@ -0,0 +1,58 @@ +package tc + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import "fmt" + +func ExampleLegacyInterfaceDetails_ToInterfaces(){ + lid := LegacyInterfaceDetails{ + InterfaceMtu: new(int), + InterfaceName: new(string), + IP6Address: new(string), + IP6Gateway: new(string), + IPAddress: new(string), + IPGateway: new(string), + IPNetmask: new(string), + } + *lid.InterfaceMtu = 9000 + *lid.InterfaceName = "test" + *lid.IP6Address = "::14/64" + *lid.IP6Gateway = "::15" + *lid.IPAddress = "1.2.3.4" + *lid.IPGateway = "4.3.2.1" + *lid.IPNetmask = "255.255.255.252" + + ifaces, err := lid.ToInterfaces(true, false) + if err != nil { + fmt.Printf(err.Error()) + return + } + + for _, iface := range ifaces { + fmt.Printf("name=%s, monitor=%t\n", iface.Name, iface.Monitor) + for _, ip := range iface.IPAddresses { + fmt.Printf("\taddr=%s, gateway=%s, service address=%t\n", ip.Address, *ip.Gateway, ip.ServiceAddress) + } + } + // Output: name=test, monitor=false + // addr=1.2.3.4/30, gateway=4.3.2.1, service address=true + // addr=::14/64, gateway=::15, service address=false + // +} From fde92d983114f0fefb14926357c3facd38ab5fb4 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 23:29:50 -0600 Subject: [PATCH 37/87] Go fmt --- lib/go-tc/cachegroups.go | 1 - lib/go-tc/servers.go | 13 +++---- lib/go-tc/servers_test.go | 14 +++---- traffic_ops/ort/atstccfg/toreqnew/toreqnew.go | 2 +- traffic_ops/traffic_ops_golang/api/api.go | 4 +- .../ats/atsprofile/profile.go | 2 +- .../ats/atsserver/parentdotconfig.go | 4 +- .../traffic_ops_golang/server/servers.go | 22 +++++------ .../traffic_ops_golang/server/servers_test.go | 38 +++++++++---------- 9 files changed, 45 insertions(+), 55 deletions(-) diff --git a/lib/go-tc/cachegroups.go b/lib/go-tc/cachegroups.go index f073d70cef..7b9d3061db 100644 --- a/lib/go-tc/cachegroups.go +++ b/lib/go-tc/cachegroups.go @@ -95,4 +95,3 @@ type CachegroupQueueUpdatesRequest struct { CDN *CDNName `json:"cdn"` CDNID *util.JSONIntStr `json:"cdnId"` } - diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index e5b7cdd1e2..a10739ea9e 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -33,7 +33,7 @@ import ( // ServersResponsev3 is the format of a response to a GET request for /servers. type ServersResponsev3 struct { Response []ServerNullable `json:"response"` - Summary struct { + Summary struct { Count uint64 `json:"count"` } `json:"summary"` Alerts @@ -160,8 +160,8 @@ func (lid *LegacyInterfaceDetails) ToInterfaces(ipv4IsService, ipv6IsService boo } ips = append(ips, ServerIpAddress{ - Address: ipStr, - Gateway: lid.IPGateway, + Address: ipStr, + Gateway: lid.IPGateway, ServiceAddress: ipv4IsService, }) } @@ -171,8 +171,8 @@ func (lid *LegacyInterfaceDetails) ToInterfaces(ipv4IsService, ipv6IsService boo lid.IP6Gateway = nil } ips = append(ips, ServerIpAddress{ - Address: *lid.IP6Address, - Gateway: lid.IP6Gateway, + Address: *lid.IP6Address, + Gateway: lid.IP6Gateway, ServiceAddress: ipv6IsService, }) } @@ -232,7 +232,6 @@ func InterfaceInfoToLegacyInterfaces(serverInterfaces []ServerInterfaceInfo) (Le return legacyDetails, nil } - type Server struct { Cachegroup string `json:"cachegroup" db:"cachegroup"` CachegroupID int `json:"cachegroupId" db:"cachegroup_id"` @@ -403,7 +402,7 @@ func (s *ServerNullable) ToServerV2() (ServerNullableV2, error) { ServerNullableV11: ServerNullableV11{ CommonServerProperties: s.CommonServerProperties, }, - IPIsService: new(bool), + IPIsService: new(bool), IP6IsService: new(bool), } diff --git a/lib/go-tc/servers_test.go b/lib/go-tc/servers_test.go index a181522d6d..443c585a32 100644 --- a/lib/go-tc/servers_test.go +++ b/lib/go-tc/servers_test.go @@ -21,15 +21,15 @@ package tc import "fmt" -func ExampleLegacyInterfaceDetails_ToInterfaces(){ +func ExampleLegacyInterfaceDetails_ToInterfaces() { lid := LegacyInterfaceDetails{ - InterfaceMtu: new(int), + InterfaceMtu: new(int), InterfaceName: new(string), - IP6Address: new(string), - IP6Gateway: new(string), - IPAddress: new(string), - IPGateway: new(string), - IPNetmask: new(string), + IP6Address: new(string), + IP6Gateway: new(string), + IPAddress: new(string), + IPGateway: new(string), + IPNetmask: new(string), } *lid.InterfaceMtu = 9000 *lid.InterfaceName = "test" diff --git a/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go b/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go index 9d8f3a8ed7..56bf454634 100644 --- a/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go +++ b/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go @@ -39,8 +39,8 @@ import ( "github.com/apache/trafficcontrol/lib/go-log" "github.com/apache/trafficcontrol/lib/go-tc" - toclient "github.com/apache/trafficcontrol/traffic_ops/v2-client" "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/torequtil" + toclient "github.com/apache/trafficcontrol/traffic_ops/v2-client" ) type TOClient struct { diff --git a/traffic_ops/traffic_ops_golang/api/api.go b/traffic_ops/traffic_ops_golang/api/api.go index 23a525c86e..6c28d7d2b8 100644 --- a/traffic_ops/traffic_ops_golang/api/api.go +++ b/traffic_ops/traffic_ops_golang/api/api.go @@ -70,13 +70,14 @@ WHERE type in ( SELECT id ) AND status=(SELECT id FROM status WHERE name='ONLINE') ` + type APIResponse struct { Response interface{} `json:"response"` } type APIResponseWithSummary struct { Response interface{} `json:"response"` - Summary struct { + Summary struct { Count uint64 `json:"count"` } `json:"summary"` } @@ -88,7 +89,6 @@ func WriteResp(w http.ResponseWriter, r *http.Request, v interface{}) { WriteRespRaw(w, r, resp) } - // WriteRespRaw acts like WriteResp, but doesn't wrap the object in a `{"response":` object. This should be used to respond with endpoints which don't wrap their response in a "response" object. func WriteRespRaw(w http.ResponseWriter, r *http.Request, v interface{}) { if respWritten(r) { diff --git a/traffic_ops/traffic_ops_golang/ats/atsprofile/profile.go b/traffic_ops/traffic_ops_golang/ats/atsprofile/profile.go index 5e83283720..52a31d65fb 100644 --- a/traffic_ops/traffic_ops_golang/ats/atsprofile/profile.go +++ b/traffic_ops/traffic_ops_golang/ats/atsprofile/profile.go @@ -26,8 +26,8 @@ import ( "strconv" "strings" - "github.com/apache/trafficcontrol/lib/go-rfc" "github.com/apache/trafficcontrol/lib/go-log" + "github.com/apache/trafficcontrol/lib/go-rfc" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/ats" diff --git a/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go b/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go index e9aebac11c..1dd3415a4a 100644 --- a/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go +++ b/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go @@ -535,8 +535,6 @@ WHERE return nil, nil, errors.New("scanning: " + err.Error()) } - - for _, cap := range caps { s.Capabilities[atscfg.ServerCapability(cap)] = struct{}{} } @@ -557,7 +555,7 @@ WHERE return nil, nil, fmt.Errorf("scanning server interfaces: %v", err) } - s, ok := cgServers[id]; + s, ok := cgServers[id] if !ok { log.Warnf("interfaces query returned interfaces for server #%d that was not in original query", id) continue diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 060b0d8f98..c19f989917 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -39,8 +39,8 @@ import ( "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/auth" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers" - "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/tenant" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/routing/middleware" + "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/tenant" "github.com/go-ozzo/ozzo-validation" "github.com/go-ozzo/ozzo-validation/is" @@ -379,15 +379,14 @@ func validateV1(s tc.ServerNullableV11, tx *sql.Tx) error { s.IP6Address = nil } - errs := []error{} if (s.IPAddress == nil || *s.IPAddress == "") && s.IP6Address == nil { errs = append(errs, tc.NeedsAtLeastOneIPError) } validateErrs := validation.Errors{ - "interfaceMtu": validation.Validate(s.InterfaceMtu, validation.NotNil), - "interfaceName": validation.Validate(s.InterfaceName, validation.NotNil), + "interfaceMtu": validation.Validate(s.InterfaceMtu, validation.NotNil), + "interfaceName": validation.Validate(s.InterfaceName, validation.NotNil), } if s.IPAddress != nil && *s.IPAddress != "" { @@ -469,8 +468,8 @@ func validateV3(s tc.ServerNullable, tx *sql.Tx) (string, error) { ruleName := fmt.Sprintf("interface '%s' ", iface.Name) errs = append(errs, tovalidate.ToErrors(validation.Errors{ - ruleName + "name": validation.Validate(iface.Name, validation.Required), - ruleName + "mtu": validation.Validate(iface.MaxBandwidth, validation.By(validateMTU)), + ruleName + "name": validation.Validate(iface.Name, validation.Required), + ruleName + "mtu": validation.Validate(iface.MaxBandwidth, validation.By(validateMTU)), ruleName + "ipAddresses": validation.Validate(iface.IPAddresses, validation.Required), })...) @@ -490,7 +489,7 @@ func validateV3(s tc.ServerNullable, tx *sql.Tx) (string, error) { if gateway := net.ParseIP(*addr.Gateway); gateway == nil { errs = append(errs, fmt.Errorf("%s: gateway: could not parse '%s' as a network gateway", ruleName, *addr.Gateway)) } else if (gateway.To4() == nil && parsedIP.To4() != nil) || (gateway.To4() != nil && parsedIP.To4() == nil) { - errs = append(errs, errors.New(ruleName + ": address family mismatch between address and gateway")) + errs = append(errs, errors.New(ruleName+": address family mismatch between address and gateway")) } } @@ -672,10 +671,8 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( } defer rows.Close() - HiddenField := "********" - servers := make(map[int]tc.ServerNullable) ids := []int{} for rows.Next() { @@ -842,7 +839,7 @@ func createInterfaces(id int, interfaces []tc.ServerInterfaceInfo, tx *sql.Tx) ( ifaceArgs = append(ifaceArgs, iface.MaxBandwidth, iface.Monitor, iface.MTU, iface.Name, id) for _, ip := range iface.IPAddresses { argStart = len(ipArgs) - ipQueryParts = append(ipQueryParts, fmt.Sprintf("($%d, $%d, $%d, $%d, $%d)", argStart+1, argStart+2, argStart+3, argStart+4, argStart+5)) + ipQueryParts = append(ipQueryParts, fmt.Sprintf("($%d, $%d, $%d, $%d, $%d)", argStart+1, argStart+2, argStart+3, argStart+4, argStart+5)) ipArgs = append(ipArgs, ip.Address, ip.Gateway, iface.Name, id, ip.ServiceAddress) } } @@ -953,8 +950,8 @@ func Update(w http.ResponseWriter, r *http.Request) { } server = tc.ServerNullableV2{ ServerNullableV11: legacyServer, - IPIsService: util.BoolPtr(true), - IP6IsService: util.BoolPtr(true), + IPIsService: util.BoolPtr(true), + IP6IsService: util.BoolPtr(true), } } @@ -1079,7 +1076,6 @@ func createV2(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { return } - if err := validateV2(&server, tx); err != nil { api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) return diff --git a/traffic_ops/traffic_ops_golang/server/servers_test.go b/traffic_ops/traffic_ops_golang/server/servers_test.go index e67b33e4ba..22aafc1314 100644 --- a/traffic_ops/traffic_ops_golang/server/servers_test.go +++ b/traffic_ops/traffic_ops_golang/server/servers_test.go @@ -36,7 +36,7 @@ import ( ) type ServerAndInterfaces struct { - Server tc.Server + Server tc.Server Interfaces []byte } @@ -223,7 +223,6 @@ func TestGetServersByCachegroup(t *testing.T) { ) } - mock.ExpectBegin() mock.ExpectQuery("SELECT COUNT\\(server.id\\) FROM server").WillReturnRows(unfilteredRows) mock.ExpectQuery("SELECT").WillReturnRows(rows) @@ -443,28 +442,28 @@ func TestV3Validations(t *testing.T) { goodInterface := tc.ServerInterfaceInfo{ IPAddresses: []tc.ServerIpAddress{ tc.ServerIpAddress{ - Address: "127.0.0.1/32", - Gateway: nil, + Address: "127.0.0.1/32", + Gateway: nil, ServiceAddress: true, }, }, MaxBandwidth: nil, - Monitor: true, - MTU: nil, - Name: "eth0", + Monitor: true, + MTU: nil, + Name: "eth0", } testServer := tc.ServerNullable{ CommonServerProperties: tc.CommonServerProperties{ - CDNID: util.IntPtr(1), - HostName: util.StrPtr("test"), - DomainName: util.StrPtr("quest"), + CDNID: util.IntPtr(1), + HostName: util.StrPtr("test"), + DomainName: util.StrPtr("quest"), PhysLocationID: new(int), - ProfileID: new(int), - StatusID: new(int), - TypeID: new(int), - UpdPending: new(bool), - CachegroupID: new(int), + ProfileID: new(int), + StatusID: new(int), + TypeID: new(int), + UpdPending: new(bool), + CachegroupID: new(int), }, Interfaces: []tc.ServerInterfaceInfo{goodInterface}, } @@ -538,7 +537,6 @@ func TestV3Validations(t *testing.T) { t.Logf("Got expected error validating server with no IP addresses: %v", err) } - badIface.IPAddresses = nil testServer.Interfaces = []tc.ServerInterfaceInfo{badIface} @@ -554,8 +552,8 @@ func TestV3Validations(t *testing.T) { badIface = goodInterface badIP := tc.ServerIpAddress{ - Address: "127.0.0.1/32", - Gateway: nil, + Address: "127.0.0.1/32", + Gateway: nil, ServiceAddress: false, } badIface.IPAddresses = []tc.ServerIpAddress{badIP} @@ -585,8 +583,8 @@ func TestV3Validations(t *testing.T) { badIface = goodInterface badIface.IPAddresses = append(badIface.IPAddresses, tc.ServerIpAddress{ - Address: "1.2.3.4/1", - Gateway: nil, + Address: "1.2.3.4/1", + Gateway: nil, ServiceAddress: true, }) testServer.Interfaces = []tc.ServerInterfaceInfo{badIface} From 12f48423f63339d4517264baab54e8766f4abe6b Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 23:35:05 -0600 Subject: [PATCH 38/87] Rolled back cdn.conf changes --- traffic_ops/app/conf/cdn.conf | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/traffic_ops/app/conf/cdn.conf b/traffic_ops/app/conf/cdn.conf index 5ee6e739c7..5f681062ec 100644 --- a/traffic_ops/app/conf/cdn.conf +++ b/traffic_ops/app/conf/cdn.conf @@ -1,7 +1,7 @@ { "hypnotoad" : { "listen" : [ - "https://[::]:60443?cert=/home/ocket8888/src/localhost.crt&key=/home/ocket8888/src/localhost.key&verify=0x00&ciphers=AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL:!EDH:!ED" + "https://[::]:60443?cert=/etc/pki/tls/certs/localhost.crt&key=/etc/pki/tls/private/localhost.key&verify=0x00&ciphers=AES128-GCM-SHA256:HIGH:!RC4:!MD5:!aNULL:!EDH:!ED" ], "user" : "trafops", "group" : "trafops", @@ -10,7 +10,7 @@ "workers" : 12 }, "traffic_ops_golang" : { - "port" : "6443", + "port" : "443", "proxy_timeout" : 60, "proxy_keep_alive" : 60, "proxy_tls_timeout" : 60, @@ -20,11 +20,11 @@ "read_header_timeout" : 60, "write_timeout" : 60, "idle_timeout" : 60, - "log_location_error": "stderr", - "log_location_warning": "stderr", - "log_location_info": "stderr", - "log_location_debug": "stderr", - "log_location_event": null, + "log_location_error": "/var/log/traffic_ops/error.log", + "log_location_warning": "", + "log_location_info": "", + "log_location_debug": "", + "log_location_event": "/var/log/traffic_ops/access.log", "max_db_connections": 20, "db_max_idle_connections": 15, "db_conn_max_lifetime_seconds": 60, From 5ef3a4664158530be79342b0305e6bc2cb9081c4 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 23:35:42 -0600 Subject: [PATCH 39/87] Rolled back database.conf changes --- traffic_ops/app/conf/development/database.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traffic_ops/app/conf/development/database.conf b/traffic_ops/app/conf/development/database.conf index a4b9980ec9..c19451d643 100644 --- a/traffic_ops/app/conf/development/database.conf +++ b/traffic_ops/app/conf/development/database.conf @@ -1,7 +1,7 @@ { "description": "Local PostgreSQL database on port 5432", - "dbname": "traffic_ops", + "dbname": "to_development", "hostname": "localhost", "user": "traffic_ops", "password": "twelve", From 6b15f93a4fb9577eabfcdb73128363510b65e897 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 23:39:48 -0600 Subject: [PATCH 40/87] Rolled back a change to ATSTCCFG that snuck in --- traffic_ops/ort/atstccfg/toreqnew/toreqnew.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go b/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go index 56bf454634..9d8f3a8ed7 100644 --- a/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go +++ b/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go @@ -39,8 +39,8 @@ import ( "github.com/apache/trafficcontrol/lib/go-log" "github.com/apache/trafficcontrol/lib/go-tc" - "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/torequtil" toclient "github.com/apache/trafficcontrol/traffic_ops/v2-client" + "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/torequtil" ) type TOClient struct { From aab60d66824125fd2e10f95d3d99df125bf49c24 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 23:40:45 -0600 Subject: [PATCH 41/87] Removed unnecessary log --- traffic_ops/testing/api/v1/atsconfig_test.go | 1 - 1 file changed, 1 deletion(-) diff --git a/traffic_ops/testing/api/v1/atsconfig_test.go b/traffic_ops/testing/api/v1/atsconfig_test.go index 037e54b6a0..8abea7a60a 100644 --- a/traffic_ops/testing/api/v1/atsconfig_test.go +++ b/traffic_ops/testing/api/v1/atsconfig_test.go @@ -84,7 +84,6 @@ func GetTestATSConfigs(t *testing.T) { "sysctl.conf", "volume.config", } - t.Logf("SERVER PROFILE: %v", server.Profile) for _, profileConfig := range profileConfigs { if _, _, err = TOSession.GetATSProfileConfig(server.ProfileID, profileConfig); err != nil { t.Errorf("Getting profile '" + server.Profile + "' config '" + profileConfig + "': " + err.Error() + "\n") From 494553fcf415fa1074d5c774db14132557a36e4f Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 23:47:25 -0600 Subject: [PATCH 42/87] Removed extra DELETE statement --- traffic_ops/testing/api/v1/todb_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/traffic_ops/testing/api/v1/todb_test.go b/traffic_ops/testing/api/v1/todb_test.go index e86cec406c..19e9d3638e 100644 --- a/traffic_ops/testing/api/v1/todb_test.go +++ b/traffic_ops/testing/api/v1/todb_test.go @@ -326,8 +326,6 @@ func Teardown(db *sql.DB) error { DELETE FROM origin; DELETE FROM ip_address; DELETE FROM interface; - DELETE FROM ip_address; - DELETE FROM interface; DELETE FROM server; DELETE FROM phys_location; DELETE FROM region; From 41e0c1dbbb3863259258fb72296c5ee970ff805f Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 23:48:22 -0600 Subject: [PATCH 43/87] Removed unnecessary log --- traffic_ops/testing/api/v2/cachegroups_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/traffic_ops/testing/api/v2/cachegroups_test.go b/traffic_ops/testing/api/v2/cachegroups_test.go index cc6f391731..ce9f2a9b30 100644 --- a/traffic_ops/testing/api/v2/cachegroups_test.go +++ b/traffic_ops/testing/api/v2/cachegroups_test.go @@ -257,8 +257,6 @@ func DeleteTestCacheGroups(t *testing.T) { if err != nil { t.Errorf("cannot DELETE CacheGroup by name: '%s' %v", *respCG.Name, err) } - - t.Logf("Deleted Cache Group %s", *respCG.Name) // Retrieve the CacheGroup to see if it got deleted cgs, _, err := TOSession.GetCacheGroupNullableByName(*cg.Name) if err != nil { From 927bd4aceee4618b9a1a7ed31b3934f86dd5f1e4 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 23:49:05 -0600 Subject: [PATCH 44/87] Removed unnecessary log --- traffic_ops/testing/api/v3/cachegroups_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/traffic_ops/testing/api/v3/cachegroups_test.go b/traffic_ops/testing/api/v3/cachegroups_test.go index c69bd86ed2..7fe45f3e10 100644 --- a/traffic_ops/testing/api/v3/cachegroups_test.go +++ b/traffic_ops/testing/api/v3/cachegroups_test.go @@ -314,8 +314,6 @@ func DeleteTestCacheGroups(t *testing.T) { if err != nil { t.Errorf("cannot DELETE CacheGroup by name: '%s' %v", *respCG.Name, err) } - - t.Logf("Deleted Cache Group '%s'", *respCG.Name) // Retrieve the CacheGroup to see if it got deleted cgs, _, err := TOSession.GetCacheGroupNullableByName(*cg.Name) if err != nil { From ec7fa99489932c848325cfd12447468233d47fa5 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 23:55:11 -0600 Subject: [PATCH 45/87] Removed unnecessary log --- traffic_ops/traffic_ops_golang/ats/atsprofile/profile.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/ats/atsprofile/profile.go b/traffic_ops/traffic_ops_golang/ats/atsprofile/profile.go index 52a31d65fb..5d2b563b7f 100644 --- a/traffic_ops/traffic_ops_golang/ats/atsprofile/profile.go +++ b/traffic_ops/traffic_ops_golang/ats/atsprofile/profile.go @@ -26,9 +26,7 @@ import ( "strconv" "strings" - "github.com/apache/trafficcontrol/lib/go-log" "github.com/apache/trafficcontrol/lib/go-rfc" - "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/ats" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/config" @@ -55,7 +53,6 @@ func WithProfileData(w http.ResponseWriter, r *http.Request, contentType string, return } } - log.Debugf("aosnutehantoehuntoehau %s", profileNameOrID) fileName := strings.TrimSuffix(inf.Params["file"], ".json") From 2ae6886a699493f2a5fb24e995a8fa8b14bcd1cb Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 18 May 2020 23:56:48 -0600 Subject: [PATCH 46/87] Removed unused import --- traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go | 1 - 1 file changed, 1 deletion(-) diff --git a/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go b/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go index 1dd3415a4a..aa96698f7c 100644 --- a/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go +++ b/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go @@ -32,7 +32,6 @@ import ( "github.com/apache/trafficcontrol/lib/go-tc" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/ats" - // "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/dbhelpers" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/server" "github.com/lib/pq" From 2421e87186edee0d29affe1372a496e8b4e5b4d2 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 19 May 2020 10:39:54 -0600 Subject: [PATCH 47/87] Updated docs for /servers in v3 --- docs/source/api/v3/servers.rst | 394 ++++++++++++++++++++------------- 1 file changed, 242 insertions(+), 152 deletions(-) diff --git a/docs/source/api/v3/servers.rst b/docs/source/api/v3/servers.rst index 508ad999f7..e748a1254d 100644 --- a/docs/source/api/v3/servers.rst +++ b/docs/source/api/v3/servers.rst @@ -70,36 +70,55 @@ Request Structure Response Structure ------------------ -:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the server belongs -:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the server belongs -:cdnId: The integral, unique identifier of the CDN to which the server belongs -:cdnName: Name of the CDN to which the server belongs -:domainName: The domain part of the server's :abbr:`FQDN (Fully Qualified Domain Name)` -:guid: An identifier used to uniquely identify the server +:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the server belongs +:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the server belongs +:cdnId: The integral, unique identifier of the CDN to which the server belongs +:cdnName: Name of the CDN to which the server belongs +:domainName: The domain part of the server's :abbr:`FQDN (Fully Qualified Domain Name)` +:guid: An identifier used to uniquely identify the server .. note:: This is a legacy key which only still exists for compatibility reasons - it should always be ``null`` -:hostName: The (short) hostname of the server -:httpsPort: The port on which the server listens for incoming HTTPS connections/requests -:id: An integral, unique identifier for this server -:iloIpAddress: The IPv4 address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:iloIpGateway: The IPv4 gateway address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:iloIpNetmask: The IPv4 subnet mask of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:iloPassword: The password of the of the server's :abbr:`ILO (Integrated Lights-Out)` service user\ [1]_ - displays as simply ``******`` if the currently logged-in user does not have the 'admin' or 'operations' :term:`Role(s) ` -:iloUsername: The user name for the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:interfaceMtu: The :abbr:`MTU (Maximum Transmission Unit)` configured on ``interfaceName`` -:interfaceName: The name of the primary network interface used by the server -:ip6Address: The IPv6 address and subnet mask of ``interfaceName`` -:ip6IsService: A boolean value which if ``true`` indicates that the IPv6 address will be used for routing content. -:ip6Gateway: The IPv6 address of the gateway used by ``interfaceName`` -:ipAddress: The IPv4 address of ``interfaceName`` -:ipIsService: A boolean value which if ``true`` indicates that the IPv4 address will be used for routing content. -:ipGateway: The IPv4 address of the gateway used by ``interfaceName`` -:ipNetmask: The IPv4 subnet mask used by ``interfaceName`` -:lastUpdated: The date and time at which this server description was last modified -:mgmtIpAddress: The IPv4 address of some network interface on the server used for 'management' -:mgmtIpGateway: The IPv4 address of a gateway used by some network interface on the server used for 'management' -:mgmtIpNetmask: The IPv4 subnet mask used by some network interface on the server used for 'management' +:hostName: The (short) hostname of the server +:httpsPort: The port on which the server listens for incoming HTTPS connections/requests +:id: An integral, unique identifier for this server +:iloIpAddress: The IPv4 address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloIpGateway: The IPv4 gateway address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloIpNetmask: The IPv4 subnet mask of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloPassword: The password of the of the server's :abbr:`ILO (Integrated Lights-Out)` service user\ [#ilo]_ - displays as simply ``******`` if the currently logged-in user does not have the 'admin' or 'operations' :term:`Role(s) ` +:iloUsername: The user name for the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:interfaces: A set of the network interfaces in use by the server. In most scenarios, only one will be present, but it is illegal for this set to be an empty collection. + + :ipAddresses: A set of objects representing IP Addresses assigned to this network interface. In most scenarios, only one or two (usually one IPv4 address and one IPv6 address) will be present, but it is illegal for this set to be an empty collection. + + :address: The actual IP address, including any mask as a CIDR-notation suffix + :gateway: Either the IP address of the network gateway for this address, or ``null`` to signify that no such gateway exists + :serviceAddress: A boolean that describes whether or not the server's main service is available at this IP address. When this property is ``true``, the IP address is referred to as a "service address". It is illegal for a server to not have at least one service address. It is also illegal for a server to have more than one service address of the same address family (i.e. more than one IPv4 service address and/or more than one IPv6 address). Finally, all service addresses for a server must be contained within one interface - which is therefore sometimes referred to as the "service interface" for the server. + + :maxBandwidth: The maximum healthy bandwidth allowed for this interface. If bandwidth exceeds this limit, Traffic Monitors will consider the entire server unhealthy - which includes *all* configured network interfaces. If this is ``null``, it has the meaning "no limit". It has no effect if ``monitor`` is not true for this interface. + + .. seealso:: :ref:`health-proto` + + :monitor: A boolean which describes whether or not this interface should be monitored by Traffic Monitor for statistics and health consideration. + :mtu: The :abbr:`MTU (Maximum Transmission Unit)` of this interface. If it is ``null``, it may be assumed that the information is either not available or not applicable for this interface. + :name: The name of the interface. No two interfaces of the same server may share a name. It is the same as the network interface's device name on the server, e.g. ``eth0``. + +:lastUpdated: The date and time at which this server description was last modified +:mgmtIpAddress: The IPv4 address of some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + +:mgmtIpGateway: The IPv4 address of a gateway used by some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + +:mgmtIpNetmask: The IPv4 subnet mask used by some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + :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 :physLocationId: An integral, unique identifier for the physical location where the server resides @@ -132,66 +151,71 @@ Response Structure :caption: Response Example HTTP/1.1 200 OK - Access-Control-Allow-Credentials: true - Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Set-Cookie, Cookie - Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE - Access-Control-Allow-Origin: * + Content-Encoding: gzip Content-Type: application/json - Set-Cookie: mojolicious=...; Path=/; Expires=Mon, 18 Nov 2019 17:40:54 GMT; Max-Age=3600; HttpOnly - Whole-Content-Sha512: WyapQctUIhjzEALka5QbBiZRZ58Mlc6MJSwjBeGyJS2UzbL3W6lN/4kvAZtPrP4qMWQBWz6JjbF7Y5lNRASUmQ== + Set-Cookie: mojolicious=...; Path=/; Expires=Tue, 19 May 2020 17:06:25 GMT; Max-Age=3600; HttpOnly + Vary: Accept-Encoding X-Server-Name: traffic_ops_golang/ - Date: Mon, 10 Dec 2018 16:13:31 GMT - Content-Length: 939 + Date: Tue, 19 May 2020 16:06:25 GMT + Content-Length: 538 + + { "response": [{ + "cachegroup": "CDN_in_a_Box_Mid", + "cachegroupId": 6, + "cdnId": 2, + "cdnName": "CDN-in-a-Box", + "domainName": "infra.ciab.test", + "guid": null, + "hostName": "mid", + "httpsPort": 443, + "id": 12, + "iloIpAddress": "", + "iloIpGateway": "", + "iloIpNetmask": "", + "iloPassword": "", + "iloUsername": "", + "lastUpdated": "2020-05-19 14:49:39+00", + "mgmtIpAddress": "", + "mgmtIpGateway": "", + "mgmtIpNetmask": "", + "offlineReason": "", + "physLocation": "Apachecon North America 2018", + "physLocationId": 1, + "profile": "ATS_MID_TIER_CACHE", + "profileDesc": "Mid Cache - Apache Traffic Server", + "profileId": 10, + "rack": "", + "revalPending": false, + "routerHostName": "", + "routerPortName": "", + "status": "REPORTED", + "statusId": 3, + "tcpPort": 80, + "type": "MID", + "typeId": 12, + "updPending": false, + "xmppId": "", + "xmppPasswd": "", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "172.26.0.4/16", + "gateway": "172.26.0.1", + "serviceAddress": true + } + ], + "maxBandwidth": null, + "monitor": false, + "mtu": 1500, + "name": "eth0" + } + ] + }], + "summary": { + "count": 13 + }} - { "response": [ - { - "cachegroup": "CDN_in_a_Box_Mid", - "cachegroupId": 6, - "cdnId": 2, - "cdnName": "CDN-in-a-Box", - "domainName": "infra.ciab.test", - "guid": null, - "hostName": "mid", - "httpsPort": 443, - "id": 10, - "iloIpAddress": "", - "iloIpGateway": "", - "iloIpNetmask": "", - "iloPassword": "", - "iloUsername": "", - "interfaceMtu": 1500, - "interfaceName": "eth0", - "ip6Address": "fc01:9400:1000:8::120", - "ip6Gateway": "fc01:9400:1000:8::1", - "ipAddress": "172.16.239.120", - "ipGateway": "172.16.239.1", - "ipNetmask": "255.255.255.0", - "lastUpdated": "2018-12-05 18:45:05+00", - "mgmtIpAddress": "", - "mgmtIpGateway": "", - "mgmtIpNetmask": "", - "offlineReason": "", - "physLocation": "Apachecon North America 2018", - "physLocationId": 1, - "profile": "ATS_MID_TIER_CACHE", - "profileDesc": "Mid Cache - Apache Traffic Server", - "profileId": 10, - "rack": "", - "revalPending": false, - "routerHostName": "", - "routerPortName": "", - "status": "REPORTED", - "statusId": 3, - "tcpPort": 80, - "type": "MID", - "typeId": 12, - "updPending": false, - "xmppId": "mid", - "xmppPasswd": "", - "ipIsService": true, - "ip6IsService": true - } - ]} ``POST`` ======== @@ -208,26 +232,42 @@ Request Structure :domainName: The domain part of the server's :abbr:`FQDN (Fully Qualified Domain Name)` :hostName: The (short) hostname of the server :httpsPort: An optional port number on which the server listens for incoming HTTPS connections/requests -:iloIpAddress: An optional IPv4 address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:iloIpGateway: An optional IPv4 gateway address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:iloIpNetmask: An optional IPv4 subnet mask of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:iloPassword: An optional string containing the password of the of the server's :abbr:`ILO (Integrated Lights-Out)` service user\ [1]_ - displays as simply ``******`` if the currently logged-in user does not have the 'admin' or 'operations' :term:`Role(s) ` -:iloUsername: An optional string containing the user name for the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:interfaceMtu: The :abbr:`MTU (Maximum Transmission Unit)` configured on ``interfaceName`` - - .. note:: In virtually all cases this ought to be 1500. Further note that the only acceptable values are 1500 and 9000. - -:interfaceName: The name of the primary network interface used by the server -:ip6Address: An optional IPv6 address and subnet mask of ``interfaceName`` -:ip6IsService: An optional boolean value which if ``true`` indicates that the IPv6 address will be used for routing content. Defaults to ``true``. -:ip6Gateway: An optional IPv6 address of the gateway used by ``interfaceName`` -:ipAddress: The IPv4 address of ``interfaceName`` -:ipIsService: An optional boolean value which if ``true`` indicates that the IPv4 address will be used for routing content. Defaults to ``true``. -:ipGateway: The IPv4 address of the gateway used by ``interfaceName`` -:ipNetmask: The IPv4 subnet mask used by ``interfaceName`` -:mgmtIpAddress: An optional IPv4 address of some network interface on the server used for 'management' -:mgmtIpGateway: An optional IPv4 address of a gateway used by some network interface on the server used for 'management' -:mgmtIpNetmask: An optional IPv4 subnet mask used by some network interface on the server used for 'management' +:iloIpAddress: An optional IPv4 address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloIpGateway: An optional IPv4 gateway address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloIpNetmask: An optional IPv4 subnet mask of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloPassword: An optional string containing the password of the of the server's :abbr:`ILO (Integrated Lights-Out)` service user\ [#ilo]_ - displays as simply ``******`` if the currently logged-in user does not have the 'admin' or 'operations' :term:`Role(s) ` +:iloUsername: An optional string containing the user name for the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:interfaces: A set of the network interfaces in use by the server. In most scenarios, only one will be necessary, but it is illegal for this set to be an empty collection. + + :ipAddresses: A set of objects representing IP Addresses assigned to this network interface. In most scenarios, only one or two (usually one IPv4 address and one IPv6 address) will be necessary, but it is illegal for this set to be an empty collection. + + :address: The actual IP address, including any mask as a CIDR-notation suffix + :gateway: Either the IP address of the network gateway for this address, or ``null`` to signify that no such gateway exists + :serviceAddress: A boolean that describes whether or not the server's main service is available at this IP address. When this property is ``true``, the IP address is referred to as a "service address". It is illegal for a server to not have at least one service address. It is also illegal for a server to have more than one service address of the same address family (i.e. more than one IPv4 service address and/or more than one IPv6 address). Finally, all service addresses for a server must be contained within one interface - which is therefore sometimes referred to as the "service interface" for the server. + + :maxBandwidth: The maximum healthy bandwidth allowed for this interface. If bandwidth exceeds this limit, Traffic Monitors will consider the entire server unhealthy - which includes *all* configured network interfaces. If this is ``null``, it has the meaning "no limit". It has no effect if ``monitor`` is not true for this interface. + + .. seealso:: :ref:`health-proto` + + :monitor: A boolean which describes whether or not this interface should be monitored by Traffic Monitor for statistics and health consideration. + :mtu: The :abbr:`MTU (Maximum Transmission Unit)` of this interface. If it is ``null``, it may be assumed that the information is either not available or not applicable for this interface. + :name: The name of the interface. No two interfaces of the same server may share a name. It is the same as the network interface's device name on the server, e.g. ``eth0``. + +:mgmtIpAddress: The IPv4 address of some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + +:mgmtIpGateway: The IPv4 address of a gateway used by some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + +:mgmtIpNetmask: The IPv4 subnet mask used by some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + :physLocationId: An integral, unique identifier for the physical location where the server resides :profileId: The :ref:`profile-id` the :term:`Profile` that shall be used by this server :revalPending: A boolean value which, if ``true`` indicates that this server has pending content invalidation/revalidation @@ -269,6 +309,26 @@ Request Structure "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "::1", + "gateway": "::2", + "serviceAddress": true + }, + { + "address": "0.0.0.1/24", + "gateway": "0.0.0.2", + "serviceAddress": true + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 1500, + "name": "eth0" + } + ], "interfaceMtu": 1500, "interfaceName": "eth0", "ip6Address": "::1", @@ -287,9 +347,7 @@ Request Structure "statusId": 3, "tcpPort": 80, "typeId": 12, - "updPending": false, - "ipIsService": true, - "ip6IsService": true + "updPending": false } Response Structure @@ -306,24 +364,43 @@ Response Structure :hostName: The (short) hostname of the server :httpsPort: The port on which the server listens for incoming HTTPS connections/requests :id: An integral, unique identifier for this server -:iloIpAddress: The IPv4 address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:iloIpGateway: The IPv4 gateway address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:iloIpNetmask: The IPv4 subnet mask of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:iloPassword: The password of the of the server's :abbr:`ILO (Integrated Lights-Out)` service user\ [1]_ - displays as simply ``******`` if the currently logged-in user does not have the 'admin' or 'operations' :abbr:`Role(s) ` -:iloUsername: The user name for the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:interfaceMtu: The :abbr:`MTU (Maximum Transmission Unit)` configured on ``interfaceName`` -:interfaceName: The name of the primary network interface used by the server -:ip6Address: The IPv6 address and subnet mask of ``interfaceName`` -:ip6IsService: A boolean value which if ``true`` indicates that the IPv6 address will be used for routing content. -:ip6Gateway: The IPv6 address of the gateway used by ``interfaceName`` -:ipAddress: The IPv4 address of ``interfaceName`` -:ipIsService: A boolean value which if ``true`` indicates that the IPv4 address will be used for routing content. -:ipGateway: The IPv4 address of the gateway used by ``interfaceName`` -:ipNetmask: The IPv4 subnet mask used by ``interfaceName`` -:lastUpdated: The date and time at which this server description was last modified -:mgmtIpAddress: The IPv4 address of some network interface on the server used for 'management' -:mgmtIpGateway: The IPv4 address of a gateway used by some network interface on the server used for 'management' -:mgmtIpNetmask: The IPv4 subnet mask used by some network interface on the server used for 'management' +:iloIpAddress: The IPv4 address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloIpGateway: The IPv4 gateway address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloIpNetmask: The IPv4 subnet mask of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloPassword: The password of the of the server's :abbr:`ILO (Integrated Lights-Out)` service user\ [#ilo]_ - displays as simply ``******`` if the currently logged-in user does not have the 'admin' or 'operations' :abbr:`Role(s) ` +:iloUsername: The user name for the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:interfaces: A set of the network interfaces in use by the server. In most scenarios, only one will be present, but it is illegal for this set to be an empty collection. + + :ipAddresses: A set of objects representing IP Addresses assigned to this network interface. In most scenarios, only one or two (usually one IPv4 address and one IPv6 address) will be present, but it is illegal for this set to be an empty collection. + + :address: The actual IP address, including any mask as a CIDR-notation suffix + :gateway: Either the IP address of the network gateway for this address, or ``null`` to signify that no such gateway exists + :serviceAddress: A boolean that describes whether or not the server's main service is available at this IP address. When this property is ``true``, the IP address is referred to as a "service address". It is illegal for a server to not have at least one service address. It is also illegal for a server to have more than one service address of the same address family (i.e. more than one IPv4 service address and/or more than one IPv6 address). Finally, all service addresses for a server must be contained within one interface - which is therefore sometimes referred to as the "service interface" for the server. + + :maxBandwidth: The maximum healthy bandwidth allowed for this interface. If bandwidth exceeds this limit, Traffic Monitors will consider the entire server unhealthy - which includes *all* configured network interfaces. If this is ``null``, it has the meaning "no limit". It has no effect if ``monitor`` is not true for this interface. + + .. seealso:: :ref:`health-proto` + + :monitor: A boolean which describes whether or not this interface should be monitored by Traffic Monitor for statistics and health consideration. + :mtu: The :abbr:`MTU (Maximum Transmission Unit)` of this interface. If it is ``null``, it may be assumed that the information is either not available or not applicable for this interface. + :name: The name of the interface. No two interfaces of the same server may share a name. It is the same as the network interface's device name on the server, e.g. ``eth0``. + +:lastUpdated: The date and time at which this server description was last modified +:mgmtIpAddress: The IPv4 address of some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + +:mgmtIpGateway: The IPv4 address of a gateway used by some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + +:mgmtIpNetmask: The IPv4 subnet mask used by some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + :offlineReason: A user-entered reason why the server is in ADMIN_DOWN or OFFLINE status :physLocation: The name of the :term:`Physical Location` where the server resides :physLocationId: An integral, unique identifier for the :term:`Physical Location` where the server resides @@ -355,70 +432,83 @@ Response Structure .. code-block:: http :caption: Response Example - HTTP/1.1 200 OK + HTTP/1.1 201 Created Access-Control-Allow-Credentials: true Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Set-Cookie, Cookie Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE Access-Control-Allow-Origin: * + Content-Encoding: gzip Content-Type: application/json - Set-Cookie: mojolicious=...; Path=/; Expires=Mon, 18 Nov 2019 17:40:54 GMT; Max-Age=3600; HttpOnly - Whole-Content-Sha512: mcGmmu5ONDg3jmvlkItcw6jxiT1ecmePYujZfmKiZrn5ThKjsSadeJIynaeOK0XVUjHuYHdtdynSqxr2rdzEyA== + Set-Cookie: mojolicious=eyJhdXRoX2RhdGEiOiJhZG1pbiIsImV4cGlyZXMiOjE1ODk5MDk2ODAsImJ5IjoidHJhZmZpY2NvbnRyb2wtZ28tdG9jb29raWUifQ--208fa3c993b41a3365aa394daf5e3b94e44c0340; Path=/; Expires=Tue, 19 May 2020 17:34:40 GMT; Max-Age=3600; HttpOnly + Vary: Accept-Encoding + Whole-Content-Sha512: ljrtkIc9hx2i7AmIOCZXTDbOyUwpoLHk2Yu1yl+ZdDnj2+B45qJqvLYi6mgXWHfz7O2IYQhU8pe5SaS5+PbhkQ== X-Server-Name: traffic_ops_golang/ - Date: Mon, 10 Dec 2018 17:44:04 GMT - Content-Length: 850 + Date: Tue, 19 May 2020 16:34:40 GMT + Content-Length: 562 { "alerts": [ { - "text": "server was created.", + "text": "Server created", "level": "success" } ], "response": { - "cachegroup": null, + "cachegroup": "CDN_in_a_Box_Mid", "cachegroupId": 6, "cdnId": 2, - "cdnName": null, + "cdnName": "CDN-in-a-Box", "domainName": "infra.ciab.test", "guid": null, "hostName": "test", "httpsPort": 443, - "id": 13, + "id": 14, "iloIpAddress": "", "iloIpGateway": "", "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 1500, - "interfaceName": "eth0", - "ip6Address": "::1", - "ip6Gateway": "::2", - "ipAddress": "0.0.0.1", - "ipGateway": "0.0.0.2", - "ipNetmask": "255.255.255.0", - "lastUpdated": "2018-12-10 17:44:04+00", + "lastUpdated": "2020-05-19 16:34:40+00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", "offlineReason": "", - "physLocation": null, + "physLocation": "Apachecon North America 2018", "physLocationId": 1, - "profile": null, - "profileDesc": null, + "profile": "ATS_MID_TIER_CACHE", + "profileDesc": "Mid Cache - Apache Traffic Server", "profileId": 10, "rack": null, - "revalPending": null, + "revalPending": false, "routerHostName": "", "routerPortName": "", - "status": null, + "status": "REPORTED", "statusId": 3, "tcpPort": 80, - "type": "", + "type": "MID", "typeId": 12, "updPending": false, - "xmppId": "test", + "xmppId": null, "xmppPasswd": null, - "ipIsService": true, - "ip6IsService": true + "interfaces": [ + { + "ipAddresses": [ + { + "address": "::1", + "gateway": "::2", + "serviceAddress": true + }, + { + "address": "0.0.0.1/24", + "gateway": "0.0.0.2", + "serviceAddress": true + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 1500, + "name": "eth0" + } + ] }} -.. [1] For more information see the `Wikipedia page on Lights-Out management `_\ . +.. [#ilo] For more information see the `Wikipedia page on Lights-Out management `_\ . From c9b3329b205110914a5dc36fe58533b52a36f7c8 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 19 May 2020 10:51:26 -0600 Subject: [PATCH 48/87] updated servers/{{ID}} docs for v3 --- docs/source/api/v3/servers.rst | 9 +- docs/source/api/v3/servers_id.rst | 277 +++++++++++++++++++++--------- 2 files changed, 202 insertions(+), 84 deletions(-) diff --git a/docs/source/api/v3/servers.rst b/docs/source/api/v3/servers.rst index e748a1254d..4523952be3 100644 --- a/docs/source/api/v3/servers.rst +++ b/docs/source/api/v3/servers.rst @@ -250,7 +250,7 @@ Request Structure .. seealso:: :ref:`health-proto` :monitor: A boolean which describes whether or not this interface should be monitored by Traffic Monitor for statistics and health consideration. - :mtu: The :abbr:`MTU (Maximum Transmission Unit)` of this interface. If it is ``null``, it may be assumed that the information is either not available or not applicable for this interface. + :mtu: The :abbr:`MTU (Maximum Transmission Unit)` of this interface. If it is ``null``, it may be assumed that the information is either not available or not applicable for this interface. This unsigned integer may not be less than 1280. :name: The name of the interface. No two interfaces of the same server may share a name. It is the same as the network interface's device name on the server, e.g. ``eth0``. :mgmtIpAddress: The IPv4 address of some network interface on the server used for 'management' @@ -433,15 +433,10 @@ Response Structure :caption: Response Example HTTP/1.1 201 Created - Access-Control-Allow-Credentials: true - Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Set-Cookie, Cookie - Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE - Access-Control-Allow-Origin: * Content-Encoding: gzip Content-Type: application/json - Set-Cookie: mojolicious=eyJhdXRoX2RhdGEiOiJhZG1pbiIsImV4cGlyZXMiOjE1ODk5MDk2ODAsImJ5IjoidHJhZmZpY2NvbnRyb2wtZ28tdG9jb29raWUifQ--208fa3c993b41a3365aa394daf5e3b94e44c0340; Path=/; Expires=Tue, 19 May 2020 17:34:40 GMT; Max-Age=3600; HttpOnly + Set-Cookie: mojolicious=...; Path=/; Expires=Tue, 19 May 2020 17:34:40 GMT; Max-Age=3600; HttpOnly Vary: Accept-Encoding - Whole-Content-Sha512: ljrtkIc9hx2i7AmIOCZXTDbOyUwpoLHk2Yu1yl+ZdDnj2+B45qJqvLYi6mgXWHfz7O2IYQhU8pe5SaS5+PbhkQ== X-Server-Name: traffic_ops_golang/ Date: Tue, 19 May 2020 16:34:40 GMT Content-Length: 562 diff --git a/docs/source/api/v3/servers_id.rst b/docs/source/api/v3/servers_id.rst index c01f468d38..46b7e1ab20 100644 --- a/docs/source/api/v3/servers_id.rst +++ b/docs/source/api/v3/servers_id.rst @@ -47,21 +47,37 @@ Request Structure :iloIpNetmask: An optional IPv4 subnet mask of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ :iloPassword: An optional string containing the password of the of the server's :abbr:`ILO (Integrated Lights-Out)` service user\ [1]_ - displays as simply ``******`` if the currently logged-in user does not have the 'admin' or 'operations' :abbr:`Role(s) ` :iloUsername: An optional string containing the user name for the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:interfaceMtu: The :abbr:`MTU (Maximum Transmission Unit)` configured on ``interfaceName`` - - .. note:: In virtually all cases this ought to be 1500. Further note that the only acceptable values are 1500 and 9000. - -:interfaceName: The name of the primary network interface used by the server -:ip6Address: An optional IPv6 address and subnet mask of ``interfaceName`` -:ip6IsService: An optional boolean value which if ``true`` indicates that the IPv6 address will be used for routing content. Defaults to ``true``. -:ip6Gateway: An optional IPv6 address of the gateway used by ``interfaceName`` -:ipAddress: The IPv4 address of ``interfaceName`` -:ipIsService: An optional boolean value which if ``true`` indicates that the IPv4 address will be used for routing content. Defaults to ``true``. -:ipGateway: The IPv4 address of the gateway used by ``interfaceName`` -:ipNetmask: The IPv4 subnet mask used by ``interfaceName`` -:mgmtIpAddress: An optional IPv4 address of some network interface on the server used for 'management' -:mgmtIpGateway: An optional IPv4 address of a gateway used by some network interface on the server used for 'management' -:mgmtIpNetmask: An optional IPv4 subnet mask used by some network interface on the server used for 'management' +:interfaces: A set of the network interfaces in use by the server. In most scenarios, only one will be necessary, but it is illegal for this set to be an empty collection. + + :ipAddresses: A set of objects representing IP Addresses assigned to this network interface. In most scenarios, only one or two (usually one IPv4 address and one IPv6 address) will be necessary, but it is illegal for this set to be an empty collection. + + :address: The actual IP address, including any mask as a CIDR-notation suffix + :gateway: Either the IP address of the network gateway for this address, or ``null`` to signify that no such gateway exists + :serviceAddress: A boolean that describes whether or not the server's main service is available at this IP address. When this property is ``true``, the IP address is referred to as a "service address". It is illegal for a server to not have at least one service address. It is also illegal for a server to have more than one service address of the same address family (i.e. more than one IPv4 service address and/or more than one IPv6 address). Finally, all service addresses for a server must be contained within one interface - which is therefore sometimes referred to as the "service interface" for the server. + + :maxBandwidth: The maximum healthy bandwidth allowed for this interface. If bandwidth exceeds this limit, Traffic Monitors will consider the entire server unhealthy - which includes *all* configured network interfaces. If this is ``null``, it has the meaning "no limit". It has no effect if ``monitor`` is not true for this interface. + + .. seealso:: :ref:`health-proto` + + :monitor: A boolean which describes whether or not this interface should be monitored by Traffic Monitor for statistics and health consideration. + :mtu: The :abbr:`MTU (Maximum Transmission Unit)` of this interface. If it is ``null``, it may be assumed that the information is either not available or not applicable for this interface. This unsigned integer must not be less than 1280. + :name: The name of the interface. No two interfaces of the same server may share a name. It is the same as the network interface's device name on the server, e.g. ``eth0``. + +:mgmtIpAddress: The IPv4 address of some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + +:mgmtIpGateway: The IPv4 address of a gateway used by some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + +:mgmtIpNetmask: The IPv4 subnet mask used by some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + :physLocationId: An integral, unique identifier for the physical location where the server resides :profileId: The :ref:`profile-id` the :term:`Profile` that shall be used by this server :revalPending: A boolean value which, if ``true`` indicates that this server has pending content invalidation/revalidation @@ -84,7 +100,7 @@ Request Structure .. code-block:: http :caption: Request Example - PUT /api/3.0/servers/13 HTTP/1.1 + PUT /api/3.0/servers/14 HTTP/1.1 Host: trafficops.infra.ciab.test User-Agent: curl/7.47.0 Accept: */* @@ -103,6 +119,26 @@ Request Structure "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", + "interfaces": [ + { + "ipAddresses": [ + { + "address": "::1", + "gateway": "::2", + "serviceAddress": true + }, + { + "address": "0.0.0.1/24", + "gateway": "0.0.0.2", + "serviceAddress": false + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 1500, + "name": "bond0" + } + ], "interfaceMtu": 1500, "interfaceName": "eth0", "ip6Address": "::1", @@ -121,9 +157,7 @@ Request Structure "statusId": 3, "tcpPort": 80, "typeId": 12, - "updPending": true, - "ipIsService": true, - "ip6IsService": true + "updPending": false } Response Structure @@ -140,27 +174,46 @@ Response Structure :hostName: The (short) hostname of the server :httpsPort: The port on which the server listens for incoming HTTPS connections/requests :id: An integral, unique identifier for this server -:iloIpAddress: The IPv4 address of the server's Integrated Lights-Out (ILO) service\ [1]_ -:iloIpGateway: The IPv4 gateway address of the server's ILO service\ [1]_ -:iloIpNetmask: The IPv4 subnet mask of the server's ILO service\ [1]_ -:iloPassword: The password of the of the server's ILO service user\ [1]_ - displays as simply ``******`` if the currently logged-in user does not have the 'admin' or 'operations' role(s) -:iloUsername: The user name for the server's ILO service\ [1]_ -:interfaceMtu: The Maximum Transmission Unit (MTU) to configured on ``interfaceName`` -:interfaceName: The name of the primary network interface used by the server -:ip6Address: The IPv6 address and subnet mask of ``interfaceName`` -:ip6IsService: A boolean value which if ``true`` indicates that the IPv6 address will be used for routing content. -:ip6Gateway: The IPv6 address of the gateway used by ``interfaceName`` -:ipAddress: The IPv4 address of ``interfaceName`` -:ipIsService: A boolean value which if ``true`` indicates that the IPv4 address will be used for routing content. -:ipGateway: The IPv4 address of the gateway used by ``interfaceName`` -:ipNetmask: The IPv4 subnet mask used by ``interfaceName`` -:lastUpdated: The date and time at which this server description was last modified -:mgmtIpAddress: The IPv4 address of some network interface on the server used for 'management' -:mgmtIpGateway: The IPv4 address of a gateway used by some network interface on the server used for 'management' -:mgmtIpNetmask: The IPv4 subnet mask used by some network interface on the server used for 'management' +:iloIpAddress: The IPv4 address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloIpGateway: The IPv4 gateway address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloIpNetmask: The IPv4 subnet mask of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloPassword: The password of the of the server's :abbr:`ILO (Integrated Lights-Out)` service user\ [#ilo]_ - displays as simply ``******`` if the currently logged-in user does not have the 'admin' or 'operations' :abbr:`Role(s) ` +:iloUsername: The user name for the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:interfaces: A set of the network interfaces in use by the server. In most scenarios, only one will be present, but it is illegal for this set to be an empty collection. + + :ipAddresses: A set of objects representing IP Addresses assigned to this network interface. In most scenarios, only one or two (usually one IPv4 address and one IPv6 address) will be present, but it is illegal for this set to be an empty collection. + + :address: The actual IP address, including any mask as a CIDR-notation suffix + :gateway: Either the IP address of the network gateway for this address, or ``null`` to signify that no such gateway exists + :serviceAddress: A boolean that describes whether or not the server's main service is available at this IP address. When this property is ``true``, the IP address is referred to as a "service address". It is illegal for a server to not have at least one service address. It is also illegal for a server to have more than one service address of the same address family (i.e. more than one IPv4 service address and/or more than one IPv6 address). Finally, all service addresses for a server must be contained within one interface - which is therefore sometimes referred to as the "service interface" for the server. + + :maxBandwidth: The maximum healthy bandwidth allowed for this interface. If bandwidth exceeds this limit, Traffic Monitors will consider the entire server unhealthy - which includes *all* configured network interfaces. If this is ``null``, it has the meaning "no limit". It has no effect if ``monitor`` is not true for this interface. + + .. seealso:: :ref:`health-proto` + + :monitor: A boolean which describes whether or not this interface should be monitored by Traffic Monitor for statistics and health consideration. + :mtu: The :abbr:`MTU (Maximum Transmission Unit)` of this interface. If it is ``null``, it may be assumed that the information is either not available or not applicable for this interface. + :name: The name of the interface. No two interfaces of the same server may share a name. It is the same as the network interface's device name on the server, e.g. ``eth0``. + +:lastUpdated: The date and time at which this server description was last modified +:mgmtIpAddress: The IPv4 address of some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + +:mgmtIpGateway: The IPv4 address of a gateway used by some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + +:mgmtIpNetmask: The IPv4 subnet mask used by some network interface on the server used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + :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 -:physLocationId: An integral, unique identifier for the physical location where the server resides +:physLocation: The name of the :term:`Physical Location` where the server resides +:physLocationId: An integral, unique identifier for the :term:`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 :profileId: The :ref:`profile-id` the :term:`Profile` used by this server @@ -194,65 +247,77 @@ Response Structure Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Set-Cookie, Cookie Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE Access-Control-Allow-Origin: * + Content-Encoding: gzip Content-Type: application/json - Set-Cookie: mojolicious=...; Path=/; Expires=Mon, 18 Nov 2019 17:40:54 GMT; Max-Age=3600; HttpOnly - Whole-Content-Sha512: 9lGAMCCC9I/bOpuBSyf3ACffjHeRuXCTuxrA/oU78uYzW5FeFTq5PHSSnsnqKG5E0vWg0Rko0CwguGeNc9IT0w== + Set-Cookie: mojolicious=...; Path=/; Expires=Tue, 19 May 2020 17:46:33 GMT; Max-Age=3600; HttpOnly + Vary: Accept-Encoding X-Server-Name: traffic_ops_golang/ - Date: Mon, 10 Dec 2018 17:58:57 GMT - Content-Length: 848 + Date: Tue, 19 May 2020 16:46:33 GMT + Content-Length: 566 { "alerts": [ { - "text": "server was updated.", + "text": "Server updated", "level": "success" } ], "response": { - "cachegroup": null, + "cachegroup": "CDN_in_a_Box_Mid", "cachegroupId": 6, "cdnId": 2, - "cdnName": null, + "cdnName": "CDN-in-a-Box", "domainName": "infra.ciab.test", "guid": null, "hostName": "quest", "httpsPort": 443, - "id": 13, + "id": 14, "iloIpAddress": "", "iloIpGateway": "", "iloIpNetmask": "", "iloPassword": "", "iloUsername": "", - "interfaceMtu": 1500, - "interfaceName": "eth0", - "ip6Address": "::1", - "ip6Gateway": "::2", - "ipAddress": "0.0.0.1", - "ipGateway": "0.0.0.2", - "ipNetmask": "255.255.255.0", - "lastUpdated": "2018-12-10 17:58:57+00", + "lastUpdated": "2020-05-19 16:46:33+00", "mgmtIpAddress": "", "mgmtIpGateway": "", "mgmtIpNetmask": "", "offlineReason": "", - "physLocation": null, + "physLocation": "Apachecon North America 2018", "physLocationId": 1, - "profile": null, - "profileDesc": null, + "profile": "ATS_MID_TIER_CACHE", + "profileDesc": "Mid Cache - Apache Traffic Server", "profileId": 10, "rack": null, - "revalPending": null, + "revalPending": false, "routerHostName": "", "routerPortName": "", - "status": null, + "status": "REPORTED", "statusId": 3, "tcpPort": 80, - "type": "", + "type": "MID", "typeId": 12, - "updPending": true, + "updPending": false, "xmppId": null, "xmppPasswd": null, - "ipIsService": true, - "ip6IsService": true + "interfaces": [ + { + "ipAddresses": [ + { + "address": "::1", + "gateway": "::2", + "serviceAddress": true + }, + { + "address": "0.0.0.1/24", + "gateway": "0.0.0.2", + "serviceAddress": false + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 1500, + "name": "bond0" + } + ] }} ``DELETE`` @@ -261,7 +326,10 @@ Allow user to delete server through api. :Auth. Required: Yes :Roles Required: "admin" or "operations" -:Response Type: ``undefined`` +:Response Type: Object + + .. versionchanged:: 3.0 + In older versions of the API, this endpoint did not return a response object. It now returns a representation of the deleted server. Request Structure ----------------- @@ -276,7 +344,7 @@ Request Structure .. code-block:: http :caption: Request Example - DELETE /api/3.0/servers/13 HTTP/1.1 + DELETE /api/3.0/servers/14 HTTP/1.1 Host: trafficops.infra.ciab.test User-Agent: curl/7.47.0 Accept: */* @@ -288,22 +356,77 @@ Response Structure :caption: Response Example HTTP/1.1 200 OK - Access-Control-Allow-Credentials: true - Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept, Set-Cookie, Cookie - Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE - Access-Control-Allow-Origin: * + Content-Encoding: gzip Content-Type: application/json - Set-Cookie: mojolicious=...; Path=/; Expires=Mon, 18 Nov 2019 17:40:54 GMT; Max-Age=3600; HttpOnly - Whole-Content-Sha512: JZdjKJYWN9w9NF6VE/rVkGUqecycKB2ABkkI4LNDmgpJLwu53bRHAA+4uWrow0zuba/4MSEhHKshutziypSxPg== + Set-Cookie: mojolicious=...; Path=/; Expires=Tue, 19 May 2020 17:50:13 GMT; Max-Age=3600; HttpOnly + Vary: Accept-Encoding X-Server-Name: traffic_ops_golang/ - Date: Mon, 10 Dec 2018 18:23:21 GMT - Content-Length: 61 + Date: Tue, 19 May 2020 16:50:13 GMT + Content-Length: 568 { "alerts": [ { - "text": "server was deleted.", + "text": "Server deleted", "level": "success" } - ]} + ], + "response": { + "cachegroup": "CDN_in_a_Box_Mid", + "cachegroupId": 6, + "cdnId": 2, + "cdnName": "CDN-in-a-Box", + "domainName": "infra.ciab.test", + "guid": null, + "hostName": "quest", + "httpsPort": 443, + "id": 14, + "iloIpAddress": "", + "iloIpGateway": "", + "iloIpNetmask": "", + "iloPassword": "", + "iloUsername": "", + "lastUpdated": "2020-05-19 16:46:33+00", + "mgmtIpAddress": "", + "mgmtIpGateway": "", + "mgmtIpNetmask": "", + "offlineReason": "", + "physLocation": "Apachecon North America 2018", + "physLocationId": 1, + "profile": "ATS_MID_TIER_CACHE", + "profileDesc": "Mid Cache - Apache Traffic Server", + "profileId": 10, + "rack": null, + "revalPending": false, + "routerHostName": "", + "routerPortName": "", + "status": "REPORTED", + "statusId": 3, + "tcpPort": 80, + "type": "MID", + "typeId": 12, + "updPending": false, + "xmppId": null, + "xmppPasswd": null, + "interfaces": [ + { + "ipAddresses": [ + { + "address": "0.0.0.1/24", + "gateway": "0.0.0.2", + "serviceAddress": false + }, + { + "address": "::1", + "gateway": "::2", + "serviceAddress": true + } + ], + "maxBandwidth": null, + "monitor": true, + "mtu": 1500, + "name": "bond0" + } + ] + }} -.. [1] For more information see the `Wikipedia page on Lights-Out management `_\ . +.. [#ilo] For more information see the `Wikipedia page on Lights-Out management `_\ . From d98071042f27a07d35921046116c32f144d679fe Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 19 May 2020 10:52:21 -0600 Subject: [PATCH 49/87] Fixed broken footnote reference --- docs/source/api/v3/servers_id.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/api/v3/servers_id.rst b/docs/source/api/v3/servers_id.rst index 46b7e1ab20..55e66ec50d 100644 --- a/docs/source/api/v3/servers_id.rst +++ b/docs/source/api/v3/servers_id.rst @@ -42,11 +42,11 @@ Request Structure :domainName: The domain part of the server's :abbr:`FQDN (Fully Qualified Domain Name)` :hostName: The (short) hostname of the server :httpsPort: An optional port number on which the server listens for incoming HTTPS connections/requests -:iloIpAddress: An optional IPv4 address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:iloIpGateway: An optional IPv4 gateway address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:iloIpNetmask: An optional IPv4 subnet mask of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ -:iloPassword: An optional string containing the password of the of the server's :abbr:`ILO (Integrated Lights-Out)` service user\ [1]_ - displays as simply ``******`` if the currently logged-in user does not have the 'admin' or 'operations' :abbr:`Role(s) ` -:iloUsername: An optional string containing the user name for the server's :abbr:`ILO (Integrated Lights-Out)` service\ [1]_ +:iloIpAddress: An optional IPv4 address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloIpGateway: An optional IPv4 gateway address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloIpNetmask: An optional IPv4 subnet mask of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloPassword: An optional string containing the password of the of the server's :abbr:`ILO (Integrated Lights-Out)` service user\ [#ilo]_ - displays as simply ``******`` if the currently logged-in user does not have the 'admin' or 'operations' :abbr:`Role(s) ` +:iloUsername: An optional string containing the user name for the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ :interfaces: A set of the network interfaces in use by the server. In most scenarios, only one will be necessary, but it is illegal for this set to be an empty collection. :ipAddresses: A set of objects representing IP Addresses assigned to this network interface. In most scenarios, only one or two (usually one IPv4 address and one IPv6 address) will be necessary, but it is illegal for this set to be an empty collection. From aecfb7edceacc361bce9f635576f56f3c5024f4b Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 19 May 2020 11:22:23 -0600 Subject: [PATCH 50/87] Fixed a ton of context-insensitive match warnings in Sphinx v3+ --- .../quick_howto/content_invalidation.rst | 6 +- docs/source/admin/quick_howto/oauth_login.rst | 2 +- .../admin/quick_howto/server_capabililty.rst | 12 +- .../traffic_portal/usingtrafficportal.rst | 36 ++-- docs/source/admin/traffic_router.rst | 2 +- docs/source/api/v1/cdns_name_snapshot.rst | 6 +- docs/source/api/v1/cdns_name_snapshot_new.rst | 6 +- .../deliveryservices_id_servers_eligible.rst | 2 +- docs/source/api/v1/origins.rst | 160 +++++++++--------- .../api/v1/regions_name_phys_locations.rst | 2 +- .../api/v1/server_server_capabilities.rst | 4 +- docs/source/api/v2/cdns_name_snapshot.rst | 6 +- docs/source/api/v2/cdns_name_snapshot_new.rst | 6 +- .../deliveryservices_id_servers_eligible.rst | 2 +- docs/source/api/v2/origins.rst | 160 +++++++++--------- .../api/v2/server_server_capabilities.rst | 4 +- docs/source/api/v3/cdns_name_snapshot.rst | 6 +- docs/source/api/v3/cdns_name_snapshot_new.rst | 6 +- .../deliveryservices_id_servers_eligible.rst | 2 +- docs/source/api/v3/origins.rst | 160 +++++++++--------- .../api/v3/server_server_capabilities.rst | 4 +- .../basics/content_delivery_networks.rst | 2 +- docs/source/glossary.rst | 36 ++-- docs/source/overview/cache_groups.rst | 4 +- docs/source/overview/delivery_services.rst | 24 +-- .../overview/profiles_and_parameters.rst | 4 +- docs/source/overview/traffic_portal.rst | 2 +- docs/source/overview/traffic_router.rst | 4 +- 28 files changed, 335 insertions(+), 335 deletions(-) diff --git a/docs/source/admin/quick_howto/content_invalidation.rst b/docs/source/admin/quick_howto/content_invalidation.rst index 98248eb439..32d2aa28ba 100644 --- a/docs/source/admin/quick_howto/content_invalidation.rst +++ b/docs/source/admin/quick_howto/content_invalidation.rst @@ -18,11 +18,11 @@ **************************** Forcing Content Invalidation **************************** -Invalidating content on the CDN is sometimes necessary when the :term:`origin` was mis-configured and something is cached in the CDN that needs to be removed. +Invalidating content on the CDN is sometimes necessary when the :term:`Origin` was mis-configured and something is cached in the CDN that needs to be removed. .. impl-detail:: Given the size of a typical Traffic Control CDN and the amount of content that can be cached in it, removing the content from all the caches may take a long time. To speed up content invalidation, Traffic Control does not try to remove the content from the caches, but it makes the content inaccessible using the `regex_revalidate plugin for Apache Traffic Server `_. This forces a "re-validation" of the content. -.. Note:: This method forces :term:`cache servers` to "re-validate" content, so in order to work properly the :term:`origin` needs to support revalidation according to section 13 of :rfc:`2616`. +.. Note:: This method forces :term:`cache servers` to "re-validate" content, so in order to work properly the :term:`Origin` needs to support revalidation according to section 13 of :rfc:`2616`. To invalidate content for a specific :term:`Delivery Service`, follow these steps: @@ -42,7 +42,7 @@ To invalidate content for a specific :term:`Delivery Service`, follow these step Select 'Manage Invalidation Requests' -#. Click/tap on the :guilabel:`+` button to open the submission form for a new content invalidation. Fill out this form. The "Path Regex" field should be a `PCRE `_-compatible regular expression that matches all content that must be invalidated - and should **not** match any content that must *not* be invalidated. "TTL (hours)" specifies the number of hours for which the invalidation should remain active. Best practice is to set this to the same as the content's cache lifetime (typically set in the :term:`origin`'s ``Cache-Control`` response header). +#. Click/tap on the :guilabel:`+` button to open the submission form for a new content invalidation. Fill out this form. The "Path Regex" field should be a `PCRE `_-compatible regular expression that matches all content that must be invalidated - and should **not** match any content that must *not* be invalidated. "TTL (hours)" specifies the number of hours for which the invalidation should remain active. Best practice is to set this to the same as the content's cache lifetime (typically set in the :term:`Origin`'s ``Cache-Control`` response header). .. figure:: content_invalidation/03.png :align: center diff --git a/docs/source/admin/quick_howto/oauth_login.rst b/docs/source/admin/quick_howto/oauth_login.rst index 4e76ce96c8..98a7d89f2b 100644 --- a/docs/source/admin/quick_howto/oauth_login.rst +++ b/docs/source/admin/quick_howto/oauth_login.rst @@ -26,7 +26,7 @@ An opt-in configuration for SSO using OAuth is supported and can be configured t .. Note:: The ``POST`` from the API to the OAuth provider to exchange the code for a token expects the response to have the token in JSON format with `access_token` as the desired field (and can include other fields). It also supports a response with just the token itself as the body. Further development work will need to be done to allow other resposne forms or other response fields. -.. Note:: Users must exist in both Traffic Ops as well as in the OAuth provider's system. The user's rights are defined by the :term:`role` assigned to the user. +.. Note:: Users must exist in both Traffic Ops as well as in the OAuth provider's system. The user's rights are defined by the :term:`Role` assigned to the user. To configure OAuth login: diff --git a/docs/source/admin/quick_howto/server_capabililty.rst b/docs/source/admin/quick_howto/server_capabililty.rst index d1246990d9..76ed2e0abd 100644 --- a/docs/source/admin/quick_howto/server_capabililty.rst +++ b/docs/source/admin/quick_howto/server_capabililty.rst @@ -18,9 +18,9 @@ ************************** Manage Server Capabilities ************************** -Server capabilities are designed to enable users with the Operations or Admin :term:`Role` to control the flow of :term:`delivery service` traffic through only the :term:`cache servers` (:term:`Edge` or :term:`Mid`) that have the required capabilities. For example, :term:`delivery services` designed to serve large binary files should only have requests routed to :term:`cache servers` with sufficient disk cache. Currently, this can be controlled at the :term:`Edge-tier` where system operators can explicitly assign only :term:`Edge-tier caches` with sufficient disk cache to the :term:`delivery service`. However, operators do not have control of :term:`Mid-tier cache` assignments and cannot dictate which :term:`Mid-tier caches` are qualified to serve these large binary files. This will cause a problem if a :term:`Mid-tier cache` with insufficient disk cache is asked to serve the :term:`delivery services` large binary files. +Server capabilities are designed to enable users with the Operations or Admin :term:`Role` to control the flow of :term:`Delivery Service` traffic through only the :term:`cache servers` (:term:`Edge` or :term:`Mid`) that have the required capabilities. For example, :term:`Delivery Services` designed to serve large binary files should only have requests routed to :term:`cache servers` with sufficient disk cache. Currently, this can be controlled at the :term:`Edge-tier` where system operators can explicitly assign only :term:`Edge-tier caches` with sufficient disk cache to the :term:`Delivery Service`. However, operators do not have control of :term:`Mid-tier cache` assignments and cannot dictate which :term:`Mid-tier caches` are qualified to serve these large binary files. This will cause a problem if a :term:`Mid-tier cache` with insufficient disk cache is asked to serve the :term:`Delivery Services`' large binary files. -A list of the server capabilities can be found under :menuselection:`Configure --> Server Capabilities`. Users with a higher-level :term:`role` ("operations" or "admin") can create or delete server capabilities. Server capabilities can only be deleted if they are not currently being used by a :term:`cache server` or required by a :term:`delivery service`. +A list of the server capabilities can be found under :menuselection:`Configure --> Server Capabilities`. Users with a higher-level :term:`Role` ("operations" or "admin") can create or delete server capabilities. Server capabilities can only be deleted if they are not currently being used by a :term:`cache server` or required by a :term:`Delivery Service`. .. figure:: server_capability/server_caps_table.png :align: center @@ -44,12 +44,12 @@ Users with the Operations or Admin :term:`Role` can associate one or more server Manage delivery service required server capabilities ==================================================== -Users with the Operations or Admin :term:`Role` can associate one or more required server capabilities with a :term:`delivery service` by navigating to a :term:`delivery service` via :menuselection:`Services --> Delivery Services` and using the context menu for the :term:`delivery services` table and selecting :menuselection:`Manage Required Server Capabilities` or by navigating to :menuselection:`Services --> Delivery Services --> Delivery Service --> More --> Manage Required Server Capabilities`. +Users with the Operations or Admin :term:`Role` can associate one or more required server capabilities with a :term:`Delivery Service` by navigating to a :term:`Delivery Service` via :menuselection:`Services --> Delivery Services` and using the context menu for the :term:`Delivery Services` table and selecting :menuselection:`Manage Required Server Capabilities` or by navigating to :menuselection:`Services --> Delivery Services --> Delivery Service --> More --> Manage Required Server Capabilities`. -Adding a required server capability to a :term:`delivery service` will ensure two things: +Adding a required server capability to a :term:`Delivery Service` will ensure two things: -1. Only :term:`Edge-tier caches` with the required capability can be assigned to the :term:`delivery service` -2. Only :term:`Mid-tier caches` with the required capability will handle requests of the :term:`delivery service` (if applicable) +1. Only :term:`Edge-tier caches` with the required capability can be assigned to the :term:`Delivery Service` +2. Only :term:`Mid-tier caches` with the required capability will handle requests of the :term:`Delivery Service` (if applicable) .. figure:: server_capability/ds_server_caps_table.png :align: center diff --git a/docs/source/admin/traffic_portal/usingtrafficportal.rst b/docs/source/admin/traffic_portal/usingtrafficportal.rst index 661d6ae853..d77442a584 100644 --- a/docs/source/admin/traffic_portal/usingtrafficportal.rst +++ b/docs/source/admin/traffic_portal/usingtrafficportal.rst @@ -418,33 +418,33 @@ Server management includes the ability to (where applicable): Origins ------- -A table of all :term:`origins`. These are automatically created for the :term:`origins` served by :term:`Delivery Services` throughout all CDNs, but additional ones can be created at will. The table has the following columns: +A table of all :term:`Origins`. These are automatically created for the :term:`Origins` served by :term:`Delivery Services` throughout all CDNs, but additional ones can be created at will. The table has the following columns: -:Name: The name of the :term:`origin`. If this :term:`origin` was created automatically for a :term:`Delivery Service`, this will be the :ref:`ds-xmlid` of that :term:`Delivery Service`. -:Tenant: The name of the :term:`Tenant` that owns this :term:`origin` - this is not necessarily the same as the :term:`Tenant` that owns the :term:`Delivery Service` to which this :term:`origin` belongs. -:Primary: Either ``true`` to indicate that this is the "primary" :term:`origin` for the :term:`Delivery Service` to which it is assigned, or ``false`` otherwise. -:Delivery Service: The :ref:`ds-xmlid` of the :term:`Delivery Service` to which this :term:`origin` is assigned. -:FQDN: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin server`. -:IPv4 Address: The :term:`origin`'s IPv4 address, if configured. -:IPv6 Address: The :term:`origin`'s IPv6 address, if configured. -:Protocol: The protocol this :term:`origin` uses to serve content. One of +:Name: The name of the :term:`Origin`. If this :term:`Origin` was created automatically for a :term:`Delivery Service`, this will be the :ref:`ds-xmlid` of that :term:`Delivery Service`. +:Tenant: The name of the :term:`Tenant` that owns this :term:`Origin` - this is not necessarily the same as the :term:`Tenant` that owns the :term:`Delivery Service` to which this :term:`Origin` belongs. +:Primary: Either ``true`` to indicate that this is the "primary" :term:`Origin` for the :term:`Delivery Service` to which it is assigned, or ``false`` otherwise. +:Delivery Service: The :ref:`ds-xmlid` of the :term:`Delivery Service` to which this :term:`Origin` is assigned. +:FQDN: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin`. +:IPv4 Address: The :term:`Origin`'s IPv4 address, if configured. +:IPv6 Address: The :term:`Origin`'s IPv6 address, if configured. +:Protocol: The protocol this :term:`Origin` uses to serve content. One of - http - https -:Port: The port on which the :term:`origin server` listens for incoming HTTP(S) requests. +:Port: The port on which the :term:`Origin` listens for incoming HTTP(S) requests. - .. note:: If this field appears blank in the table, it means that a default was chosen for the :term:`origin` based on its Protocol - ``80`` for "http", ``443`` for "https". + .. note:: If this field appears blank in the table, it means that a default was chosen for the :term:`Origin` based on its Protocol - ``80`` for "http", ``443`` for "https". -:Coordinate: The name of the geographic coordinate pair that defines the physical location of this :term:`origin server`. :term:`Origins` created for :term:`Delivery Services` automatically will **not** have associated Coordinates. This can be rectified on the details pages for said :term:`origins` -:Cachegroup: The :ref:`Name of the Cache Group ` to which this :term:`origin` belongs, if any. -:Profile: The :ref:`profile-name` of a :term:`Profile` used by this :term:`origin`. +:Coordinate: The name of the geographic coordinate pair that defines the physical location of this :term:`Origin`. :term:`Origins` created for :term:`Delivery Services` automatically will **not** have associated Coordinates. This can be rectified on the details pages for said :term:`Origins` +:Cachegroup: The :ref:`Name of the Cache Group ` to which this :term:`Origin` belongs, if any. +:Profile: The :ref:`profile-name` of a :term:`Profile` used by this :term:`Origin`. :term:`Origin` management includes the ability to (where applicable): -- create a new :term:`origin` -- update an existing :term:`origin` -- delete an existing :term:`origin` +- create a new :term:`Origin` +- update an existing :term:`Origin` +- delete an existing :term:`Origin` .. _tp-configure-profiles: @@ -740,7 +740,7 @@ User management includes the ability to (where applicable): - update an existing user - view :term:`Delivery Services` visible to a user -.. Note:: If OAuth is enabled, the username must exist both here as well as with the OAuth provider. A user's rights are defined by the :term:`role` assigned to the user in Traffic Ops. Creating/deleting a user here will update the user's :term:`role` but the user needs to be created/deleted with the OAuth provider as well. +.. Note:: If OAuth is enabled, the username must exist both here as well as with the OAuth provider. A user's rights are defined by the :term:`Role` assigned to the user in Traffic Ops. Creating/deleting a user here will update the user's :term:`Role` but the user needs to be created/deleted with the OAuth provider as well. Tenants ------- diff --git a/docs/source/admin/traffic_router.rst b/docs/source/admin/traffic_router.rst index 80803b5790..789a98a291 100644 --- a/docs/source/admin/traffic_router.rst +++ b/docs/source/admin/traffic_router.rst @@ -211,7 +211,7 @@ Much of a Traffic Router's configuration can be obtained through the :term:`Para | deepcoveragezone.polling.url | CRConfig.json | The location (URL) where a :term:`Deep Coverage Zone Map` may be found. | +-----------------------------------------+------------------------------+---------------------------------------------------------------------------------------------------------------------------------------+ | client.steering.forced.diversity | CRConfig.json | When this :term:`Parameter` exists and is exactly "true", it enables the "Client Steering Forced Diversity" feature to diversify | - | | | CLIENT_STEERING results by including more unique :term:`Edge-Tier Cache Servers` in the response to the client's request. | + | | | CLIENT_STEERING results by including more unique :term:`Edge-tier cache servers` in the response to the client's request. | +-----------------------------------------+------------------------------+---------------------------------------------------------------------------------------------------------------------------------------+ | tld.soa.expire | CRConfig.json | The value for the "expire" field the Traffic Router DNS Server will respond with on :abbr:`SOA (Start of Authority)` records. | +-----------------------------------------+------------------------------+---------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/docs/source/api/v1/cdns_name_snapshot.rst b/docs/source/api/v1/cdns_name_snapshot.rst index 69214a271b..746d41d1f9 100644 --- a/docs/source/api/v1/cdns_name_snapshot.rst +++ b/docs/source/api/v1/cdns_name_snapshot.rst @@ -116,7 +116,7 @@ Response Structure .. seealso:: :ref:`health-proto` -:contentServers: An object containing keys which are the (short) hostnames of the :term:`Edge-Tier cache servers` in the CDN; the values corresponding to those keys are routing information for said servers +:contentServers: An object containing keys which are the (short) hostnames of the :term:`Edge-tier cache servers` in the CDN; the values corresponding to those keys are routing information for said servers :cacheGroup: A string that is the :ref:`cache-group-name` of the :term:`Cache Group` to which the server belongs :deliveryServices: An object containing keys which are the names of :term:`Delivery Services` to which this :term:`cache server` is assigned; the values corresponding to those keys are arrays of :abbr:`FQDNs (Fully Qualified Domain Names)` that resolve to this :term:`cache server` @@ -186,9 +186,9 @@ Response Structure :shuffled: A string containing a boolean that tells whether the :term:`cache servers` chosen for content dispersion are chosen randomly or based on a consistent hash of the request URL; one of: "false" - :term:`Cache servers` will be chosen consistently + :term:`cache servers` will be chosen consistently "true" - :term:`Cache servers` will be chosen at random + :term:`cache servers` will be chosen at random :domains: An array of domains served by this :term:`Delivery Service` :ecsEnabled: A string containing a boolean from :ref:`ds-ecs` that tells whether EDNS0 client subnet is enabled on this :term:`Delivery Service`; one of: diff --git a/docs/source/api/v1/cdns_name_snapshot_new.rst b/docs/source/api/v1/cdns_name_snapshot_new.rst index 289ec5a3e8..479fd5975b 100644 --- a/docs/source/api/v1/cdns_name_snapshot_new.rst +++ b/docs/source/api/v1/cdns_name_snapshot_new.rst @@ -115,7 +115,7 @@ Response Structure .. seealso:: :ref:`health-proto` -:contentServers: An object containing keys which are the (short) hostnames of the :term:`Edge-Tier cache servers` in the CDN; the values corresponding to those keys are routing information for said servers +:contentServers: An object containing keys which are the (short) hostnames of the :term:`Edge-tier cache servers` in the CDN; the values corresponding to those keys are routing information for said servers :cacheGroup: A string that is the :ref:`cache-group-name` of the :term:`Cache Group` to which the server belongs :deliveryServices: An object containing keys which are the names of :term:`Delivery Services` to which this :term:`cache server` is assigned; the values corresponding to those keys are arrays of :abbr:`FQDNs (Fully Qualified Domain Names)` that resolve to this :term:`cache server` @@ -185,9 +185,9 @@ Response Structure :shuffled: A string containing a boolean that tells whether the :term:`cache servers` chosen for content dispersion are chosen randomly or based on a consistent hash of the request URL; one of: "false" - :term:`Cache servers` will be chosen consistently + :term:`cache servers` will be chosen consistently "true" - :term:`Cache servers` will be chosen at random + :term:`cache servers` will be chosen at random :domains: An array of domains served by this :term:`Delivery Service` :ecsEnabled: A string containing a boolean from :ref:`ds-ecs` that tells whether EDNS0 client subnet is enabled on this :term:`Delivery Service`; one of: diff --git a/docs/source/api/v1/deliveryservices_id_servers_eligible.rst b/docs/source/api/v1/deliveryservices_id_servers_eligible.rst index 73e6512219..8357a3706c 100644 --- a/docs/source/api/v1/deliveryservices_id_servers_eligible.rst +++ b/docs/source/api/v1/deliveryservices_id_servers_eligible.rst @@ -23,7 +23,7 @@ ``GET`` ======= -Retrieves properties of :term:`Edge-Tier cache servers` eligible for assignment to a particular :term:`Delivery Service`. Eligibility is determined based on the following properties: +Retrieves properties of :term:`Edge-tier cache servers` eligible for assignment to a particular :term:`Delivery Service`. Eligibility is determined based on the following properties: - The name of the server's :term:`Type` must match one of the glob patterns ``EDGE*``, ``ORG*`` - The server and :term:`Delivery Service` must belong to the same CDN diff --git a/docs/source/api/v1/origins.rst b/docs/source/api/v1/origins.rst index 1ea43ceac9..df865b2c18 100644 --- a/docs/source/api/v1/origins.rst +++ b/docs/source/api/v1/origins.rst @@ -22,7 +22,7 @@ ``GET`` ======= -Gets all requested :term:`origins`. +Gets all requested :term:`Origins`. :Auth. Required: Yes :Roles Required: None @@ -35,22 +35,22 @@ Request Structure +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Name | Required | Description | +=================+==========+===================================================================================================================================================================+ - | cachegroup | no | Return only :term:`origins` within the :term:`Cache Group` that has this :ref:`cache-group-id` | + | cachegroup | no | Return only :term:`Origins` within the :term:`Cache Group` that has this :ref:`cache-group-id` | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | coordinate | no | Return only :term:`origins` located at the geographic coordinates identified by this integral, unique identifier | + | coordinate | no | Return only :term:`Origins` located at the geographic coordinates identified by this integral, unique identifier | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | deliveryservice | no | Return only :term:`origins` that belong to the :term:`Delivery Service` identified by this integral, unique identifier | + | deliveryservice | no | Return only :term:`Origins` that belong to the :term:`Delivery Service` identified by this integral, unique identifier | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | id | no | Return only the :term:`origin` that has this integral, unique identifier | + | id | no | Return only the :term:`Origin` that has this integral, unique identifier | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | name | no | Return only :term:`origins` by this name | + | name | no | Return only :term:`Origins` by this name | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | profileId | no | Return only :term:`origins` which use the :term:`Profile` that has this :ref:`profile-id` | + | profileId | no | Return only :term:`Origins` which use the :term:`Profile` that has this :ref:`profile-id` | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | primary | no | If ``true``, return only :term:`origins` which are the the primary :term:`origin` of the :term:`Delivery Service` to which they belong - if ``false`` return only | - | | | :term:`origins` which are *not* the primary :term:`origin` of the :term:`Delivery Service` to which they belong | + | primary | no | If ``true``, return only :term:`Origins` which are the the primary :term:`Origin` of the :term:`Delivery Service` to which they belong - if ``false`` return only | + | | | :term:`Origins` which are *not* the primary :term:`Origin` of the :term:`Delivery Service` to which they belong | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | tenant | no | Return only :term:`origins` belonging to the tenant identified by this integral, unique identifier | + | tenant | no | Return only :term:`Origins` belonging to the tenant identified by this integral, unique identifier | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | orderby | no | Choose the ordering of the results - must be the name of one of the fields of the objects in the ``response`` | | | | array | @@ -78,25 +78,25 @@ Request Structure Response Structure ------------------ -:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`origin` belongs -:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`origin` belongs +:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`Origin` belongs +:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`Origin` belongs :coordinate: The name of a coordinate pair that defines the origin's geographic location -:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`origin`'s geographic location -:deliveryService: A string that is the :ref:`ds-xmlid` of the :term:`Delivery Service` to which the :term:`origin` belongs -:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`origin` belongs -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:id: An integral, unique identifier for this :term:`origin` +:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`Origin`'s geographic location +:deliveryService: A string that is the :ref:`ds-xmlid` of the :term:`Delivery Service` to which the :term:`Origin` belongs +:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`Origin` belongs +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:id: An integral, unique identifier for this :term:`Origin` :ip6Address: The IPv6 address of the :term:`Origin` :ipAddress: The IPv4 address of the :term:`Origin` -:isPrimary: A boolean value which, when ``true`` specifies this :term:`origin` as the 'primary' :term:`origin` served by ``deliveryService`` -:lastUpdated: The date and time at which this :term:`origin` was last modified -:name: The name of the :term:`origin` -:port: The TCP port on which the :term:`origin` listens -:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`origin` -:profileId: The :ref:`profile-id` of the :term:`Profile` used by this :term:`origin` +:isPrimary: A boolean value which, when ``true`` specifies this :term:`Origin` as the 'primary' :term:`Origin` served by ``deliveryService`` +:lastUpdated: The date and time at which this :term:`Origin` was last modified +:name: The name of the :term:`Origin` +:port: The TCP port on which the :term:`Origin` listens +:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`Origin` +:profileId: The :ref:`profile-id` of the :term:`Profile` used by this :term:`Origin` :protocol: The protocol used by this origin - will be one of 'http' or 'https' -:tenant: The name of the :term:`Tenant` that owns this :term:`origin` -:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`origin` +:tenant: The name of the :term:`Tenant` that owns this :term:`Origin` +:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`Origin` .. code-block:: http :caption: Response Example @@ -149,21 +149,21 @@ Creates a new origin definition. Request Structure ----------------- -:cachegroupId: An optional, integer which, if present, should be the :ref:`Cache Group ID ` that identifies a :term:`Cache Group` to which the new :term:`origin` shall belong -:coordinateId: An optional, integral, unique identifier of a coordinate pair that shall define the :term:`origin`'s geographic location -:deliveryServiceId: The integral, unique identifier of the :term:`Delivery Service` to which the new :term:`origin` shall belong -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:ip6Address: An optional string containing the IPv6 address of the :term:`origin` -:ipAddress: An optional string containing the IPv4 address of the :term:`origin` -:isPrimary: An optional boolean which, if ``true`` will set this :term:`origin` as the 'primary' :term:`origin` served by the :term:`Delivery Service` identified by ``deliveryServiceID`` +:cachegroupId: An optional, integer which, if present, should be the :ref:`Cache Group ID ` that identifies a :term:`Cache Group` to which the new :term:`Origin` shall belong +:coordinateId: An optional, integral, unique identifier of a coordinate pair that shall define the :term:`Origin`'s geographic location +:deliveryServiceId: The integral, unique identifier of the :term:`Delivery Service` to which the new :term:`Origin` shall belong +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:ip6Address: An optional string containing the IPv6 address of the :term:`Origin` +:ipAddress: An optional string containing the IPv4 address of the :term:`Origin` +:isPrimary: An optional boolean which, if ``true`` will set this :term:`Origin` as the 'primary' :term:`Origin` served by the :term:`Delivery Service` identified by ``deliveryServiceID`` .. note:: Though not specifying this field in this request will leave it as ``null`` in the output, Traffic Ops will silently coerce that to its default value: ``false``. :name: A human-friendly name of the :term:`Origin` -:port: An optional port number on which the :term:`origin` listens for incoming TCP connections -:profileId: An optional :ref:`profile-id` ofa :term:`Profile` that shall be used by this :term:`origin` +:port: An optional port number on which the :term:`Origin` listens for incoming TCP connections +:profileId: An optional :ref:`profile-id` ofa :term:`Profile` that shall be used by this :term:`Origin` :protocol: The protocol used by the origin - must be one of 'http' or 'https' -:tenantId: An optional\ [1]_, integral, unique identifier for the :term:`Tenant` which shall own the new :term:`origin` +:tenantId: An optional\ [1]_, integral, unique identifier for the :term:`Tenant` which shall own the new :term:`Origin` .. code-block:: http :caption: Request Example @@ -189,25 +189,25 @@ Request Structure Response Structure ------------------ -:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`origin` belongs -:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`origin` belongs +:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`Origin` belongs +:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`Origin` belongs :coordinate: The name of a coordinate pair that defines the origin's geographic location -:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`origin`'s geographic location -:deliveryService: The 'xml_id' of the :term:`Delivery Service` to which the :term:`origin` belongs -:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`origin` belongs -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:id: An integral, unique identifier for this :term:`origin` +:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`Origin`'s geographic location +:deliveryService: The 'xml_id' of the :term:`Delivery Service` to which the :term:`Origin` belongs +:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`Origin` belongs +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:id: An integral, unique identifier for this :term:`Origin` :ip6Address: The IPv6 address of the :term:`Origin` :ipAddress: The IPv4 address of the :term:`Origin` -:isPrimary: A boolean value which, when ``true`` specifies this :term:`origin` as the 'primary' :term:`origin` served by ``deliveryService`` -:lastUpdated: The date and time at which this :term:`origin` was last modified -:name: The name of the :term:`origin` -:port: The TCP port on which the :term:`origin` listens -:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`origin` -:profileId: The :ref:`profile-id` the :term:`Profile` used by this :term:`origin` +:isPrimary: A boolean value which, when ``true`` specifies this :term:`Origin` as the 'primary' :term:`Origin` served by ``deliveryService`` +:lastUpdated: The date and time at which this :term:`Origin` was last modified +:name: The name of the :term:`Origin` +:port: The TCP port on which the :term:`Origin` listens +:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`Origin` +:profileId: The :ref:`profile-id` the :term:`Profile` used by this :term:`Origin` :protocol: The protocol used by this origin - will be one of 'http' or 'https' -:tenant: The name of the :term:`Tenant` that owns this :term:`origin` -:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`origin` +:tenant: The name of the :term:`Tenant` that owns this :term:`Origin` +:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`Origin` .. code-block:: http :caption: Response Example @@ -254,7 +254,7 @@ Response Structure ``PUT`` ======= -Updates an :term:`origin` definition. +Updates an :term:`Origin` definition. :Auth. Required: Yes :Roles Required: "admin" or "operations" @@ -267,21 +267,21 @@ Request Structure +------+----------+-------------------------------------------------------------------------------+ | Name | Required | Description | +======+==========+===============================================================================+ - | id | yes | The integral, unique identifier of the :term:`origin` definition being edited | + | id | yes | The integral, unique identifier of the :term:`Origin` definition being edited | +------+----------+-------------------------------------------------------------------------------+ -:cachegroupId: An optional, integer which, if present, should be the :ref:`Cache Group ID ` that identifies a :term:`Cache Group` to which the new :term:`origin` shall belong -:coordinateId: An optional, integral, unique identifier of a coordinate pair that shall define the :term:`origin`'s geographic location -:deliveryServiceId: The integral, unique identifier of the :term:`Delivery Service` to which the :term:`origin` shall belong -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:ip6Address: An optional string containing the IPv6 address of the :term:`origin` -:ipAddress: An optional string containing the IPv4 address of the :term:`origin` -:isPrimary: An optional boolean which, if ``true`` will set this :term:`origin` as the 'primary' origin served by the :term:`Delivery Service` identified by ``deliveryServiceID`` +:cachegroupId: An optional, integer which, if present, should be the :ref:`Cache Group ID ` that identifies a :term:`Cache Group` to which the new :term:`Origin` shall belong +:coordinateId: An optional, integral, unique identifier of a coordinate pair that shall define the :term:`Origin`'s geographic location +:deliveryServiceId: The integral, unique identifier of the :term:`Delivery Service` to which the :term:`Origin` shall belong +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:ip6Address: An optional string containing the IPv6 address of the :term:`Origin` +:ipAddress: An optional string containing the IPv4 address of the :term:`Origin` +:isPrimary: An optional boolean which, if ``true`` will set this :term:`Origin` as the 'primary' origin served by the :term:`Delivery Service` identified by ``deliveryServiceID`` :name: A human-friendly name of the :term:`Origin` -:port: An optional port number on which the :term:`origin` listens for incoming TCP connections -:profileId: An optional :ref:`profile-id` of the :term:`Profile` that shall be used by this :term:`origin` -:protocol: The protocol used by the :term:`origin` - must be one of 'http' or 'https' -:tenantId: An optional\ [1]_, integral, unique identifier for the :term:`Tenant` which shall own the new :term:`origin` +:port: An optional port number on which the :term:`Origin` listens for incoming TCP connections +:profileId: An optional :ref:`profile-id` of the :term:`Profile` that shall be used by this :term:`Origin` +:protocol: The protocol used by the :term:`Origin` - must be one of 'http' or 'https' +:tenantId: An optional\ [1]_, integral, unique identifier for the :term:`Tenant` which shall own the new :term:`Origin` .. code-block:: http :caption: Request Example @@ -307,25 +307,25 @@ Request Structure Response Structure ------------------ -:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`origin` belongs -:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`origin` belongs +:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`Origin` belongs +:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`Origin` belongs :coordinate: The name of a coordinate pair that defines the origin's geographic location -:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`origin`'s geographic location -:deliveryService: The 'xml_id' of the :term:`Delivery Service` to which the :term:`origin` belongs -:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`origin` belongs -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:id: An integral, unique identifier for this :term:`origin` +:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`Origin`'s geographic location +:deliveryService: The 'xml_id' of the :term:`Delivery Service` to which the :term:`Origin` belongs +:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`Origin` belongs +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:id: An integral, unique identifier for this :term:`Origin` :ip6Address: The IPv6 address of the :term:`Origin` :ipAddress: The IPv4 address of the :term:`Origin` -:isPrimary: A boolean value which, when ``true`` specifies this :term:`origin` as the 'primary' :term:`origin` served by ``deliveryService`` -:lastUpdated: The date and time at which this :term:`origin` was last modified -:name: The name of the :term:`origin` -:port: The TCP port on which the :term:`origin` listens -:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`origin` -:profileId: The :ref:`profile-id` the :term:`Profile` used by this :term:`origin` +:isPrimary: A boolean value which, when ``true`` specifies this :term:`Origin` as the 'primary' :term:`Origin` served by ``deliveryService`` +:lastUpdated: The date and time at which this :term:`Origin` was last modified +:name: The name of the :term:`Origin` +:port: The TCP port on which the :term:`Origin` listens +:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`Origin` +:profileId: The :ref:`profile-id` the :term:`Profile` used by this :term:`Origin` :protocol: The protocol used by this origin - will be one of 'http' or 'https' -:tenant: The name of the :term:`Tenant` that owns this :term:`origin` -:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`origin` +:tenant: The name of the :term:`Tenant` that owns this :term:`Origin` +:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`Origin` .. code-block:: http :caption: Response Example @@ -372,7 +372,7 @@ Response Structure ``DELETE`` ========== -Deletes an :term:`origin` definition. +Deletes an :term:`Origin` definition. :Auth. Required: Yes :Roles Required: "admin" or "operations" @@ -385,7 +385,7 @@ Request Structure +------+----------+--------------------------------------------------------------------------------+ | Name | Required | Description | +======+==========+================================================================================+ - | id | yes | The integral, unique identifier of the :term:`origin` definition being deleted | + | id | yes | The integral, unique identifier of the :term:`Origin` definition being deleted | +------+----------+--------------------------------------------------------------------------------+ .. code-block:: http diff --git a/docs/source/api/v1/regions_name_phys_locations.rst b/docs/source/api/v1/regions_name_phys_locations.rst index b8750d2c8a..f770e2d25a 100644 --- a/docs/source/api/v1/regions_name_phys_locations.rst +++ b/docs/source/api/v1/regions_name_phys_locations.rst @@ -22,7 +22,7 @@ ``POST`` ======== -Creates a new :term:`Physical Location` within the specified :term:`region`. +Creates a new :term:`Physical Location` within the specified :term:`Region`. :Auth. Required: Yes :Roles Required: "admin" or "operations" diff --git a/docs/source/api/v1/server_server_capabilities.rst b/docs/source/api/v1/server_server_capabilities.rst index ddd616759b..8dbf7b1749 100644 --- a/docs/source/api/v1/server_server_capabilities.rst +++ b/docs/source/api/v1/server_server_capabilities.rst @@ -23,7 +23,7 @@ ``GET`` ======= -Gets all associations of :term:`Server Capabilities` to :term:`Cache Servers`. +Gets all associations of :term:`Server Capabilities` to :term:`cache servers`. :Auth. Required: Yes :Roles Required: None @@ -115,7 +115,7 @@ Request Structure :serverId: The integral, unique identifier of a server to be associated with a :term:`Server Capability` :serverCapability: The :term:`Server Capability`'s name to associate -.. note:: The server referenced must be either an :term:`Edge-tier` or :term:`Mid-tier Cache Server`. +.. note:: The server referenced must be either an :term:`Edge-tier` or :term:`Mid-tier cache server`. .. code-block:: http :caption: Request Example diff --git a/docs/source/api/v2/cdns_name_snapshot.rst b/docs/source/api/v2/cdns_name_snapshot.rst index e82dd50a2f..bcdc07b7a5 100644 --- a/docs/source/api/v2/cdns_name_snapshot.rst +++ b/docs/source/api/v2/cdns_name_snapshot.rst @@ -116,7 +116,7 @@ Response Structure .. seealso:: :ref:`health-proto` -:contentServers: An object containing keys which are the (short) hostnames of the :term:`Edge-Tier cache servers` in the CDN; the values corresponding to those keys are routing information for said servers +:contentServers: An object containing keys which are the (short) hostnames of the :term:`Edge-tier cache servers` in the CDN; the values corresponding to those keys are routing information for said servers :cacheGroup: A string that is the :ref:`cache-group-name` of the :term:`Cache Group` to which the server belongs :deliveryServices: An object containing keys which are the names of :term:`Delivery Services` to which this :term:`cache server` is assigned; the values corresponding to those keys are arrays of :abbr:`FQDNs (Fully Qualified Domain Names)` that resolve to this :term:`cache server` @@ -180,9 +180,9 @@ Response Structure :shuffled: A string containing a boolean that tells whether the :term:`cache servers` chosen for content dispersion are chosen randomly or based on a consistent hash of the request URL; one of: "false" - :term:`Cache servers` will be chosen consistently + :term:`cache servers` will be chosen consistently "true" - :term:`Cache servers` will be chosen at random + :term:`cache servers` will be chosen at random :domains: An array of domains served by this :term:`Delivery Service` :ecsEnabled: A string containing a boolean from :ref:`ds-ecs` that tells whether EDNS0 client subnet is enabled on this :term:`Delivery Service`; one of: diff --git a/docs/source/api/v2/cdns_name_snapshot_new.rst b/docs/source/api/v2/cdns_name_snapshot_new.rst index ecb20e1275..dfe2dbd5c5 100644 --- a/docs/source/api/v2/cdns_name_snapshot_new.rst +++ b/docs/source/api/v2/cdns_name_snapshot_new.rst @@ -115,7 +115,7 @@ Response Structure .. seealso:: :ref:`health-proto` -:contentServers: An object containing keys which are the (short) hostnames of the :term:`Edge-Tier cache servers` in the CDN; the values corresponding to those keys are routing information for said servers +:contentServers: An object containing keys which are the (short) hostnames of the :term:`Edge-tier cache servers` in the CDN; the values corresponding to those keys are routing information for said servers :cacheGroup: A string that is the :ref:`cache-group-name` of the :term:`Cache Group` to which the server belongs :deliveryServices: An object containing keys which are the names of :term:`Delivery Services` to which this :term:`cache server` is assigned; the values corresponding to those keys are arrays of :abbr:`FQDNs (Fully Qualified Domain Names)` that resolve to this :term:`cache server` @@ -179,9 +179,9 @@ Response Structure :shuffled: A string containing a boolean that tells whether the :term:`cache servers` chosen for content dispersion are chosen randomly or based on a consistent hash of the request URL; one of: "false" - :term:`Cache servers` will be chosen consistently + :term:`cache servers` will be chosen consistently "true" - :term:`Cache servers` will be chosen at random + :term:`cache servers` will be chosen at random :domains: An array of domains served by this :term:`Delivery Service` :ecsEnabled: A string containing a boolean from :ref:`ds-ecs` that tells whether EDNS0 client subnet is enabled on this :term:`Delivery Service`; one of: diff --git a/docs/source/api/v2/deliveryservices_id_servers_eligible.rst b/docs/source/api/v2/deliveryservices_id_servers_eligible.rst index f623b0c21e..33727f5cf2 100644 --- a/docs/source/api/v2/deliveryservices_id_servers_eligible.rst +++ b/docs/source/api/v2/deliveryservices_id_servers_eligible.rst @@ -23,7 +23,7 @@ ``GET`` ======= -Retrieves properties of :term:`Edge-Tier cache servers` eligible for assignment to a particular :term:`Delivery Service`. Eligibility is determined based on the following properties: +Retrieves properties of :term:`Edge-tier cache servers` eligible for assignment to a particular :term:`Delivery Service`. Eligibility is determined based on the following properties: - The name of the server's :term:`Type` must match one of the glob patterns ``EDGE*``, ``ORG*`` - The server and :term:`Delivery Service` must belong to the same CDN diff --git a/docs/source/api/v2/origins.rst b/docs/source/api/v2/origins.rst index 3a94af4161..2aa998e229 100644 --- a/docs/source/api/v2/origins.rst +++ b/docs/source/api/v2/origins.rst @@ -21,7 +21,7 @@ ``GET`` ======= -Gets all requested :term:`origins`. +Gets all requested :term:`Origins`. :Auth. Required: Yes :Roles Required: None @@ -34,22 +34,22 @@ Request Structure +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Name | Required | Description | +=================+==========+===================================================================================================================================================================+ - | cachegroup | no | Return only :term:`origins` within the :term:`Cache Group` that has this :ref:`cache-group-id` | + | cachegroup | no | Return only :term:`Origins` within the :term:`Cache Group` that has this :ref:`cache-group-id` | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | coordinate | no | Return only :term:`origins` located at the geographic coordinates identified by this integral, unique identifier | + | coordinate | no | Return only :term:`Origins` located at the geographic coordinates identified by this integral, unique identifier | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | deliveryservice | no | Return only :term:`origins` that belong to the :term:`Delivery Service` identified by this integral, unique identifier | + | deliveryservice | no | Return only :term:`Origins` that belong to the :term:`Delivery Service` identified by this integral, unique identifier | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | id | no | Return only the :term:`origin` that has this integral, unique identifier | + | id | no | Return only the :term:`Origin` that has this integral, unique identifier | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | name | no | Return only :term:`origins` by this name | + | name | no | Return only :term:`Origins` by this name | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | profileId | no | Return only :term:`origins` which use the :term:`Profile` that has this :ref:`profile-id` | + | profileId | no | Return only :term:`Origins` which use the :term:`Profile` that has this :ref:`profile-id` | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | primary | no | If ``true``, return only :term:`origins` which are the the primary :term:`origin` of the :term:`Delivery Service` to which they belong - if ``false`` return only | - | | | :term:`origins` which are *not* the primary :term:`origin` of the :term:`Delivery Service` to which they belong | + | primary | no | If ``true``, return only :term:`Origins` which are the the primary :term:`Origin` of the :term:`Delivery Service` to which they belong - if ``false`` return only | + | | | :term:`Origins` which are *not* the primary :term:`Origin` of the :term:`Delivery Service` to which they belong | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | tenant | no | Return only :term:`origins` belonging to the tenant identified by this integral, unique identifier | + | tenant | no | Return only :term:`Origins` belonging to the tenant identified by this integral, unique identifier | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | orderby | no | Choose the ordering of the results - must be the name of one of the fields of the objects in the ``response`` | | | | array | @@ -77,25 +77,25 @@ Request Structure Response Structure ------------------ -:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`origin` belongs -:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`origin` belongs +:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`Origin` belongs +:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`Origin` belongs :coordinate: The name of a coordinate pair that defines the origin's geographic location -:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`origin`'s geographic location -:deliveryService: A string that is the :ref:`ds-xmlid` of the :term:`Delivery Service` to which the :term:`origin` belongs -:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`origin` belongs -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:id: An integral, unique identifier for this :term:`origin` +:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`Origin`'s geographic location +:deliveryService: A string that is the :ref:`ds-xmlid` of the :term:`Delivery Service` to which the :term:`Origin` belongs +:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`Origin` belongs +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:id: An integral, unique identifier for this :term:`Origin` :ip6Address: The IPv6 address of the :term:`Origin` :ipAddress: The IPv4 address of the :term:`Origin` -:isPrimary: A boolean value which, when ``true`` specifies this :term:`origin` as the 'primary' :term:`origin` served by ``deliveryService`` -:lastUpdated: The date and time at which this :term:`origin` was last modified -:name: The name of the :term:`origin` -:port: The TCP port on which the :term:`origin` listens -:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`origin` -:profileId: The :ref:`profile-id` of the :term:`Profile` used by this :term:`origin` +:isPrimary: A boolean value which, when ``true`` specifies this :term:`Origin` as the 'primary' :term:`Origin` served by ``deliveryService`` +:lastUpdated: The date and time at which this :term:`Origin` was last modified +:name: The name of the :term:`Origin` +:port: The TCP port on which the :term:`Origin` listens +:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`Origin` +:profileId: The :ref:`profile-id` of the :term:`Profile` used by this :term:`Origin` :protocol: The protocol used by this origin - will be one of 'http' or 'https' -:tenant: The name of the :term:`Tenant` that owns this :term:`origin` -:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`origin` +:tenant: The name of the :term:`Tenant` that owns this :term:`Origin` +:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`Origin` .. code-block:: http :caption: Response Example @@ -148,21 +148,21 @@ Creates a new origin definition. Request Structure ----------------- -:cachegroupId: An optional, integer which, if present, should be the :ref:`Cache Group ID ` that identifies a :term:`Cache Group` to which the new :term:`origin` shall belong -:coordinateId: An optional, integral, unique identifier of a coordinate pair that shall define the :term:`origin`'s geographic location -:deliveryServiceId: The integral, unique identifier of the :term:`Delivery Service` to which the new :term:`origin` shall belong -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:ip6Address: An optional string containing the IPv6 address of the :term:`origin` -:ipAddress: An optional string containing the IPv4 address of the :term:`origin` -:isPrimary: An optional boolean which, if ``true`` will set this :term:`origin` as the 'primary' :term:`origin` served by the :term:`Delivery Service` identified by ``deliveryServiceID`` +:cachegroupId: An optional, integer which, if present, should be the :ref:`Cache Group ID ` that identifies a :term:`Cache Group` to which the new :term:`Origin` shall belong +:coordinateId: An optional, integral, unique identifier of a coordinate pair that shall define the :term:`Origin`'s geographic location +:deliveryServiceId: The integral, unique identifier of the :term:`Delivery Service` to which the new :term:`Origin` shall belong +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:ip6Address: An optional string containing the IPv6 address of the :term:`Origin` +:ipAddress: An optional string containing the IPv4 address of the :term:`Origin` +:isPrimary: An optional boolean which, if ``true`` will set this :term:`Origin` as the 'primary' :term:`Origin` served by the :term:`Delivery Service` identified by ``deliveryServiceID`` .. note:: Though not specifying this field in this request will leave it as ``null`` in the output, Traffic Ops will silently coerce that to its default value: ``false``. :name: A human-friendly name of the :term:`Origin` -:port: An optional port number on which the :term:`origin` listens for incoming TCP connections -:profileId: An optional :ref:`profile-id` ofa :term:`Profile` that shall be used by this :term:`origin` +:port: An optional port number on which the :term:`Origin` listens for incoming TCP connections +:profileId: An optional :ref:`profile-id` ofa :term:`Profile` that shall be used by this :term:`Origin` :protocol: The protocol used by the origin - must be one of 'http' or 'https' -:tenantId: An optional\ [1]_, integral, unique identifier for the :term:`Tenant` which shall own the new :term:`origin` +:tenantId: An optional\ [1]_, integral, unique identifier for the :term:`Tenant` which shall own the new :term:`Origin` .. code-block:: http :caption: Request Example @@ -188,25 +188,25 @@ Request Structure Response Structure ------------------ -:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`origin` belongs -:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`origin` belongs +:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`Origin` belongs +:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`Origin` belongs :coordinate: The name of a coordinate pair that defines the origin's geographic location -:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`origin`'s geographic location -:deliveryService: The 'xml_id' of the :term:`Delivery Service` to which the :term:`origin` belongs -:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`origin` belongs -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:id: An integral, unique identifier for this :term:`origin` +:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`Origin`'s geographic location +:deliveryService: The 'xml_id' of the :term:`Delivery Service` to which the :term:`Origin` belongs +:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`Origin` belongs +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:id: An integral, unique identifier for this :term:`Origin` :ip6Address: The IPv6 address of the :term:`Origin` :ipAddress: The IPv4 address of the :term:`Origin` -:isPrimary: A boolean value which, when ``true`` specifies this :term:`origin` as the 'primary' :term:`origin` served by ``deliveryService`` -:lastUpdated: The date and time at which this :term:`origin` was last modified -:name: The name of the :term:`origin` -:port: The TCP port on which the :term:`origin` listens -:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`origin` -:profileId: The :ref:`profile-id` the :term:`Profile` used by this :term:`origin` +:isPrimary: A boolean value which, when ``true`` specifies this :term:`Origin` as the 'primary' :term:`Origin` served by ``deliveryService`` +:lastUpdated: The date and time at which this :term:`Origin` was last modified +:name: The name of the :term:`Origin` +:port: The TCP port on which the :term:`Origin` listens +:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`Origin` +:profileId: The :ref:`profile-id` the :term:`Profile` used by this :term:`Origin` :protocol: The protocol used by this origin - will be one of 'http' or 'https' -:tenant: The name of the :term:`Tenant` that owns this :term:`origin` -:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`origin` +:tenant: The name of the :term:`Tenant` that owns this :term:`Origin` +:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`Origin` .. code-block:: http :caption: Response Example @@ -253,7 +253,7 @@ Response Structure ``PUT`` ======= -Updates an :term:`origin` definition. +Updates an :term:`Origin` definition. :Auth. Required: Yes :Roles Required: "admin" or "operations" @@ -266,21 +266,21 @@ Request Structure +------+----------+-------------------------------------------------------------------------------+ | Name | Required | Description | +======+==========+===============================================================================+ - | id | yes | The integral, unique identifier of the :term:`origin` definition being edited | + | id | yes | The integral, unique identifier of the :term:`Origin` definition being edited | +------+----------+-------------------------------------------------------------------------------+ -:cachegroupId: An optional, integer which, if present, should be the :ref:`Cache Group ID ` that identifies a :term:`Cache Group` to which the new :term:`origin` shall belong -:coordinateId: An optional, integral, unique identifier of a coordinate pair that shall define the :term:`origin`'s geographic location -:deliveryServiceId: The integral, unique identifier of the :term:`Delivery Service` to which the :term:`origin` shall belong -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:ip6Address: An optional string containing the IPv6 address of the :term:`origin` -:ipAddress: An optional string containing the IPv4 address of the :term:`origin` -:isPrimary: An optional boolean which, if ``true`` will set this :term:`origin` as the 'primary' origin served by the :term:`Delivery Service` identified by ``deliveryServiceID`` +:cachegroupId: An optional, integer which, if present, should be the :ref:`Cache Group ID ` that identifies a :term:`Cache Group` to which the new :term:`Origin` shall belong +:coordinateId: An optional, integral, unique identifier of a coordinate pair that shall define the :term:`Origin`'s geographic location +:deliveryServiceId: The integral, unique identifier of the :term:`Delivery Service` to which the :term:`Origin` shall belong +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:ip6Address: An optional string containing the IPv6 address of the :term:`Origin` +:ipAddress: An optional string containing the IPv4 address of the :term:`Origin` +:isPrimary: An optional boolean which, if ``true`` will set this :term:`Origin` as the 'primary' origin served by the :term:`Delivery Service` identified by ``deliveryServiceID`` :name: A human-friendly name of the :term:`Origin` -:port: An optional port number on which the :term:`origin` listens for incoming TCP connections -:profileId: An optional :ref:`profile-id` of the :term:`Profile` that shall be used by this :term:`origin` -:protocol: The protocol used by the :term:`origin` - must be one of 'http' or 'https' -:tenantId: An optional\ [1]_, integral, unique identifier for the :term:`Tenant` which shall own the new :term:`origin` +:port: An optional port number on which the :term:`Origin` listens for incoming TCP connections +:profileId: An optional :ref:`profile-id` of the :term:`Profile` that shall be used by this :term:`Origin` +:protocol: The protocol used by the :term:`Origin` - must be one of 'http' or 'https' +:tenantId: An optional\ [1]_, integral, unique identifier for the :term:`Tenant` which shall own the new :term:`Origin` .. code-block:: http :caption: Request Example @@ -306,25 +306,25 @@ Request Structure Response Structure ------------------ -:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`origin` belongs -:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`origin` belongs +:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`Origin` belongs +:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`Origin` belongs :coordinate: The name of a coordinate pair that defines the origin's geographic location -:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`origin`'s geographic location -:deliveryService: The 'xml_id' of the :term:`Delivery Service` to which the :term:`origin` belongs -:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`origin` belongs -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:id: An integral, unique identifier for this :term:`origin` +:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`Origin`'s geographic location +:deliveryService: The 'xml_id' of the :term:`Delivery Service` to which the :term:`Origin` belongs +:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`Origin` belongs +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:id: An integral, unique identifier for this :term:`Origin` :ip6Address: The IPv6 address of the :term:`Origin` :ipAddress: The IPv4 address of the :term:`Origin` -:isPrimary: A boolean value which, when ``true`` specifies this :term:`origin` as the 'primary' :term:`origin` served by ``deliveryService`` -:lastUpdated: The date and time at which this :term:`origin` was last modified -:name: The name of the :term:`origin` -:port: The TCP port on which the :term:`origin` listens -:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`origin` -:profileId: The :ref:`profile-id` the :term:`Profile` used by this :term:`origin` +:isPrimary: A boolean value which, when ``true`` specifies this :term:`Origin` as the 'primary' :term:`Origin` served by ``deliveryService`` +:lastUpdated: The date and time at which this :term:`Origin` was last modified +:name: The name of the :term:`Origin` +:port: The TCP port on which the :term:`Origin` listens +:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`Origin` +:profileId: The :ref:`profile-id` the :term:`Profile` used by this :term:`Origin` :protocol: The protocol used by this origin - will be one of 'http' or 'https' -:tenant: The name of the :term:`Tenant` that owns this :term:`origin` -:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`origin` +:tenant: The name of the :term:`Tenant` that owns this :term:`Origin` +:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`Origin` .. code-block:: http :caption: Response Example @@ -371,7 +371,7 @@ Response Structure ``DELETE`` ========== -Deletes an :term:`origin` definition. +Deletes an :term:`Origin` definition. :Auth. Required: Yes :Roles Required: "admin" or "operations" @@ -384,7 +384,7 @@ Request Structure +------+----------+--------------------------------------------------------------------------------+ | Name | Required | Description | +======+==========+================================================================================+ - | id | yes | The integral, unique identifier of the :term:`origin` definition being deleted | + | id | yes | The integral, unique identifier of the :term:`Origin` definition being deleted | +------+----------+--------------------------------------------------------------------------------+ .. code-block:: http diff --git a/docs/source/api/v2/server_server_capabilities.rst b/docs/source/api/v2/server_server_capabilities.rst index b3f10b3959..3154538bda 100644 --- a/docs/source/api/v2/server_server_capabilities.rst +++ b/docs/source/api/v2/server_server_capabilities.rst @@ -21,7 +21,7 @@ ``GET`` ======= -Gets all associations of :term:`Server Capabilities` to :term:`Cache Servers`. +Gets all associations of :term:`Server Capabilities` to :term:`cache servers`. :Auth. Required: Yes :Roles Required: None @@ -113,7 +113,7 @@ Request Structure :serverId: The integral, unique identifier of a server to be associated with a :term:`Server Capability` :serverCapability: The :term:`Server Capability`'s name to associate -.. note:: The server referenced must be either an :term:`Edge-tier` or :term:`Mid-tier Cache Server`. +.. note:: The server referenced must be either an :term:`Edge-tier` or :term:`Mid-tier cache server`. .. code-block:: http :caption: Request Example diff --git a/docs/source/api/v3/cdns_name_snapshot.rst b/docs/source/api/v3/cdns_name_snapshot.rst index c93af850c4..942f32d451 100644 --- a/docs/source/api/v3/cdns_name_snapshot.rst +++ b/docs/source/api/v3/cdns_name_snapshot.rst @@ -116,7 +116,7 @@ Response Structure .. seealso:: :ref:`health-proto` -:contentServers: An object containing keys which are the (short) hostnames of the :term:`Edge-Tier cache servers` in the CDN; the values corresponding to those keys are routing information for said servers +:contentServers: An object containing keys which are the (short) hostnames of the :term:`Edge-tier cache servers` in the CDN; the values corresponding to those keys are routing information for said servers :cacheGroup: A string that is the :ref:`cache-group-name` of the :term:`Cache Group` to which the server belongs :deliveryServices: An object containing keys which are the names of :term:`Delivery Services` to which this :term:`cache server` is assigned; the values corresponding to those keys are arrays of :abbr:`FQDNs (Fully Qualified Domain Names)` that resolve to this :term:`cache server` @@ -180,9 +180,9 @@ Response Structure :shuffled: A string containing a boolean that tells whether the :term:`cache servers` chosen for content dispersion are chosen randomly or based on a consistent hash of the request URL; one of: "false" - :term:`Cache servers` will be chosen consistently + :term:`cache servers` will be chosen consistently "true" - :term:`Cache servers` will be chosen at random + :term:`cache servers` will be chosen at random :domains: An array of domains served by this :term:`Delivery Service` :ecsEnabled: A string containing a boolean from :ref:`ds-ecs` that tells whether EDNS0 client subnet is enabled on this :term:`Delivery Service`; one of: diff --git a/docs/source/api/v3/cdns_name_snapshot_new.rst b/docs/source/api/v3/cdns_name_snapshot_new.rst index e722d2d9cc..0920421c44 100644 --- a/docs/source/api/v3/cdns_name_snapshot_new.rst +++ b/docs/source/api/v3/cdns_name_snapshot_new.rst @@ -115,7 +115,7 @@ Response Structure .. seealso:: :ref:`health-proto` -:contentServers: An object containing keys which are the (short) hostnames of the :term:`Edge-Tier cache servers` in the CDN; the values corresponding to those keys are routing information for said servers +:contentServers: An object containing keys which are the (short) hostnames of the :term:`Edge-tier cache servers` in the CDN; the values corresponding to those keys are routing information for said servers :cacheGroup: A string that is the :ref:`cache-group-name` of the :term:`Cache Group` to which the server belongs :deliveryServices: An object containing keys which are the names of :term:`Delivery Services` to which this :term:`cache server` is assigned; the values corresponding to those keys are arrays of :abbr:`FQDNs (Fully Qualified Domain Names)` that resolve to this :term:`cache server` @@ -179,9 +179,9 @@ Response Structure :shuffled: A string containing a boolean that tells whether the :term:`cache servers` chosen for content dispersion are chosen randomly or based on a consistent hash of the request URL; one of: "false" - :term:`Cache servers` will be chosen consistently + :term:`cache servers` will be chosen consistently "true" - :term:`Cache servers` will be chosen at random + :term:`cache servers` will be chosen at random :domains: An array of domains served by this :term:`Delivery Service` :ecsEnabled: A string containing a boolean from :ref:`ds-ecs` that tells whether EDNS0 client subnet is enabled on this :term:`Delivery Service`; one of: diff --git a/docs/source/api/v3/deliveryservices_id_servers_eligible.rst b/docs/source/api/v3/deliveryservices_id_servers_eligible.rst index 8cef711efd..f6bd15b11b 100644 --- a/docs/source/api/v3/deliveryservices_id_servers_eligible.rst +++ b/docs/source/api/v3/deliveryservices_id_servers_eligible.rst @@ -23,7 +23,7 @@ ``GET`` ======= -Retrieves properties of :term:`Edge-Tier cache servers` eligible for assignment to a particular :term:`Delivery Service`. Eligibility is determined based on the following properties: +Retrieves properties of :term:`Edge-tier cache servers` eligible for assignment to a particular :term:`Delivery Service`. Eligibility is determined based on the following properties: - The name of the server's :term:`Type` must match one of the glob patterns ``EDGE*``, ``ORG*`` - The server and :term:`Delivery Service` must belong to the same CDN diff --git a/docs/source/api/v3/origins.rst b/docs/source/api/v3/origins.rst index 650b8d5ad2..175abc6681 100644 --- a/docs/source/api/v3/origins.rst +++ b/docs/source/api/v3/origins.rst @@ -21,7 +21,7 @@ ``GET`` ======= -Gets all requested :term:`origins`. +Gets all requested :term:`Origins`. :Auth. Required: Yes :Roles Required: None @@ -34,22 +34,22 @@ Request Structure +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Name | Required | Description | +=================+==========+===================================================================================================================================================================+ - | cachegroup | no | Return only :term:`origins` within the :term:`Cache Group` that has this :ref:`cache-group-id` | + | cachegroup | no | Return only :term:`Origins` within the :term:`Cache Group` that has this :ref:`cache-group-id` | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | coordinate | no | Return only :term:`origins` located at the geographic coordinates identified by this integral, unique identifier | + | coordinate | no | Return only :term:`Origins` located at the geographic coordinates identified by this integral, unique identifier | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | deliveryservice | no | Return only :term:`origins` that belong to the :term:`Delivery Service` identified by this integral, unique identifier | + | deliveryservice | no | Return only :term:`Origins` that belong to the :term:`Delivery Service` identified by this integral, unique identifier | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | id | no | Return only the :term:`origin` that has this integral, unique identifier | + | id | no | Return only the :term:`Origin` that has this integral, unique identifier | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | name | no | Return only :term:`origins` by this name | + | name | no | Return only :term:`Origins` by this name | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | profileId | no | Return only :term:`origins` which use the :term:`Profile` that has this :ref:`profile-id` | + | profileId | no | Return only :term:`Origins` which use the :term:`Profile` that has this :ref:`profile-id` | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | primary | no | If ``true``, return only :term:`origins` which are the the primary :term:`origin` of the :term:`Delivery Service` to which they belong - if ``false`` return only | - | | | :term:`origins` which are *not* the primary :term:`origin` of the :term:`Delivery Service` to which they belong | + | primary | no | If ``true``, return only :term:`Origins` which are the the primary :term:`Origin` of the :term:`Delivery Service` to which they belong - if ``false`` return only | + | | | :term:`Origins` which are *not* the primary :term:`Origin` of the :term:`Delivery Service` to which they belong | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | tenant | no | Return only :term:`origins` belonging to the tenant identified by this integral, unique identifier | + | tenant | no | Return only :term:`Origins` belonging to the tenant identified by this integral, unique identifier | +-----------------+----------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | orderby | no | Choose the ordering of the results - must be the name of one of the fields of the objects in the ``response`` | | | | array | @@ -77,25 +77,25 @@ Request Structure Response Structure ------------------ -:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`origin` belongs -:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`origin` belongs +:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`Origin` belongs +:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`Origin` belongs :coordinate: The name of a coordinate pair that defines the origin's geographic location -:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`origin`'s geographic location -:deliveryService: A string that is the :ref:`ds-xmlid` of the :term:`Delivery Service` to which the :term:`origin` belongs -:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`origin` belongs -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:id: An integral, unique identifier for this :term:`origin` +:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`Origin`'s geographic location +:deliveryService: A string that is the :ref:`ds-xmlid` of the :term:`Delivery Service` to which the :term:`Origin` belongs +:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`Origin` belongs +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:id: An integral, unique identifier for this :term:`Origin` :ip6Address: The IPv6 address of the :term:`Origin` :ipAddress: The IPv4 address of the :term:`Origin` -:isPrimary: A boolean value which, when ``true`` specifies this :term:`origin` as the 'primary' :term:`origin` served by ``deliveryService`` -:lastUpdated: The date and time at which this :term:`origin` was last modified -:name: The name of the :term:`origin` -:port: The TCP port on which the :term:`origin` listens -:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`origin` -:profileId: The :ref:`profile-id` of the :term:`Profile` used by this :term:`origin` +:isPrimary: A boolean value which, when ``true`` specifies this :term:`Origin` as the 'primary' :term:`Origin` served by ``deliveryService`` +:lastUpdated: The date and time at which this :term:`Origin` was last modified +:name: The name of the :term:`Origin` +:port: The TCP port on which the :term:`Origin` listens +:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`Origin` +:profileId: The :ref:`profile-id` of the :term:`Profile` used by this :term:`Origin` :protocol: The protocol used by this origin - will be one of 'http' or 'https' -:tenant: The name of the :term:`Tenant` that owns this :term:`origin` -:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`origin` +:tenant: The name of the :term:`Tenant` that owns this :term:`Origin` +:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`Origin` .. code-block:: http :caption: Response Example @@ -148,21 +148,21 @@ Creates a new origin definition. Request Structure ----------------- -:cachegroupId: An optional, integer which, if present, should be the :ref:`Cache Group ID ` that identifies a :term:`Cache Group` to which the new :term:`origin` shall belong -:coordinateId: An optional, integral, unique identifier of a coordinate pair that shall define the :term:`origin`'s geographic location -:deliveryServiceId: The integral, unique identifier of the :term:`Delivery Service` to which the new :term:`origin` shall belong -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:ip6Address: An optional string containing the IPv6 address of the :term:`origin` -:ipAddress: An optional string containing the IPv4 address of the :term:`origin` -:isPrimary: An optional boolean which, if ``true`` will set this :term:`origin` as the 'primary' :term:`origin` served by the :term:`Delivery Service` identified by ``deliveryServiceID`` +:cachegroupId: An optional, integer which, if present, should be the :ref:`Cache Group ID ` that identifies a :term:`Cache Group` to which the new :term:`Origin` shall belong +:coordinateId: An optional, integral, unique identifier of a coordinate pair that shall define the :term:`Origin`'s geographic location +:deliveryServiceId: The integral, unique identifier of the :term:`Delivery Service` to which the new :term:`Origin` shall belong +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:ip6Address: An optional string containing the IPv6 address of the :term:`Origin` +:ipAddress: An optional string containing the IPv4 address of the :term:`Origin` +:isPrimary: An optional boolean which, if ``true`` will set this :term:`Origin` as the 'primary' :term:`Origin` served by the :term:`Delivery Service` identified by ``deliveryServiceID`` .. note:: Though not specifying this field in this request will leave it as ``null`` in the output, Traffic Ops will silently coerce that to its default value: ``false``. :name: A human-friendly name of the :term:`Origin` -:port: An optional port number on which the :term:`origin` listens for incoming TCP connections -:profileId: An optional :ref:`profile-id` ofa :term:`Profile` that shall be used by this :term:`origin` +:port: An optional port number on which the :term:`Origin` listens for incoming TCP connections +:profileId: An optional :ref:`profile-id` ofa :term:`Profile` that shall be used by this :term:`Origin` :protocol: The protocol used by the origin - must be one of 'http' or 'https' -:tenantId: An optional\ [1]_, integral, unique identifier for the :term:`Tenant` which shall own the new :term:`origin` +:tenantId: An optional\ [1]_, integral, unique identifier for the :term:`Tenant` which shall own the new :term:`Origin` .. code-block:: http :caption: Request Example @@ -188,25 +188,25 @@ Request Structure Response Structure ------------------ -:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`origin` belongs -:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`origin` belongs +:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`Origin` belongs +:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`Origin` belongs :coordinate: The name of a coordinate pair that defines the origin's geographic location -:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`origin`'s geographic location -:deliveryService: The 'xml_id' of the :term:`Delivery Service` to which the :term:`origin` belongs -:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`origin` belongs -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:id: An integral, unique identifier for this :term:`origin` +:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`Origin`'s geographic location +:deliveryService: The 'xml_id' of the :term:`Delivery Service` to which the :term:`Origin` belongs +:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`Origin` belongs +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:id: An integral, unique identifier for this :term:`Origin` :ip6Address: The IPv6 address of the :term:`Origin` :ipAddress: The IPv4 address of the :term:`Origin` -:isPrimary: A boolean value which, when ``true`` specifies this :term:`origin` as the 'primary' :term:`origin` served by ``deliveryService`` -:lastUpdated: The date and time at which this :term:`origin` was last modified -:name: The name of the :term:`origin` -:port: The TCP port on which the :term:`origin` listens -:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`origin` -:profileId: The :ref:`profile-id` the :term:`Profile` used by this :term:`origin` +:isPrimary: A boolean value which, when ``true`` specifies this :term:`Origin` as the 'primary' :term:`Origin` served by ``deliveryService`` +:lastUpdated: The date and time at which this :term:`Origin` was last modified +:name: The name of the :term:`Origin` +:port: The TCP port on which the :term:`Origin` listens +:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`Origin` +:profileId: The :ref:`profile-id` the :term:`Profile` used by this :term:`Origin` :protocol: The protocol used by this origin - will be one of 'http' or 'https' -:tenant: The name of the :term:`Tenant` that owns this :term:`origin` -:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`origin` +:tenant: The name of the :term:`Tenant` that owns this :term:`Origin` +:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`Origin` .. code-block:: http :caption: Response Example @@ -253,7 +253,7 @@ Response Structure ``PUT`` ======= -Updates an :term:`origin` definition. +Updates an :term:`Origin` definition. :Auth. Required: Yes :Roles Required: "admin" or "operations" @@ -266,21 +266,21 @@ Request Structure +------+----------+-------------------------------------------------------------------------------+ | Name | Required | Description | +======+==========+===============================================================================+ - | id | yes | The integral, unique identifier of the :term:`origin` definition being edited | + | id | yes | The integral, unique identifier of the :term:`Origin` definition being edited | +------+----------+-------------------------------------------------------------------------------+ -:cachegroupId: An optional, integer which, if present, should be the :ref:`Cache Group ID ` that identifies a :term:`Cache Group` to which the new :term:`origin` shall belong -:coordinateId: An optional, integral, unique identifier of a coordinate pair that shall define the :term:`origin`'s geographic location -:deliveryServiceId: The integral, unique identifier of the :term:`Delivery Service` to which the :term:`origin` shall belong -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:ip6Address: An optional string containing the IPv6 address of the :term:`origin` -:ipAddress: An optional string containing the IPv4 address of the :term:`origin` -:isPrimary: An optional boolean which, if ``true`` will set this :term:`origin` as the 'primary' origin served by the :term:`Delivery Service` identified by ``deliveryServiceID`` +:cachegroupId: An optional, integer which, if present, should be the :ref:`Cache Group ID ` that identifies a :term:`Cache Group` to which the new :term:`Origin` shall belong +:coordinateId: An optional, integral, unique identifier of a coordinate pair that shall define the :term:`Origin`'s geographic location +:deliveryServiceId: The integral, unique identifier of the :term:`Delivery Service` to which the :term:`Origin` shall belong +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:ip6Address: An optional string containing the IPv6 address of the :term:`Origin` +:ipAddress: An optional string containing the IPv4 address of the :term:`Origin` +:isPrimary: An optional boolean which, if ``true`` will set this :term:`Origin` as the 'primary' origin served by the :term:`Delivery Service` identified by ``deliveryServiceID`` :name: A human-friendly name of the :term:`Origin` -:port: An optional port number on which the :term:`origin` listens for incoming TCP connections -:profileId: An optional :ref:`profile-id` of the :term:`Profile` that shall be used by this :term:`origin` -:protocol: The protocol used by the :term:`origin` - must be one of 'http' or 'https' -:tenantId: An optional\ [1]_, integral, unique identifier for the :term:`Tenant` which shall own the new :term:`origin` +:port: An optional port number on which the :term:`Origin` listens for incoming TCP connections +:profileId: An optional :ref:`profile-id` of the :term:`Profile` that shall be used by this :term:`Origin` +:protocol: The protocol used by the :term:`Origin` - must be one of 'http' or 'https' +:tenantId: An optional\ [1]_, integral, unique identifier for the :term:`Tenant` which shall own the new :term:`Origin` .. code-block:: http :caption: Request Example @@ -306,25 +306,25 @@ Request Structure Response Structure ------------------ -:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`origin` belongs -:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`origin` belongs +:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the :term:`Origin` belongs +:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the :term:`Origin` belongs :coordinate: The name of a coordinate pair that defines the origin's geographic location -:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`origin`'s geographic location -:deliveryService: The 'xml_id' of the :term:`Delivery Service` to which the :term:`origin` belongs -:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`origin` belongs -:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`origin` -:id: An integral, unique identifier for this :term:`origin` +:coordinateId: An integral, unique identifier for the coordinate pair that defines the :term:`Origin`'s geographic location +:deliveryService: The 'xml_id' of the :term:`Delivery Service` to which the :term:`Origin` belongs +:deliveryServiceId: An integral, unique identifier for the :term:`Delivery Service` to which the :term:`Origin` belongs +:fqdn: The :abbr:`FQDN (Fully Qualified Domain Name)` of the :term:`Origin` +:id: An integral, unique identifier for this :term:`Origin` :ip6Address: The IPv6 address of the :term:`Origin` :ipAddress: The IPv4 address of the :term:`Origin` -:isPrimary: A boolean value which, when ``true`` specifies this :term:`origin` as the 'primary' :term:`origin` served by ``deliveryService`` -:lastUpdated: The date and time at which this :term:`origin` was last modified -:name: The name of the :term:`origin` -:port: The TCP port on which the :term:`origin` listens -:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`origin` -:profileId: The :ref:`profile-id` the :term:`Profile` used by this :term:`origin` +:isPrimary: A boolean value which, when ``true`` specifies this :term:`Origin` as the 'primary' :term:`Origin` served by ``deliveryService`` +:lastUpdated: The date and time at which this :term:`Origin` was last modified +:name: The name of the :term:`Origin` +:port: The TCP port on which the :term:`Origin` listens +:profile: The :ref:`profile-name` of the :term:`Profile` used by this :term:`Origin` +:profileId: The :ref:`profile-id` the :term:`Profile` used by this :term:`Origin` :protocol: The protocol used by this origin - will be one of 'http' or 'https' -:tenant: The name of the :term:`Tenant` that owns this :term:`origin` -:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`origin` +:tenant: The name of the :term:`Tenant` that owns this :term:`Origin` +:tenantId: An integral, unique identifier for the :term:`Tenant` that owns this :term:`Origin` .. code-block:: http :caption: Response Example @@ -371,7 +371,7 @@ Response Structure ``DELETE`` ========== -Deletes an :term:`origin` definition. +Deletes an :term:`Origin` definition. :Auth. Required: Yes :Roles Required: "admin" or "operations" @@ -384,7 +384,7 @@ Request Structure +------+----------+--------------------------------------------------------------------------------+ | Name | Required | Description | +======+==========+================================================================================+ - | id | yes | The integral, unique identifier of the :term:`origin` definition being deleted | + | id | yes | The integral, unique identifier of the :term:`Origin` definition being deleted | +------+----------+--------------------------------------------------------------------------------+ .. code-block:: http diff --git a/docs/source/api/v3/server_server_capabilities.rst b/docs/source/api/v3/server_server_capabilities.rst index 81ef556494..f3ea276818 100644 --- a/docs/source/api/v3/server_server_capabilities.rst +++ b/docs/source/api/v3/server_server_capabilities.rst @@ -21,7 +21,7 @@ ``GET`` ======= -Gets all associations of :term:`Server Capabilities` to :term:`Cache Servers`. +Gets all associations of :term:`Server Capabilities` to :term:`cache servers`. :Auth. Required: Yes :Roles Required: None @@ -113,7 +113,7 @@ Request Structure :serverId: The integral, unique identifier of a server to be associated with a :term:`Server Capability` :serverCapability: The :term:`Server Capability`'s name to associate -.. note:: The server referenced must be either an :term:`Edge-tier` or :term:`Mid-tier Cache Server`. +.. note:: The server referenced must be either an :term:`Edge-tier` or :term:`Mid-tier cache server`. .. code-block:: http :caption: Request Example diff --git a/docs/source/basics/content_delivery_networks.rst b/docs/source/basics/content_delivery_networks.rst index 61b15135a6..94fd8fa993 100644 --- a/docs/source/basics/content_delivery_networks.rst +++ b/docs/source/basics/content_delivery_networks.rst @@ -18,7 +18,7 @@ Content Delivery Networks ************************* The vast majority of today's Internet traffic is media files (often video or audio) being sent from a single source (the *Content Provider*) to many thousands or even millions of destinations (the *Content Consumers*). :abbr:`CDN (Content Delivery Network)`\ s are the technology that make that one-to-many distribution efficient. A :abbr:`CDN (Content Delivery Network)` is a distributed system of servers for delivering content over HTTP(S). These servers are deployed in multiple locations with the goal of optimizing the delivery of content to the end users, while minimizing the traffic on the network. A :abbr:`CDN (Content Delivery Network)` typically consists of the following: -:term:`Cache Servers` +:term:`cache servers` The :dfn:`cache server` is a server that both proxies the requests and caches the results for reuse. Traffic Control uses `Apache Traffic Server `_ to provide :term:`cache servers`. Content Router diff --git a/docs/source/glossary.rst b/docs/source/glossary.rst index d2c85ca939..1c2553b78c 100644 --- a/docs/source/glossary.rst +++ b/docs/source/glossary.rst @@ -32,9 +32,9 @@ Glossary cache servers The main function of a CDN is to proxy requests from clients to :term:`origin servers` and cache the results. To proxy, in the CDN context, is to obtain content using HTTP from an :term:`origin server` on behalf of a client. To cache is to store the results so they can be reused when other clients are requesting the same content. There are three types of proxies in use on the Internet today: - - :term:`Reverse Proxy`: Used by Traffic Control for Edge-tier :dfn:`cache servers`. - - :term:`Forward Proxy`: Used by Traffic Control for Mid-tier :dfn:`cache servers`. - - Transparent Proxy: These are not used by Traffic Control. If you are interested you can learn more about transparent proxies on `wikipedia `_. + - :term:`reverse proxy`: Used by Traffic Control for Edge-tier :dfn:`cache servers`. + - :term:`forward proxy`: Used by Traffic Control for Mid-tier :dfn:`cache servers`. + - transparent proxy: These are not used by Traffic Control. If you are interested you can learn more about transparent proxies on `wikipedia `_. Cache Group Cache Groups @@ -133,7 +133,7 @@ Glossary Federations :dfn:`Federations` allow for other ("federated") CDNs (e.g. at a different :abbr:`ISP (Internet Service Provider)`) to add a list of DNS resolvers and an :abbr:`FQDN (Fully Qualified Domain Name)` to be used in a DNS CNAME record for a :term:`Delivery Service`. When a request is made from one of the federated CDN's clients, Traffic Router will return the CNAME record configured from the federation mapping. This allows the federated CDN to serve the content without the content provider changing the URL, or having to manage multiple URLs. For example, if the external CDN was actually another :abbr:`ATC (Apache Traffic Control)`-managed CDN, then a federation mapping to direct clients toward it should use the :abbr:`FQDN (Fully Qualified Domain Name)` of a :term:`Delivery Service` on the external CDN. - Federations only have meaning to DNS-routed :term:`Delivery Services` - HTTP-routed Delivery services should instead treat the external :abbr:`FQDN (Fully Qualified Domain Name)` as an :term:`origin` to achieve the same effect. + Federations only have meaning to DNS-routed :term:`Delivery Services` - HTTP-routed Delivery services should instead treat the external :abbr:`FQDN (Fully Qualified Domain Name)` as an :term:`Origin` to achieve the same effect. .. seealso:: Federations are currently only manageable by directly using the :ref:`to-api`. The endpoints related to federations are :ref:`to-api-federations`, :ref:`to-api-federation_resolvers`, :ref:`to-api-federations-id-deliveryservices`, :ref:`to-api-federations-id-deliveryservices-id`, :ref:`to-api-federations-id-federation_resolvers`, :ref:`to-api-federations-id-users`, and :ref:`to-api-federations-id-users-id`. @@ -157,10 +157,10 @@ Glossary #. The proxy verifies whether the response for ``http://www-origin-cache.cdn.com/foo/bar/fun.html`` is already in the cache. If it is not in the cache: - #. The proxy sends the HTTP request to the :term:`origin`. + #. The proxy sends the HTTP request to the :term:`Origin`. .. code-block:: http - :caption: The :dfn:`Forward Proxy` Requests Content from the :term:`Origin Server` + :caption: The :dfn:`Forward Proxy` Requests Content from the :term:`origin server` GET /foo/bar/fun.html HTTP/1.1 Host: www.origin.com @@ -168,7 +168,7 @@ Glossary #. The :term:`origin server` responds with the requested content. .. code-block:: http - :caption: The :term:`Origin Server`'s Response + :caption: The :term:`origin server`'s Response HTTP/1.1 200 OK Date: Sun, 14 Dec 2014 23:22:44 GMT @@ -234,10 +234,10 @@ Glossary Mid-tier caches Mid-tier cache server Mid-tier cache servers - The tier above the edge tier. The mid tier does not directly serves the end-user and is used as an additional layer between the edge and the :term:`origin`. In a Traffic Control CDN the basic function of the mid cache is that of a :term:`forward proxy`. + The tier above the edge tier. The mid tier does not directly serves the end-user and is used as an additional layer between the edge and the :term:`Origin`. In a Traffic Control CDN the basic function of the mid cache is that of a :term:`forward proxy`. - origin - origins + Origin + Origins origin server origin servers The source of content for the CDN. Usually a redundant HTTP/1.1 webserver. @@ -263,7 +263,7 @@ Glossary Profile Profiles - A :dfn:`Profile` is, most generally, a group of :term:`Parameters` that will be applied to a server. :dfn:`Profiles` are typically re-used by all :term:`Edge-Tier cache servers` within a CDN or :term:`Cache Group`. A :dfn:`Profile` will, in addition to configuration :term:`Parameters`, define the CDN to which a server belongs and the :ref:`"Type" ` of the Profile - which determines some behaviors of Traffic Control components. The allowed :ref:`"Types" ` of :dfn:`Profiles` are **not** the same as :term:`Types`, and are maintained as a PostgreSQL "Enum" in :atc-file:`traffic_ops/app/db/create_tables.sql`. + A :dfn:`Profile` is, most generally, a group of :term:`Parameters` that will be applied to a server. :dfn:`Profiles` are typically re-used by all :term:`Edge-tier cache servers` within a CDN or :term:`Cache Group`. A :dfn:`Profile` will, in addition to configuration :term:`Parameters`, define the CDN to which a server belongs and the :ref:`"Type" ` of the Profile - which determines some behaviors of Traffic Control components. The allowed :ref:`"Types" ` of :dfn:`Profiles` are **not** the same as :term:`Types`, and are maintained as a PostgreSQL "Enum" in :atc-file:`traffic_ops/app/db/create_tables.sql`. .. tip:: A :dfn:`Profile` of the wrong type assigned to a Traffic Control component *will* (in general) cause it to function incorrectly, regardless of the :term:`Parameters` assigned to it. @@ -288,11 +288,11 @@ Glossary reverse proxy reverse proxies - A :dfn:`reverse proxy` acts on behalf of the :term:`origin server` such that the client is (potentially) unaware it is not communicating directly with the :term:`origin`. All Edge-tier :term:`cache servers` in a Traffic Control CDN are :dfn:`reverse proxies`. To the end user a Traffic Control-based CDN appears as a :dfn:`reverse proxy` since it retrieves content from the :term:`origin server`, acting on behalf of that :term:`origin server`. The client requests a URL that has a hostname which resolves to the :dfn:`reverse proxy`'s IP address and, in compliance with the HTTP 1.1 specification (:rfc:`2616`), the client sends a ``Host:`` header to the :dfn:`reverse proxy` that matches the hostname in the URL. The proxy looks up this hostname in a list of mappings to find the :term:`origin` hostname; if the hostname of the ``Host:`` header is not found in the list, the proxy will send an error (usually either ``404 Not Found`` or ``503 Service Unavailable`` as appropriate) to the client. If the supplied hostname is found in this list of mappings, the proxy checks its cache, and when the content is not already present, connects to the :term:`origin` to which the requested ``Host:`` maps requests the path of the original URL, providing the :term:`origin` hostname in the ``Host`` header. The proxy then stores the URL in its cache and serves the contents to the client. When there are subsequent requests for the same URL, a caching proxy serves the content out of its cache - provided :ref:`cache-revalidation` are satisfied - thereby reducing latency and network traffic. + A :dfn:`reverse proxy` acts on behalf of the :term:`origin server` such that the client is (potentially) unaware it is not communicating directly with the :term:`Origin`. All Edge-tier :term:`cache servers` in a Traffic Control CDN are :dfn:`reverse proxies`. To the end user a Traffic Control-based CDN appears as a :dfn:`reverse proxy` since it retrieves content from the :term:`origin server`, acting on behalf of that :term:`origin server`. The client requests a URL that has a hostname which resolves to the :dfn:`reverse proxy`'s IP address and, in compliance with the HTTP 1.1 specification (:rfc:`2616`), the client sends a ``Host:`` header to the :dfn:`reverse proxy` that matches the hostname in the URL. The proxy looks up this hostname in a list of mappings to find the :term:`Origin` hostname; if the hostname of the ``Host:`` header is not found in the list, the proxy will send an error (usually either ``404 Not Found`` or ``503 Service Unavailable`` as appropriate) to the client. If the supplied hostname is found in this list of mappings, the proxy checks its cache, and when the content is not already present, connects to the :term:`Origin` to which the requested ``Host:`` maps requests the path of the original URL, providing the :term:`Origin` hostname in the ``Host`` header. The proxy then stores the URL in its cache and serves the contents to the client. When there are subsequent requests for the same URL, a caching proxy serves the content out of its cache - provided :ref:`cache-revalidation` are satisfied - thereby reducing latency and network traffic. .. seealso:: `The Apache Traffic Server documentation on reverse proxy `_. - To insert a :dfn:`reverse proxy` into a typical HTTP 1.1 request and response flow, the :dfn:`reverse proxy` needs to be told where the :term:`origin server` can be reached (and which :term:`origin` to use for a given request when it's configured to proxy requests for multiple :term:`origins`). In :abbr:`ATS (Apache Traffic Server)` this is handled by adding rules to `the remap.config configuration file `_. The content owner must inform the clients, by updating the URL, to receive the content from the cache and not from the :term:`origin server` directly. For example, clients might be instructed to request content from ``http://www-origin-cache.cdn.com`` which points to a :dfn:`reverse proxy` for the actual :term:`origin` located at ``http://www.origin.com``. + To insert a :dfn:`reverse proxy` into a typical HTTP 1.1 request and response flow, the :dfn:`reverse proxy` needs to be told where the :term:`origin server` can be reached (and which :term:`Origin` to use for a given request when it's configured to proxy requests for multiple :term:`Origins`). In :abbr:`ATS (Apache Traffic Server)` this is handled by adding rules to `the remap.config configuration file `_. The content owner must inform the clients, by updating the URL, to receive the content from the cache and not from the :term:`origin server` directly. For example, clients might be instructed to request content from ``http://www-origin-cache.cdn.com`` which points to a :dfn:`reverse proxy` for the actual :term:`Origin` located at ``http://www.origin.com``. Now, if the client requests ``/foo/bar/fun.html`` from the :dfn:`reverse proxy` the sequence of events is as follows. is given the URL ``http://www-origin-cache.cdn.com/foo/bar/fun.html`` (note the different hostname) and when attempting to obtain that URL, the following occurs: @@ -306,14 +306,14 @@ Glossary GET /foo/bar/fun.html HTTP/1.1 Host: www-origin-cache.cdn.com - #. The :dfn:`reverse proxy` finds out the URL of the true :term:`origin` - in the case of :abbr:`ATS (Apache Traffic Server)` this is done by looking up ``www-origin-cache.cdn.com`` in its remap rules - and finds that it is ``www.origin.com``. + #. The :dfn:`reverse proxy` finds out the URL of the true :term:`Origin` - in the case of :abbr:`ATS (Apache Traffic Server)` this is done by looking up ``www-origin-cache.cdn.com`` in its remap rules - and finds that it is ``www.origin.com``. #. The proxy checks its cache to see if the response for ``GET /foo/bar/fun.html HTTP/1.1`` from ``www.origin.com`` is already in the cache. #. If the response is not in the cache: - #. The proxy sends the request to the actual :term:`origin` + #. The proxy sends the request to the actual :term:`Origin` .. code-block:: http - :caption: :dfn:`Reverse Proxy` Requests Content from the :term:`Origin Server` + :caption: :dfn:`Reverse Proxy` Requests Content from the :term:`origin server` GET /foo/bar/fun.html HTTP/1.1 Host: www.origin.com @@ -321,7 +321,7 @@ Glossary #. The :term:`origin server` responds with the requested content .. code-block:: http - :caption: Response from the :term:`Origin Server` + :caption: Response from the :term:`origin server` HTTP/1.1 200 OK Date: Sun, 14 Dec 2014 23:22:44 GMT @@ -376,7 +376,7 @@ Glossary Server Capability Server Capabilities - A :dfn:`Server Capability` (not to be confused with a "Capability") expresses the capacity of a :term:`cache server` to serve a particular kind of traffic. For example, a :dfn:`Server Capability` could be created named "RAM" to be assigned to :term:`cache servers` that have RAM-disks allocated for content caching. :dfn:`Server Capabilities` can also be required by :term:`Delivery Services`, which will prevent :term:`cache servers` without that :dfn:`Server Capability` from being assigned to them. It also prevents :term:`Mid-tier Cache Servers` without said :term:`Server Capability` from being selected to serve upstream requests from those :term:`Edge-tier Cache Servers` assigned to the requiring :term:`Delivery Services`. + A :dfn:`Server Capability` (not to be confused with a "Capability") expresses the capacity of a :term:`cache server` to serve a particular kind of traffic. For example, a :dfn:`Server Capability` could be created named "RAM" to be assigned to :term:`cache servers` that have RAM-disks allocated for content caching. :dfn:`Server Capabilities` can also be required by :term:`Delivery Services`, which will prevent :term:`cache servers` without that :dfn:`Server Capability` from being assigned to them. It also prevents :term:`Mid-tier cache servers` without said :term:`Server Capability` from being selected to serve upstream requests from those :term:`Edge-tier cache servers` assigned to the requiring :term:`Delivery Services`. Snapshot Snapshots diff --git a/docs/source/overview/cache_groups.rst b/docs/source/overview/cache_groups.rst index 53efabd33d..53b0b0b3b0 100644 --- a/docs/source/overview/cache_groups.rst +++ b/docs/source/overview/cache_groups.rst @@ -22,7 +22,7 @@ A :dfn:`Cache Group` is - ostensibly - exactly what it sounds like it is: a grou The most typical :ref:`Types ` of Cache Groups are EDGE_LOC_ which contain :term:`Edge-tier cache servers` and MID_LOC_ which contain :term:`Mid-tier cache servers`. The latter are each designated as a Parent_ of one or more of the former to fill out the two-tiered caching hierarchy of an :abbr:`ATC (Apache Traffic Control)` CDN. -Consider the example CDN in :numref:`fig-cg_hierarchy`. Here some country/province/region has been divided into quarters: Northeast, Southeast, Northwest, and Southwest. The arrows in the diagram indicate the flow of requests. If a client in the Northwest, for example, were to make a request to the :term:`Delivery Service`, it would first be directed to some :term:`cache server` in the "Northwest" Edge-tier :dfn:`Cache Group`. Should the requested content not be in cache, the Edge-tier server will select a parent from the "West" :dfn:`Cache Group` and pass the request up, caching the result for future use. All Mid-tier :dfn:`Cache Groups` (usually) answer to a single :term:`origin` that provides canonical content. If requested content is not in the Mid-tier cache, then the request will be passed up to the :term:`origin` and the result cached. +Consider the example CDN in :numref:`fig-cg_hierarchy`. Here some country/province/region has been divided into quarters: Northeast, Southeast, Northwest, and Southwest. The arrows in the diagram indicate the flow of requests. If a client in the Northwest, for example, were to make a request to the :term:`Delivery Service`, it would first be directed to some :term:`cache server` in the "Northwest" Edge-tier :dfn:`Cache Group`. Should the requested content not be in cache, the Edge-tier server will select a parent from the "West" :dfn:`Cache Group` and pass the request up, caching the result for future use. All Mid-tier :dfn:`Cache Groups` (usually) answer to a single :term:`Origin` that provides canonical content. If requested content is not in the Mid-tier cache, then the request will be passed up to the :term:`Origin` and the result cached. .. _fig-cg_hierarchy: @@ -307,7 +307,7 @@ This :term:`Type` of Cache Group contains :term:`Mid-tier cache servers` ORG_LOC """"""" -This :term:`Type` of Cache Group contains :term:`origins`. The primary purpose of these is to group :term:`origins` for the purposes of "multi-site-origins", and it's suggested that if that doesn't meet your use-case that these be mostly avoided. In general, it's not strictly necessary to create :term:`origin` *servers* in ATC at all, unless you have to support "multi-site-origins". +This :term:`Type` of Cache Group contains :term:`Origins`. The primary purpose of these is to group :term:`Origins` for the purposes of "multi-site-origins", and it's suggested that if that doesn't meet your use-case that these be mostly avoided. In general, it's not strictly necessary to create :term:`Origin` *servers* in ATC at all, unless you have to support "multi-site-origins". .. seealso:: :ref:`multi-site-origin-qht` diff --git a/docs/source/overview/delivery_services.rst b/docs/source/overview/delivery_services.rst index c5ca7a3394..bc05c66421 100644 --- a/docs/source/overview/delivery_services.rst +++ b/docs/source/overview/delivery_services.rst @@ -56,7 +56,7 @@ Cache URL Expression .. deprecated:: 3.0 This feature is no longer supported by :abbr:`ATS (Apache Traffic Server)` and consequently it will be removed from Traffic Control in the future. -Manipulates the cache key of the incoming requests. Normally, the cache key is the :term:`origin` domain. This can be changed so that multiple services can share a cache key, can also be used to preserve cached content if service origin is changed. +Manipulates the cache key of the incoming requests. Normally, the cache key is the :term:`Origin` domain. This can be changed so that multiple services can share a cache key, can also be used to preserve cached content if service origin is changed. .. warning:: This field provides access to a feature that was only present in :abbr:`ATS (Apache Traffic Server)` 6.X and earlier. As :term:`cache servers` must now use :abbr:`ATS (Apache Traffic Server)` 7.1.X, this field **must** be blank unless all :term:`cache servers` can be guaranteed to use that older :abbr:`ATS (Apache Traffic Server)` version (**NOT** recommended). @@ -70,7 +70,7 @@ A CDN to which this Delivery Service belongs. Only :term:`cache servers` within Check Path ---------- -A request path on the :term:`origin server` which is used to by certain :ref:`Traffic Ops Extensions ` to indicate the "health" of the :term:`origin`. +A request path on the :term:`origin server` which is used to by certain :ref:`Traffic Ops Extensions ` to indicate the "health" of the :term:`Origin`. .. _ds-consistent-hashing-regex: @@ -521,7 +521,7 @@ The Origin Server’s base URL which includes the protocol (http or https). Exam Origin Shield ------------- -An experimental feature that allows administrators to list additional forward proxies that sit between the :term:`Mid-tier` and the :term:`origin`. In most scenarios, this is represented (and required to be input) as a pipe (``|``)-delimited string. +An experimental feature that allows administrators to list additional forward proxies that sit between the :term:`Mid-tier` and the :term:`Origin`. In most scenarios, this is represented (and required to be input) as a pipe (``|``)-delimited string. .. _ds-profile: @@ -577,9 +577,9 @@ Query String Handling Describes how query strings should be handled by the :term:`Edge-tier cache servers` when serving content for this Delivery Service. This is nearly always expressed as an integral, unique identifier for each behavior, though in Traffic Portal a more descriptive value is typically used, or at least provided in addition to the integral, unique identifier. The allowed values and their meanings are: 0 - For the purposes of caching, :term:`Edge-tier cache servers` will consider URLs unique if and only if they are unique up to and including any and all query parameters. They will also pass the query parameters in their own requests to :term:`Mid-tier cache servers` (which in turn will exhibit the same caching behavior and pass the query parameters in requests to the :term:`origin`). (Aliased as "USE" in Traffic Portal tables, and "0 - use qstring in cache key, and pass up" in Traffic Portal forms) + For the purposes of caching, :term:`Edge-tier cache servers` will consider URLs unique if and only if they are unique up to and including any and all query parameters. They will also pass the query parameters in their own requests to :term:`Mid-tier cache servers` (which in turn will exhibit the same caching behavior and pass the query parameters in requests to the :term:`Origin`). (Aliased as "USE" in Traffic Portal tables, and "0 - use qstring in cache key, and pass up" in Traffic Portal forms) 1 - For the purposes of caching, neither :term:`Edge-tier` nor :term:`Mid-tier cache servers` will consider the query parameter string when determining if a URL is stored in cache. However, the query string will still be passed in upstream requests to :term:`Mid-tier cache servers` and in turn the :term:`origin`. (Aliased as "IGNORE" in Traffic Portal tables and "1 - ignore in cache key, and pass up" in Traffic Portal forms) + For the purposes of caching, neither :term:`Edge-tier` nor :term:`Mid-tier cache servers` will consider the query parameter string when determining if a URL is stored in cache. However, the query string will still be passed in upstream requests to :term:`Mid-tier cache servers` and in turn the :term:`Origin`. (Aliased as "IGNORE" in Traffic Portal tables and "1 - ignore in cache key, and pass up" in Traffic Portal forms) 2 The query parameter string will be stripped from URLs immediately when the request is received by an :term:`Edge-tier cache server`. This means it is never considered for the purposes of caching unique URLs and will not be passed in upstream requests. (Aliased as "DROP" in Traffic Portal tables and "2 - drop at edge" in Traffic Portal forms) @@ -657,7 +657,7 @@ For example, if you have an Apache Traffic Server lua plugin which manipulates t Regex Remap Expression ---------------------- -Allows remapping of incoming requests URL using regular expressions to search and replace text. In a more literal sense, this is the raw contents of a configuration file used by the `ATS regex_remap plugin `_. At its most basic, the contents of this field should consist of ``map`` followed by a regular expression and then a "template URL" - all space-separated. The regular expression matches a client's request *path* (i.e. not a full URL - ``/path/to/content`` **not** ``https://origin.example.com/path/to/content``) and when such a match occurs, the request is transformed into a request for the template URL. The most basic usage of the template URL is to use ``$1``-``$9`` to insert the corresponding regular expression capture group. For example, a regular expression of :regexp:`^/a/(.*)` and a template URL of ``https://origin.example.com/b/$1`` maps requests for :term:`origin` content under path ``/a/`` to the same sub-paths under path ``b``. Note that since it's a full URL, this mapping can be made to another server entirely. +Allows remapping of incoming requests URL using regular expressions to search and replace text. In a more literal sense, this is the raw contents of a configuration file used by the `ATS regex_remap plugin `_. At its most basic, the contents of this field should consist of ``map`` followed by a regular expression and then a "template URL" - all space-separated. The regular expression matches a client's request *path* (i.e. not a full URL - ``/path/to/content`` **not** ``https://origin.example.com/path/to/content``) and when such a match occurs, the request is transformed into a request for the template URL. The most basic usage of the template URL is to use ``$1``-``$9`` to insert the corresponding regular expression capture group. For example, a regular expression of :regexp:`^/a/(.*)` and a template URL of ``https://origin.example.com/b/$1`` maps requests for :term:`Origin` content under path ``/a/`` to the same sub-paths under path ``b``. Note that since it's a full URL, this mapping can be made to another server entirely. .. seealso:: The `documentation for the regex_remap plugin `_ for :abbr:`ATS (Apache Traffic Server)` @@ -691,7 +691,7 @@ Required Capabilities --------------------- .. versionadded:: ATCv4 -A Delivery Service can be associated with :term:`Server Capabilities` that it requires :term:`cache servers` serving its content to have. When one or more :term:`Server Capability` is required by a Delivery Service, it will block the assignment of :term:`cache servers` to it that do not have those :term:`Server Capabilities`. Additionally, the :term:`Edge-tier Cache Servers` assigned to a Delivery Service that requires a :term:`Server Capability` will only request content they do not have cached from :term:`Mid-tier Cache Servers` which also have this :term:`Server Capability`. +A Delivery Service can be associated with :term:`Server Capabilities` that it requires :term:`cache servers` serving its content to have. When one or more :term:`Server Capability` is required by a Delivery Service, it will block the assignment of :term:`cache servers` to it that do not have those :term:`Server Capabilities`. Additionally, the :term:`Edge-tier cache servers` assigned to a Delivery Service that requires a :term:`Server Capability` will only request content they do not have cached from :term:`Mid-tier cache servers` which also have this :term:`Server Capability`. Typically, a required :term:`Server Capability` is represented merely by the name of said :term:`Server Capability`. In fact, there's nothing more to a :term:`Server Capability` than its name; it's the responsibility of CDN operators to ensure that they are assigned and required properly. There is no mechanism to detect whether or not a :term:`cache server` has a given :term:`Server Capability`, it must be assigned manually. @@ -711,7 +711,7 @@ Servers can be assigned to Delivery Services using the :ref:`tp-configure-server Signing Algorithm ----------------- -URLs/URIs may be signed using one of two algorithms before a request for the content to which they refer is sent to the :term:`origin` (which in practice can be any upstream network). At the time of this writing, this field is restricted within the Traffic Ops Database to one of two values (or ``NULL``/"None", to indicate no signing should be done). +URLs/URIs may be signed using one of two algorithms before a request for the content to which they refer is sent to the :term:`Origin` (which in practice can be any upstream network). At the time of this writing, this field is restricted within the Traffic Ops Database to one of two values (or ``NULL``/"None", to indicate no signing should be done). .. seealso:: The url_sig `README `_. @@ -866,11 +866,11 @@ CLIENT_STEERING A CLIENT_STEERING Delivery Service is exactly like STEERING except that it provides clients with methods of bypassing the weights, orders, and localizations of targets in order to choose any arbitrary target at will. When utilizing these methods, the client will either directly choose a target immediately or request a list of all available targets from Traffic Router and then choose one to which to send a subsequent request for actual content. CLIENT_STEERING also supports two additional target types: STEERING_GEO_ORDER - These targets behave exactly like STEERING_ORDER targets, but Delivery Services are grouped according to the "locations" of their :term:`origins`. Before choosing a Delivery Service to which to direct the client, Traffic Router will first create subsets of choices according to these groupings, and order them by physical distance from the client (closest to farthest). Within these subsets, the values of the targets establish a strict precedence ordering, just like STEERING_ORDER targets. + These targets behave exactly like STEERING_ORDER targets, but Delivery Services are grouped according to the "locations" of their :term:`Origins`. Before choosing a Delivery Service to which to direct the client, Traffic Router will first create subsets of choices according to these groupings, and order them by physical distance from the client (closest to farthest). Within these subsets, the values of the targets establish a strict precedence ordering, just like STEERING_ORDER targets. STEERING_GEO_WEIGHT - These targets behave exactly like STEERING_WEIGHT targets, but Delivery Services are grouped according to the "locations" of their :term:`origins`. Before choosing a Delivery Service to which to direct the client, Traffic Router will first create subsets of choices according to these groupings, and order them by physical distance from the client (closest to farthest). Within these subsets, the values of the targets establish the likelihood that any given target within the subset will be chosen for the client - effectively determining the spread of traffic across targets within that subset. + These targets behave exactly like STEERING_WEIGHT targets, but Delivery Services are grouped according to the "locations" of their :term:`Origins`. Before choosing a Delivery Service to which to direct the client, Traffic Router will first create subsets of choices according to these groupings, and order them by physical distance from the client (closest to farthest). Within these subsets, the values of the targets establish the likelihood that any given target within the subset will be chosen for the client - effectively determining the spread of traffic across targets within that subset. - .. important:: To make use of the STEERING_GEO_ORDER and/or STEERING_GEO_WEIGHT target types, it is first necessary to ensure that at least the "primary" :term:`origin` of the :term:`Delivery Service` has an associated geographic coordinate pair. This can be done either from the :ref:`tp-configure-origins` page in Traffic Portal, or using the :ref:`to-api-origins` :ref:`to-api` endpoint. + .. important:: To make use of the STEERING_GEO_ORDER and/or STEERING_GEO_WEIGHT target types, it is first necessary to ensure that at least the "primary" :term:`Origin` of the :term:`Delivery Service` has an associated geographic coordinate pair. This can be done either from the :ref:`tp-configure-origins` page in Traffic Portal, or using the :ref:`to-api-origins` :ref:`to-api` endpoint. .. note:: "Steering" is also commonly used to collectively refer to either of the kinds of Delivery Services that can participate in steering behavior (STEERING and CLIENT_STEERING). @@ -888,7 +888,7 @@ CLIENT_STEERING Use Multi-Site Origin Feature ----------------------------- -A boolean value that indicates whether or not this Delivery Service serves content for an :term:`origin` that provides content from two or more redundant servers. There are very few good reasons for this to not be ``false``. When ``true``, Traffic Ops will configure :term:`Mid-tier cache servers` to perform load-balancing and other optimizations for redundant :term:`origin servers`. +A boolean value that indicates whether or not this Delivery Service serves content for an :term:`Origin` that provides content from two or more redundant servers. There are very few good reasons for this to not be ``false``. When ``true``, Traffic Ops will configure :term:`Mid-tier cache servers` to perform load-balancing and other optimizations for redundant :term:`origin servers`. Naturally, this assumes that each redundant server is exactly identical, from request paths to actual content. If Multi-Site Origin is configured for servers that are *not* identical, the client's experience is undefined. Furthermore, the :term:`origin servers` may have differing IP addresses, but **must** serve content for a single :abbr:`FQDN (Fully Qualified Domain Name)` - as defined by the Delivery Service's `Origin Server Base URL`_. These redundant servers **must** be configured as servers (server :term:`Type` ``ORG``) in Traffic Ops - either using the :ref:`appropriate section of Traffic Portal ` or the :ref:`to-api-servers` endpoint. diff --git a/docs/source/overview/profiles_and_parameters.rst b/docs/source/overview/profiles_and_parameters.rst index 6532d73eb1..9b90d5d2f6 100644 --- a/docs/source/overview/profiles_and_parameters.rst +++ b/docs/source/overview/profiles_and_parameters.rst @@ -100,7 +100,7 @@ LOGSTASH_PROFILE .. warning:: For legacy reasons, the names of Profiles of this type *must* begin with ``LOGSTASH_``. This is **not** enforced by the :ref:`to-api` or Traffic Portal, but certain Traffic Control operations/components expect this and will fail to work otherwise! ORG_PROFILE - A Profile that may be used by either :term:`origin servers` or :term:`origins` (no, they aren't the same thing). + A Profile that may be used by either :term:`origin servers` or :term:`Origins` (no, they aren't the same thing). .. warning:: For legacy reasons, the names of Profiles of this type *must* begin with ``MSO``, or contain either ``ORG`` or ``ORIGIN`` anywhere in the name. This is **not** enforced by the :ref:`to-api` or Traffic Portal, but certain Traffic Control operations/components expect this and will fail to work otherwise! @@ -314,7 +314,7 @@ Config Files that match this pattern - where ``anything`` is zero or more charac hosting.config '''''''''''''' -This configuration file is mainly generated based on the assignments of :term:`cache servers` to :term:`Delivery Services` and the :term:`Cache Group` hierarchy, but there are a couple of Parameter :ref:`Names ` that can affect it when assigned to this Config File. When a Parameter assigned to the ``storage.config`` Config File - **NOT this Config File** - with the :ref:`parameter-name` "RAM_Drive_Prefix" *exists*, it will cause lines to be generated in this configuration file for each :term:`Delivery Service` that is of on of the :ref:`Types ` DNS_LIVE (only if the server is an :term:`Edge-Tier Cache Server`), HTTP_LIVE (only if the server is an :term:`Edge-Tier Cache Server`), DNS_LIVE_NATNL, or HTTP_LIVE_NATNL to which the :term:`cache server` to which the :ref:`Profile ` containing that Parameter belongs is assigned. Specifically, it will cause each of them to use ``volume=1`` **UNLESS** the Parameter with the :ref:`parameter-name` "Drive_Prefix" associated with Config File ``storage.config`` - again, **NOT this Config File** - *also* exists, in which case they will use ``volume=2``. +This configuration file is mainly generated based on the assignments of :term:`cache servers` to :term:`Delivery Services` and the :term:`Cache Group` hierarchy, but there are a couple of Parameter :ref:`Names ` that can affect it when assigned to this Config File. When a Parameter assigned to the ``storage.config`` Config File - **NOT this Config File** - with the :ref:`parameter-name` "RAM_Drive_Prefix" *exists*, it will cause lines to be generated in this configuration file for each :term:`Delivery Service` that is of on of the :ref:`Types ` DNS_LIVE (only if the server is an :term:`Edge-tier cache server`), HTTP_LIVE (only if the server is an :term:`Edge-tier cache server`), DNS_LIVE_NATNL, or HTTP_LIVE_NATNL to which the :term:`cache server` to which the :ref:`Profile ` containing that Parameter belongs is assigned. Specifically, it will cause each of them to use ``volume=1`` **UNLESS** the Parameter with the :ref:`parameter-name` "Drive_Prefix" associated with Config File ``storage.config`` - again, **NOT this Config File** - *also* exists, in which case they will use ``volume=2``. .. caution:: If a Parameter with Config File ``storage.config`` and :ref:`parameter-name` "RAM_Drive_Prefix" does *not* exist on a :ref:`Profile `, then the :term:`cache servers` using that :ref:`Profile ` will **be incapable of serving traffic for** :term:`Delivery Services` **of the aforementioned** :ref:`Types `, **even when a** :ref:`"location" ` **Parameter exists**. diff --git a/docs/source/overview/traffic_portal.rst b/docs/source/overview/traffic_portal.rst index 2e22bb3fe1..1ae20e6e68 100644 --- a/docs/source/overview/traffic_portal.rst +++ b/docs/source/overview/traffic_portal.rst @@ -25,6 +25,6 @@ Features - CDN Monitoring - CDN Administration - :term:`Delivery Service` Configuration -- :term:`Cache Server` Maintenance +- :term:`cache server` Maintenance .. seealso:: See :ref:`usingtrafficportal` for an overview of the Traffic Portal UI. diff --git a/docs/source/overview/traffic_router.rst b/docs/source/overview/traffic_router.rst index 697565c536..3773c08aeb 100644 --- a/docs/source/overview/traffic_router.rst +++ b/docs/source/overview/traffic_router.rst @@ -32,7 +32,7 @@ Traffic routing options are often configured at the :term:`Delivery Service` lev DNS Content Routing =================== -For a DNS :term:`Delivery Service` the client might receive a URL such as ``http://video.demo1.mycdn.ciab.test/``. When the :abbr:`LDNS (Local Domain Name Server)` is resolving this ``video.demo1.mycdn.ciab.test`` hostname to an IP address, it ends at Traffic Router because it is the authoritative DNS server for ``mycdn.ciab.test`` and the domains below it, and subsequently responds with a list of IP addresses from the eligible :term:`cache servers` based on the location of the :abbr:`LDNS (Local Domain Name Server)`. When responding, Traffic Router does not know the actual client IP address or the path that the client is going to request. The decision on what :term:`cache server` IP address (or list of :term:`cache server` IP addresses) to return is solely based on the location of the :abbr:`LDNS (Local Domain Name Server)` and the health of the :term:`cache servers`. The client then connects to port 80 (HTTP) or port 443 (HTTPS) on the :term:`cache server`, and sends the ``Host: video.demo1.mycdn.ciab.test`` header. The configuration of the :term:`cache server` includes the "remap rule" ``http://video.demo1.mycdn.ciab.test http://origin.infra.ciab.test`` to map the routed name to an :term:`origin` hostname. +For a DNS :term:`Delivery Service` the client might receive a URL such as ``http://video.demo1.mycdn.ciab.test/``. When the :abbr:`LDNS (Local Domain Name Server)` is resolving this ``video.demo1.mycdn.ciab.test`` hostname to an IP address, it ends at Traffic Router because it is the authoritative DNS server for ``mycdn.ciab.test`` and the domains below it, and subsequently responds with a list of IP addresses from the eligible :term:`cache servers` based on the location of the :abbr:`LDNS (Local Domain Name Server)`. When responding, Traffic Router does not know the actual client IP address or the path that the client is going to request. The decision on what :term:`cache server` IP address (or list of :term:`cache server` IP addresses) to return is solely based on the location of the :abbr:`LDNS (Local Domain Name Server)` and the health of the :term:`cache servers`. The client then connects to port 80 (HTTP) or port 443 (HTTPS) on the :term:`cache server`, and sends the ``Host: video.demo1.mycdn.ciab.test`` header. The configuration of the :term:`cache server` includes the "remap rule" ``http://video.demo1.mycdn.ciab.test http://origin.infra.ciab.test`` to map the routed name to an :term:`Origin` hostname. .. _http-cr: @@ -50,7 +50,7 @@ For an HTTP :term:`Delivery Service` the client might receive a URL such as ``ht Traffic Router uses an HTTP ``302 Found`` response to redirect the client to the best :term:`cache server`. .. code-block:: http - :caption: Traffic Router Redirect to Edge-tier :term:`Cache Server` + :caption: Traffic Router Redirect to Edge-tier :term:`cache server` HTTP/1.1 302 Found Location: http://edge.demo1.mycdn.ciab.test/ From af5d16e7451de70b1a7fc1a9c9bb81abd850ebd0 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 19 May 2020 11:32:01 -0600 Subject: [PATCH 51/87] Added response structure for DELETE /servers/{{ID}} --- docs/source/api/v3/servers_id.rst | 77 +++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/docs/source/api/v3/servers_id.rst b/docs/source/api/v3/servers_id.rst index 55e66ec50d..041eb6e20f 100644 --- a/docs/source/api/v3/servers_id.rst +++ b/docs/source/api/v3/servers_id.rst @@ -352,6 +352,83 @@ Request Structure Response Structure ------------------ +:cachegroup: A string that is the :ref:`name of the Cache Group ` to which the server belonged +:cachegroupId: An integer that is the :ref:`ID of the Cache Group ` to which the server belonged +:cdnId: The integral, unique identifier of the CDN to which the server belonged +:cdnName: Name of the CDN to which the server belonged +:domainName: The domain part of the server's :abbr:`FQDN (Fully Qualified Domain Name)` +:guid: An identifier used to uniquely identify the server + + .. note:: This is a legacy key which only still exists for compatibility reasons - it should always be ``null`` + +:hostName: The (short) hostname of the server +:httpsPort: The port on which the server listened for incoming HTTPS connections/requests +:id: An integral, unique identifier for this server +:iloIpAddress: The IPv4 address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloIpGateway: The IPv4 gateway address of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloIpNetmask: The IPv4 subnet mask of the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:iloPassword: The password of the of the server's :abbr:`ILO (Integrated Lights-Out)` service user\ [#ilo]_ - displays as simply ``******`` if the currently logged-in user does not have the 'admin' or 'operations' :term:`Role(s) ` +:iloUsername: The user name for the server's :abbr:`ILO (Integrated Lights-Out)` service\ [#ilo]_ +:interfaces: A set of the network interfaces that were in use by the server + + :ipAddresses: A set of objects representing IP Addresses that were assigned to this network interface + + :address: The actual IP address, including any mask as a CIDR-notation suffix + :gateway: Either the IP address of the network gateway for this address, or ``null`` to signify that no such gateway exists + :serviceAddress: A boolean that describes whether or not the server's main service is available at this IP address. When this property is ``true``, the IP address is referred to as a "service address". + + :maxBandwidth: The maximum healthy bandwidth allowed for this interface. If bandwidth exceeds this limit, Traffic Monitors would have considered the entire server unhealthy - which includes *all* configured network interfaces. If this was ``null``, it has the meaning "no limit". It had no effect if ``monitor`` was not true for this interface. + + .. seealso:: :ref:`health-proto` + + :monitor: A boolean which describes whether or not this interface should have been monitored by Traffic Monitor for statistics and health consideration + :mtu: The :abbr:`MTU (Maximum Transmission Unit)` of this interface. If it is ``null``, it may be assumed that the information was either not available or not applicable for this interface. + :name: The name of the interface. It is the same as the network interface's device name on the server, e.g. ``eth0``. + +:lastUpdated: The date and time at which this server description was last modified +:mgmtIpAddress: The IPv4 address of some network interface on the server that was used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + +:mgmtIpGateway: The IPv4 address of a gateway used by some network interface on the server that was used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + +:mgmtIpNetmask: The IPv4 subnet mask used by some network interface on the server that was used for 'management' + + .. deprecated:: 3.0 + This field is deprecated and will be removed in a future API version. Operators should migrate this data into the ``interfaces`` property of the server. + +:offlineReason: A user-entered reason why the server was in ADMIN_DOWN or OFFLINE status +:physLocation: The name of the physical location where the server resided +:physLocationId: An integral, unique identifier for the physical location where the server resided +:profile: The :ref:`profile-name` of the :term:`Profile` which was used by this server +:profileDesc: A :ref:`profile-description` of the :term:`Profile` which was used by this server +:profileId: The :ref:`profile-id` the :term:`Profile` which was used by this server +:revalPending: A boolean value which, if ``true`` indicates that this server had pending content invalidation/revalidation +:rack: A string indicating "server rack" location +:routerHostName: The human-readable name of the router responsible for reaching this server +:routerPortName: The human-readable name of the port used by the router responsible for reaching this server +:status: The :term:`Status` of the server + + .. seealso:: :ref:`health-proto` + +:statusId: The integral, unique identifier of the status of this server + + .. seealso:: :ref:`health-proto` + +:tcpPort: The port on which this server listened for incoming TCP connections + + .. note:: This is typically thought of as synonymous with "HTTP port", as the port specified by ``httpsPort`` may also be used for incoming TCP connections. + +:type: The name of the :term:`Type` of this server +:typeId: The integral, unique identifier of the 'type' of this server +:updPending: A boolean value which, if ``true``, indicates that the server had updates of some kind pending, typically to be acted upon by Traffic Ops :term:`ORT` +:xmppId: An identifier to be used in XMPP communications with the server - in nearly all cases this will be the same as ``hostName`` +:xmppPasswd: The password used in XMPP communications with the server + .. code-block:: http :caption: Response Example From e3f9b93fcdd5419df39237fefdeb7197a6c77a63 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 19 May 2020 11:38:45 -0600 Subject: [PATCH 52/87] Added summary field descriptions --- docs/source/api/index.rst | 11 +++++++++++ docs/source/api/v3/servers.rst | 3 +++ 2 files changed, 14 insertions(+) diff --git a/docs/source/api/index.rst b/docs/source/api/index.rst index 783eb2a835..04f84d8b0e 100644 --- a/docs/source/api/index.rst +++ b/docs/source/api/index.rst @@ -102,6 +102,17 @@ Object ``undefined`` No ``response`` object is present in the response payload. Unless the format is otherwise noted, this means that there should be no field list in the "Response Structure" subsection. +Summary +------- +The top-level ``summary`` object is used to provide summary statistics about object collections. In general the use of ``summary`` is left to be defined by API endpoints (subject to some restrictions). When an endpoint uses the ``summary`` object, its fields will be explained in a subsection of the "Response Structure" named "Summary Fields". + +The following, reserved properties of ``summary`` are guaranteed to always have their herein-described meaning. + +.. _reserved-summary-fields: + +``count`` + ``count`` contains an unsigned integer that defines the total number of results that could possibly be returned given the non-pagination query parameters supplied by the client. + Using API Endpoints =================== #. Authenticate with valid Traffic Control user account credentials (the same used by Traffic Portal). diff --git a/docs/source/api/v3/servers.rst b/docs/source/api/v3/servers.rst index 4523952be3..90cf54a24d 100644 --- a/docs/source/api/v3/servers.rst +++ b/docs/source/api/v3/servers.rst @@ -216,6 +216,9 @@ Response Structure "count": 13 }} +Summary Fields +"""""""""""""" +The ``summary`` object returned by this method of this endpoint uses only the ``count`` :ref:`standard property `. ``POST`` ======== From 0749543825bbc08e7b0f8ff25604f0a5749c9e44 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 19 May 2020 11:53:55 -0600 Subject: [PATCH 53/87] Updated CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 572f3d01e4..df10d0f184 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). - Changed ORT Config Generation to be deterministic, which will prevent spurious diffs when nothing actually changed. - Changed the access logs in Traffic Ops to now show the route ID with every API endpoint call. The Route ID is appended to the end of the access log line. - With the addition of multiple server interfaces, interface data is constructed from IP Address/Gateway/Netmask (and their IPv6 counterparts) and Interface Name and Interface MTU fields on services. These **MUST** have proper, valid data before attempting to upgrade or the upgrade **WILL** fail. In particular IP fields need to be valid IP addresses/netmasks, and MTU must only be positive integers of at least 1280. +- The `/servers` and `/servers/{{ID}}}` API endpoints have been updated to use and reflect multi-interface servers. ### Deprecated - Deprecated the non-nullable `DeliveryService` Go struct and other structs that use it. `DeliveryServiceNullable` structs should be used instead. From 5e2db6ea238554f3166bb009b123d162705d9baf Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 20 May 2020 12:52:59 -0600 Subject: [PATCH 54/87] Proper capitalization of IP in ServerIPAddress --- lib/go-tc/servers.go | 12 ++++++------ .../traffic_ops_golang/server/servers_test.go | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index a10739ea9e..1f55dfe04f 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -81,8 +81,8 @@ type ServersV3DetailResponse struct { Alerts } -// ServerIpAddress is the data associated with a server's interface's IP address. -type ServerIpAddress struct { +// ServerIPAddress is the data associated with a server's interface's IP address. +type ServerIPAddress struct { Address string `json:"address" db:"address"` Gateway *string `json:"gateway" db:"gateway"` ServiceAddress bool `json:"serviceAddress" db:"service_address"` @@ -90,7 +90,7 @@ type ServerIpAddress struct { // ServerInterfaceInfo is the data associated with a server's interface. type ServerInterfaceInfo struct { - IPAddresses []ServerIpAddress `json:"ipAddresses" db:"ip_addresses"` + IPAddresses []ServerIPAddress `json:"ipAddresses" db:"ip_addresses"` MaxBandwidth *uint64 `json:"maxBandwidth" db:"max_bandwidth"` Monitor bool `json:"monitor" db:"monitor"` MTU *uint64 `json:"mtu" db:"mtu"` @@ -143,7 +143,7 @@ func (lid *LegacyInterfaceDetails) ToInterfaces(ipv4IsService, ipv6IsService boo } iface.Name = *lid.InterfaceName - var ips []ServerIpAddress + var ips []ServerIPAddress if lid.IPAddress != nil && *lid.IPAddress != "" { if lid.IPGateway != nil && *lid.IPGateway == "" { lid.IPGateway = nil @@ -159,7 +159,7 @@ func (lid *LegacyInterfaceDetails) ToInterfaces(ipv4IsService, ipv6IsService boo ipStr = fmt.Sprintf("%s/%d", ipStr, cidr) } - ips = append(ips, ServerIpAddress{ + ips = append(ips, ServerIPAddress{ Address: ipStr, Gateway: lid.IPGateway, ServiceAddress: ipv4IsService, @@ -170,7 +170,7 @@ func (lid *LegacyInterfaceDetails) ToInterfaces(ipv4IsService, ipv6IsService boo if lid.IP6Gateway != nil && *lid.IP6Gateway == "" { lid.IP6Gateway = nil } - ips = append(ips, ServerIpAddress{ + ips = append(ips, ServerIPAddress{ Address: *lid.IP6Address, Gateway: lid.IP6Gateway, ServiceAddress: ipv6IsService, diff --git a/traffic_ops/traffic_ops_golang/server/servers_test.go b/traffic_ops/traffic_ops_golang/server/servers_test.go index 22aafc1314..d9e7780450 100644 --- a/traffic_ops/traffic_ops_golang/server/servers_test.go +++ b/traffic_ops/traffic_ops_golang/server/servers_test.go @@ -440,8 +440,8 @@ func TestV3Validations(t *testing.T) { defer db.Close() goodInterface := tc.ServerInterfaceInfo{ - IPAddresses: []tc.ServerIpAddress{ - tc.ServerIpAddress{ + IPAddresses: []tc.ServerIPAddress{ + tc.ServerIPAddress{ Address: "127.0.0.1/32", Gateway: nil, ServiceAddress: true, @@ -524,7 +524,7 @@ func TestV3Validations(t *testing.T) { } badIface.MTU = nil - badIface.IPAddresses = []tc.ServerIpAddress{} + badIface.IPAddresses = []tc.ServerIPAddress{} testServer.Interfaces = []tc.ServerInterfaceInfo{badIface} mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) @@ -551,12 +551,12 @@ func TestV3Validations(t *testing.T) { } badIface = goodInterface - badIP := tc.ServerIpAddress{ + badIP := tc.ServerIPAddress{ Address: "127.0.0.1/32", Gateway: nil, ServiceAddress: false, } - badIface.IPAddresses = []tc.ServerIpAddress{badIP} + badIface.IPAddresses = []tc.ServerIPAddress{badIP} testServer.Interfaces = []tc.ServerInterfaceInfo{badIface} mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) @@ -582,7 +582,7 @@ func TestV3Validations(t *testing.T) { } badIface = goodInterface - badIface.IPAddresses = append(badIface.IPAddresses, tc.ServerIpAddress{ + badIface.IPAddresses = append(badIface.IPAddresses, tc.ServerIPAddress{ Address: "1.2.3.4/1", Gateway: nil, ServiceAddress: true, From caf0708ac3e9655e4b27b356135cbb98c6091e8e Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 20 May 2020 12:55:09 -0600 Subject: [PATCH 55/87] s/ServersResponsev3/ServersV3Response/g --- lib/go-tc/servers.go | 4 ++-- traffic_ops/client/server.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index 1f55dfe04f..80602af441 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -30,8 +30,8 @@ import ( * under the License. */ -// ServersResponsev3 is the format of a response to a GET request for /servers. -type ServersResponsev3 struct { +// ServersV3Response is the format of a response to a GET request for /servers. +type ServersV3Response struct { Response []ServerNullable `json:"response"` Summary struct { Count uint64 `json:"count"` diff --git a/traffic_ops/client/server.go b/traffic_ops/client/server.go index 2edd55d375..bf27399eb4 100644 --- a/traffic_ops/client/server.go +++ b/traffic_ops/client/server.go @@ -165,7 +165,7 @@ func (to *Session) GetServers(params *url.Values) ([]tc.ServerNullable, tc.Alert } defer resp.Body.Close() - var data tc.ServersResponsev3 + var data tc.ServersV3Response err = json.NewDecoder(resp.Body).Decode(&data) return data.Response, data.Alerts, data.Summary.Count, reqInf, err } From 49b85b35271e283a7c132e0ad93895d71e3e418a Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 20 May 2020 12:59:19 -0600 Subject: [PATCH 56/87] Unset netmask when not present --- lib/go-tc/servers.go | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index 80602af441..bc79c1de70 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -219,6 +219,7 @@ func InterfaceInfoToLegacyInterfaces(serverInterfaces []ServerInterfaceInfo) (Le } else { legacyDetails.IPAddress = util.StrPtr(parsedIp.String()) legacyDetails.IPGateway = gateway + legacyDetails.IPNetmask = new(string) } if intFace.MTU != nil { From a1c648215ba70ac3e248e6de9873f229d73fed78 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 20 May 2020 13:03:55 -0600 Subject: [PATCH 57/87] Short-circuit eval for interface-to-legacy conversion --- lib/go-tc/servers.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/go-tc/servers.go b/lib/go-tc/servers.go index bc79c1de70..0904a52590 100644 --- a/lib/go-tc/servers.go +++ b/lib/go-tc/servers.go @@ -227,6 +227,12 @@ func InterfaceInfoToLegacyInterfaces(serverInterfaces []ServerInterfaceInfo) (Le } legacyDetails.InterfaceName = &intFace.Name + + // we can jump out here since servers can only legally have one + // IPv4 and one IPv6 service address + if legacyDetails.IPAddress != nil && *legacyDetails.IPAddress != "" && legacyDetails.IP6Address != nil && *legacyDetails.IP6Address != "" { + return legacyDetails, nil + } } } From d26a299c0a2faa971491adcee5fbfe0f6bc5eecf Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 20 May 2020 14:06:11 -0600 Subject: [PATCH 58/87] Removed ip_allow.config, remap.config, and parent.config v1 generation routes --- .../ats/atsserver/chkconfig.go | 4 +- .../ats/atsserver/hostingdotconfig.go | 2 +- .../ats/atsserver/ipallowdotconfig.go | 184 ---- .../ats/atsserver/packages.go | 3 +- .../ats/atsserver/parentdotconfig.go | 814 ------------------ .../ats/atsserver/remapdotconfig.go | 95 -- .../ats/atsserver/unknown.go | 2 +- traffic_ops/traffic_ops_golang/ats/db.go | 32 + .../traffic_ops_golang/routing/routes.go | 4 - 9 files changed, 39 insertions(+), 1101 deletions(-) delete mode 100644 traffic_ops/traffic_ops_golang/ats/atsserver/ipallowdotconfig.go delete mode 100644 traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go delete mode 100644 traffic_ops/traffic_ops_golang/ats/atsserver/remapdotconfig.go diff --git a/traffic_ops/traffic_ops_golang/ats/atsserver/chkconfig.go b/traffic_ops/traffic_ops_golang/ats/atsserver/chkconfig.go index db58f24d8c..b445781faf 100644 --- a/traffic_ops/traffic_ops_golang/ats/atsserver/chkconfig.go +++ b/traffic_ops/traffic_ops_golang/ats/atsserver/chkconfig.go @@ -25,7 +25,9 @@ import ( "github.com/apache/trafficcontrol/lib/go-atscfg" "github.com/apache/trafficcontrol/lib/go-rfc" + "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" + "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/ats" ) func GetChkconfig(w http.ResponseWriter, r *http.Request) { @@ -45,7 +47,7 @@ func GetChkconfig(w http.ResponseWriter, r *http.Request) { return } - params, err := GetServerParams(inf.Tx.Tx, serverName, atscfg.ChkconfigParamConfigFile) + params, err := ats.GetServerParams(inf.Tx.Tx, serverName, atscfg.ChkconfigParamConfigFile) if err != nil { api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting server '"+string(serverName)+"' + chkconfig parameters: "+err.Error())) return diff --git a/traffic_ops/traffic_ops_golang/ats/atsserver/hostingdotconfig.go b/traffic_ops/traffic_ops_golang/ats/atsserver/hostingdotconfig.go index e3525be324..c441687afd 100644 --- a/traffic_ops/traffic_ops_golang/ats/atsserver/hostingdotconfig.go +++ b/traffic_ops/traffic_ops_golang/ats/atsserver/hostingdotconfig.go @@ -55,7 +55,7 @@ func GetHostingDotConfig(w http.ResponseWriter, r *http.Request) { return } - multiParams, err := GetServerParams(inf.Tx.Tx, serverName, atscfg.HostingConfigParamConfigFile) + multiParams, err := ats.GetServerParams(inf.Tx.Tx, serverName, atscfg.HostingConfigParamConfigFile) if err != nil { api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting server '"+string(serverName)+"' + hosting parameters: "+err.Error())) return diff --git a/traffic_ops/traffic_ops_golang/ats/atsserver/ipallowdotconfig.go b/traffic_ops/traffic_ops_golang/ats/atsserver/ipallowdotconfig.go deleted file mode 100644 index bab067edcf..0000000000 --- a/traffic_ops/traffic_ops_golang/ats/atsserver/ipallowdotconfig.go +++ /dev/null @@ -1,184 +0,0 @@ -package atsserver - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import ( - "database/sql" - "errors" - "fmt" - "net/http" - "strings" - - "github.com/apache/trafficcontrol/lib/go-atscfg" - "github.com/apache/trafficcontrol/lib/go-tc" - "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" - "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/ats" - - "github.com/lib/pq" -) - -func GetIPAllowDotConfig(w http.ResponseWriter, r *http.Request) { - inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"id-or-host"}, nil) - if userErr != nil || sysErr != nil { - api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr) - return - } - defer inf.Close() - - serverName, serverType, ok, err := GetServerNameAndTypeFromNameOrID(inf.Tx.Tx, inf.Params["id-or-host"]) - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting server name from ID: "+err.Error())) - return - } else if !ok { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusNotFound, errors.New("not found"), nil) - return - } - - toToolName, toURL, err := ats.GetToolNameAndURL(inf.Tx.Tx) - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting tool name and url: "+err.Error())) - return - } - - params, err := GetServerParams(inf.Tx.Tx, serverName, atscfg.IPAllowConfigFileName) - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting server '"+string(serverName)+"' + ip_allow parameters: "+err.Error())) - return - } - - childServers := map[tc.CacheName]atscfg.IPAllowServer{} - if strings.HasPrefix(string(serverType), tc.MidTypePrefix) { - if childServers, err = GetChildServers(inf.Tx.Tx, serverName); err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting child servers from mid '"+string(serverName)+"': "+err.Error())) - return - } - } - - txt := atscfg.MakeIPAllowDotConfig(serverName, serverType, toToolName, toURL, params, childServers) - - w.Header().Set("Content-Type", "text/plain") - w.Write([]byte(txt)) -} - -// GetChildServers returns the child servers of the given Mid serverName. This should not be called with an Edge server. -func GetChildServers(tx *sql.Tx, serverName tc.CacheName) (map[tc.CacheName]atscfg.IPAllowServer, error) { - qry := ` - SELECT - s.host_name, - 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 - ), - 'maxBandwidth', interface.max_bandwidth, - 'monitor', interface.monitor, - 'mtu', interface.mtu, - 'name', interface.name - ) - ) - FROM interface - WHERE interface.server = s.id - ) AS interfaces - FROM server s - JOIN type tp on tp.id = s.type - JOIN cachegroup cg on cg.id = s.cachegroup - WHERE - (tp.name = 'RASCAL' OR ( tp.name LIKE 'EDGE%') - AND cg.id IN ( - SELECT cg2.id - FROM server s2 - JOIN cachegroup cg2 ON (cg2.parent_cachegroup_id = s2.cachegroup OR cg2.secondary_parent_cachegroup_id = s2.cachegroup) - WHERE s2.host_name = $1 - ) - )` - rows, err := tx.Query(qry, serverName) - if err != nil { - return nil, errors.New("querying: " + err.Error()) - } - defer rows.Close() - - servers := map[tc.CacheName]atscfg.IPAllowServer{} - for rows.Next() { - var svName string - var ifaces []tc.ServerInterfaceInfo - if err := rows.Scan(&svName, pq.Array(&ifaces)); err != nil { - return nil, errors.New("scanning: " + err.Error()) - } - - var sv atscfg.IPAllowServer - legacyNet, err := tc.InterfaceInfoToLegacyInterfaces(ifaces) - if err != nil { - return nil, fmt.Errorf("Converting server '%s' interfaces to legacy info: %v", svName, err) - } - - if legacyNet.IPAddress != nil { - sv.IPAddress = *legacyNet.IPAddress - } - if legacyNet.IP6Address != nil { - sv.IP6Address = *legacyNet.IP6Address - } - - servers[tc.CacheName(svName)] = sv - } - return servers, nil -} - -func GetServerParams(tx *sql.Tx, serverName tc.CacheName, configFile string) (map[string][]string, error) { - qry := ` -SELECT - pa.name, - pa.value -FROM - parameter pa - JOIN profile_parameter pp ON pp.parameter = pa.id - JOIN profile pr ON pr.id = pp.profile - JOIN server s ON s.profile = pr.id -WHERE - s.host_name = $1 - AND pa.config_file = $2 -` - rows, err := tx.Query(qry, serverName, configFile) - if err != nil { - return nil, errors.New("querying: " + err.Error()) - } - defer rows.Close() - - params := map[string][]string{} - for rows.Next() { - name := "" - val := "" - if err := rows.Scan(&name, &val); err != nil { - return nil, errors.New("scanning: " + err.Error()) - } - params[name] = append(params[name], val) - } - return params, nil -} diff --git a/traffic_ops/traffic_ops_golang/ats/atsserver/packages.go b/traffic_ops/traffic_ops_golang/ats/atsserver/packages.go index 65b4025a48..7da7e4283b 100644 --- a/traffic_ops/traffic_ops_golang/ats/atsserver/packages.go +++ b/traffic_ops/traffic_ops_golang/ats/atsserver/packages.go @@ -26,6 +26,7 @@ import ( "github.com/apache/trafficcontrol/lib/go-atscfg" "github.com/apache/trafficcontrol/lib/go-rfc" "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" + "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/ats" ) func GetPackages(w http.ResponseWriter, r *http.Request) { @@ -45,7 +46,7 @@ func GetPackages(w http.ResponseWriter, r *http.Request) { return } - params, err := GetServerParams(inf.Tx.Tx, serverName, atscfg.PackagesParamConfigFile) + params, err := ats.GetServerParams(inf.Tx.Tx, serverName, atscfg.PackagesParamConfigFile) if err != nil { api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting server '"+string(serverName)+"' + package parameters: "+err.Error())) return diff --git a/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go b/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go deleted file mode 100644 index aa96698f7c..0000000000 --- a/traffic_ops/traffic_ops_golang/ats/atsserver/parentdotconfig.go +++ /dev/null @@ -1,814 +0,0 @@ -package atsserver - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import ( - "database/sql" - "errors" - "fmt" - "net/http" - "strconv" - "strings" - - "github.com/apache/trafficcontrol/lib/go-atscfg" - "github.com/apache/trafficcontrol/lib/go-log" - "github.com/apache/trafficcontrol/lib/go-tc" - "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" - "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/ats" - "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/server" - - "github.com/lib/pq" -) - -func GetParentDotConfig(w http.ResponseWriter, r *http.Request) { - inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"server-name-or-id"}, nil) - if userErr != nil || sysErr != nil { - api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr) - return - } - defer inf.Close() - - idOrHost := strings.TrimSuffix(inf.Params["server-name-or-id"], ".json") - hostName := "" - isHost := false - id, err := strconv.Atoi(idOrHost) - if err != nil { - isHost = true - hostName = idOrHost - } - - serverInfo, ok, err := &atscfg.ServerInfo{}, false, error(nil) - if isHost { - serverInfo, ok, err = ats.GetServerInfoByHost(inf.Tx.Tx, hostName) - } else { - serverInfo, ok, err = ats.GetServerInfoByID(inf.Tx.Tx, id) - } - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting server info: "+err.Error())) - return - } - if !ok { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusNotFound, errors.New("server not found"), nil) - return - } - - atsMajorVer, err := GetATSMajorVersion(inf.Tx.Tx, int(serverInfo.ProfileID)) - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting ATS major version: "+err.Error())) - return - } - - toolName, toURL, err := ats.GetToolNameAndURL(inf.Tx.Tx) - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting toolname and TO url parameters: "+err.Error())) - return - } - - parentConfigDSes := []atscfg.ParentConfigDSTopLevel{} - if serverInfo.IsTopLevelCache() { - parentConfigDSes, err = getParentConfigDSTopLevel(inf.Tx.Tx, serverInfo.CDN) - } else { - parentConfigDSes, err = getParentConfigDS(inf.Tx.Tx, serverInfo.ID) - } - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting server params: "+err.Error())) - return - } - - serverParams, err := getParentConfigServerProfileParams(inf.Tx.Tx, serverInfo.ID) - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting server params: "+err.Error())) - return - } - - parentInfos, err := getParentInfo(inf.Tx.Tx, serverInfo) - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting server parent info: "+err.Error())) - return - } - - text := atscfg.MakeParentDotConfig(serverInfo, atsMajorVer, toolName, toURL, parentConfigDSes, serverParams, parentInfos) - - w.Header().Set("Content-Type", "text/plain") - w.Write([]byte(text)) -} - -type ParentConfigDSSortByName []atscfg.ParentConfigDS - -func (s ParentConfigDSSortByName) Len() int { return len(([]atscfg.ParentConfigDS)(s)) } -func (s ParentConfigDSSortByName) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -func (s ParentConfigDSSortByName) Less(i, j int) bool { - // TODO make this match the Perl sort "foreach my $ds ( sort @{ $data->{dslist} } )" ? - return strings.Compare(string(s[i].Name), string(s[j].Name)) < 0 -} - -// GetATSMajorVersion returns the major version of the given profile's package trafficserver parameter. -// If no parameter exists, this does not return an error, but rather logs a warning and uses DefaultATSVersion. -func GetATSMajorVersion(tx *sql.Tx, serverProfileID int) (int, error) { - atsVersion, _, err := ats.GetProfileParamValue(tx, serverProfileID, "package", "trafficserver") - if err != nil { - return 0, errors.New("getting profile param value: " + err.Error()) - } - if len(atsVersion) == 0 { - atsVersion = atscfg.DefaultATSVersion - log.Warnln("Parameter package.trafficserver missing for profile " + strconv.Itoa(int(serverProfileID)) + ". Assuming version " + atsVersion) - } - return atscfg.GetATSMajorVersionFromATSVersion(atsVersion) -} - -type ParentConfigDS struct { - Name tc.DeliveryServiceName - QStringIgnore tc.QStringIgnore - OriginFQDN string - MultiSiteOrigin bool - OriginShield string - Type tc.DSType - - QStringHandling string -} - -type ParentConfigDSTopLevel struct { - ParentConfigDS - MSOAlgorithm string - MSOParentRetry string - MSOUnavailableServerRetryResponses string - MSOMaxSimpleRetries string - MSOMaxUnavailableServerRetries string -} - -func ParentConfigDSQuerySelect() string { - return ` -SELECT - ds.xml_id, - COALESCE(ds.qstring_ignore, ` + tc.QStringIgnoreUseInCacheKeyAndPassUp.String() + `), - COALESCE((SELECT o.protocol::text || '://' || o.fqdn || rtrim(concat(':', o.port::text), ':') - FROM origin o - WHERE o.deliveryservice = ds.id - AND o.is_primary), '') as org_server_fqdn, - COALESCE(ds.multi_site_origin, false), - COALESCE(ds.origin_shield, ''), - ARRAY(SELECT required_capability FROM deliveryservices_required_capability dsrc WHERE dsrc.deliveryservice_id = ds.id), - dt.name AS ds_type -` -} - -const ParentConfigDSQueryFromTopLevel = ` -FROM - deliveryservice ds - JOIN type as dt ON ds.type = dt.id - JOIN cdn ON cdn.id = ds.cdn_id -` // TODO Perl does 'JOIN deliveryservice_regex dsr ON dsr.deliveryservice = ds.id JOIN regex r ON dsr.regex = r.id JOIN type as rt ON r.type = rt.id' and orders by, but doesn't use; ensure it isn't necessary - -const ParentConfigDSQueryFrom = ParentConfigDSQueryFromTopLevel + ` -` - -const ParentConfigDSQueryOrder = ` -ORDER BY ds.id -` // TODO: perl does 'ORDER BY ds.id, rt.name, dsr.set_number' - but doesn't actually use regexes - ensure it isn't necessary - -const ParentConfigDSQueryWhere = ` -WHERE ds.id in (SELECT DISTINCT(dss.deliveryservice) FROM deliveryservice_server dss where dss.server = $1) -` - -const ParentConfigDSQueryWhereTopLevel = ` -WHERE - cdn.name = $1 - AND ds.id in (SELECT deliveryservice_server.deliveryservice FROM deliveryservice_server) - AND ds.active = true -` - -func ParentConfigDSQuery() string { - return ParentConfigDSQuerySelect() + - ParentConfigDSQueryFrom + - ParentConfigDSQueryWhere + - ParentConfigDSQueryOrder -} - -func ParentConfigDSQueryTopLevel() string { - return ParentConfigDSQuerySelect() + - ParentConfigDSQueryFromTopLevel + - ParentConfigDSQueryWhereTopLevel + - ParentConfigDSQueryOrder -} - -func getParentConfigDSTopLevel(tx *sql.Tx, cdnName tc.CDNName) ([]atscfg.ParentConfigDSTopLevel, error) { - dses, err := getParentConfigDSRaw(tx, ParentConfigDSQueryTopLevel(), []interface{}{cdnName}) - if err != nil { - return nil, errors.New("getting top level raw parent config ds: " + err.Error()) - } - topDSes := []atscfg.ParentConfigDSTopLevel{} - for _, ds := range dses { - topDSes = append(topDSes, ds) - } - - dsesWithParams, err := getParentConfigDSParamsTopLevel(tx, topDSes) - if err != nil { - return nil, errors.New("getting top level ds params: " + err.Error()) - } - - return dsesWithParams, nil -} - -func getParentConfigDS(tx *sql.Tx, serverID int) ([]atscfg.ParentConfigDSTopLevel, error) { - dses, err := getParentConfigDSRaw(tx, ParentConfigDSQuery(), []interface{}{serverID}) - if err != nil { - return nil, errors.New("getting raw parent config ds: " + err.Error()) - } - - dsesWithParams, err := getParentConfigDSParams(tx, dses) - if err != nil { - return nil, errors.New("getting ds params: " + err.Error()) - } - return dsesWithParams, nil -} - -func getParentConfigServerProfileParams(tx *sql.Tx, serverID int) (map[string]string, error) { - qry := ` -SELECT - pa.name, - pa.value -FROM - parameter pa - JOIN profile_parameter pp ON pp.parameter = pa.id - JOIN profile pr ON pr.id = pp.profile - JOIN server s on s.profile = pr.id -WHERE - s.id = $1 - AND pa.config_file = 'parent.config' - AND pa.name IN ( - '` + atscfg.ParentConfigParamQStringHandling + `', - '` + atscfg.ParentConfigParamAlgorithm + `', - '` + atscfg.ParentConfigParamQString + `' - ) -` - rows, err := tx.Query(qry, serverID) - if err != nil { - return nil, errors.New("querying: " + err.Error()) - } - defer rows.Close() - params := map[string]string{} - for rows.Next() { - name := "" - val := "" - if err := rows.Scan(&name, &val); err != nil { - return nil, errors.New("scanning: " + err.Error()) - } - params[name] = val - } - return params, nil -} - -// getParentConfigDSRaw returns a ParentConfigDSTopLevel, but all fields in addition to ParentConfigDS will be defaulted. This is because a ParentConfigDSTopLevel is returned to share the same interface, but it doesn't actually have top level data. -func getParentConfigDSRaw(tx *sql.Tx, qry string, qryParams []interface{}) ([]atscfg.ParentConfigDSTopLevel, error) { - rows, err := tx.Query(qry, qryParams...) - if err != nil { - return nil, errors.New("querying: " + err.Error()) - } - defer rows.Close() - dses := []atscfg.ParentConfigDSTopLevel{} - for rows.Next() { - d := atscfg.ParentConfigDS{RequiredCapabilities: map[atscfg.ServerCapability]struct{}{}} - requiredCaps := []string{} - if err := rows.Scan(&d.Name, &d.QStringIgnore, &d.OriginFQDN, &d.MultiSiteOrigin, &d.OriginShield, pq.Array(&requiredCaps), &d.Type); err != nil { - return nil, errors.New("scanning: " + err.Error()) - } - if d.OriginFQDN == "" { - // TODO skip ANY_MAP DSes? Why? Did Perl, I didn't see it? - log.Errorf("parent.config generation: getting parent config ds: server %+v has no origin, skipping!\n", d.Name) - continue - } - d.Type = tc.DSTypeFromString(string(d.Type)) - for _, cap := range requiredCaps { - - d.RequiredCapabilities[atscfg.ServerCapability(cap)] = struct{}{} - } - dses = append(dses, atscfg.ParentConfigDSTopLevel{ParentConfigDS: d}) - } - - return dses, nil -} - -func parentConfigDSesToNamesTopLevel(dses []atscfg.ParentConfigDSTopLevel) []string { - names := []string{} - for _, ds := range dses { - names = append(names, string(ds.Name)) - } - return names -} - -const ParentConfigDSParamsQuerySelect = ` -SELECT - ds.xml_id, - pa.name, - pa.value -` -const ParentConfigDSParamsQueryFrom = ` -FROM - parameter pa - JOIN profile_parameter pp ON pp.parameter = pa.id - JOIN profile pr ON pr.id = pp.profile - JOIN deliveryservice ds on ds.profile = pr.id -` -const ParentConfigDSParamsQueryWhere = ` -WHERE - pa.config_file = 'parent.config' - AND ds.xml_id = ANY($1) - AND pa.name IN ( - '` + atscfg.ParentConfigParamQStringHandling + `' - ) -` - -var ParentConfigDSParamsQueryWhereTopLevel = ` -WHERE - pa.config_file = 'parent.config' - AND ds.xml_id = ANY($1) - AND pa.name IN ( - '` + atscfg.ParentConfigParamQStringHandling + `', - '` + atscfg.ParentConfigParamMSOAlgorithm + `', - '` + atscfg.ParentConfigParamMSOParentRetry + `', - '` + atscfg.ParentConfigParamUnavailableServerRetryResponses + `', - '` + atscfg.ParentConfigParamMaxSimpleRetries + `', - '` + atscfg.ParentConfigParamMaxUnavailableServerRetries + `' - ) -` - -const ParentConfigDSParamsQuery = ParentConfigDSParamsQuerySelect + ParentConfigDSParamsQueryFrom + ParentConfigDSParamsQueryWhere - -var ParentConfigDSParamsQueryTopLevel = ParentConfigDSParamsQuerySelect + ParentConfigDSParamsQueryFrom + ParentConfigDSParamsQueryWhereTopLevel - -func getParentConfigDSParams(tx *sql.Tx, dses []atscfg.ParentConfigDSTopLevel) ([]atscfg.ParentConfigDSTopLevel, error) { - params, err := getParentConfigDSParamsRaw(tx, ParentConfigDSParamsQuery, parentConfigDSesToNamesTopLevel(dses)) - if err != nil { - return nil, err - } - for i, ds := range dses { - dsParams, ok := params[ds.Name] - if !ok { - continue - } - if v, ok := dsParams[atscfg.ParentConfigParamQStringHandling]; ok { - ds.QStringHandling = v - dses[i] = ds - } - } - return dses, nil -} - -func getParentConfigDSParamsTopLevel(tx *sql.Tx, dses []atscfg.ParentConfigDSTopLevel) ([]atscfg.ParentConfigDSTopLevel, error) { - params, err := getParentConfigDSParamsRaw(tx, ParentConfigDSParamsQueryTopLevel, parentConfigDSesToNamesTopLevel(dses)) - if err != nil { - return nil, err - } - for i, ds := range dses { - dsParams := params[ds.Name] // it's acceptable for this to not exist, if there are no params for the DS. If so, we still need to continue below, to set all the defaults. - if v, ok := dsParams[atscfg.ParentConfigParamQStringHandling]; ok { - ds.QStringHandling = v - } - if v, ok := dsParams[atscfg.ParentConfigParamMSOAlgorithm]; ok && strings.TrimSpace(v) != "" { - ds.MSOAlgorithm = v - } else { - ds.MSOAlgorithm = atscfg.ParentConfigDSParamDefaultMSOAlgorithm - } - if v, ok := dsParams[atscfg.ParentConfigParamMSOParentRetry]; ok { - ds.MSOParentRetry = v - } else { - ds.MSOParentRetry = atscfg.ParentConfigDSParamDefaultMSOParentRetry - } - if v, ok := dsParams[atscfg.ParentConfigParamUnavailableServerRetryResponses]; ok { - ds.MSOUnavailableServerRetryResponses = v - } else { - ds.MSOUnavailableServerRetryResponses = atscfg.ParentConfigDSParamDefaultMSOUnavailableServerRetryResponses - } - if v, ok := dsParams[atscfg.ParentConfigParamMaxSimpleRetries]; ok { - ds.MSOMaxSimpleRetries = v - } else { - ds.MSOMaxSimpleRetries = atscfg.ParentConfigDSParamDefaultMaxSimpleRetries - } - if v, ok := dsParams[atscfg.ParentConfigParamMaxUnavailableServerRetries]; ok { - ds.MSOMaxUnavailableServerRetries = v - } else { - ds.MSOMaxUnavailableServerRetries = atscfg.ParentConfigDSParamDefaultMaxUnavailableServerRetries - } - dses[i] = ds - } - return dses, nil -} - -func getParentConfigDSParamsRaw(tx *sql.Tx, qry string, dsNames []string) (map[tc.DeliveryServiceName]map[string]string, error) { - rows, err := tx.Query(qry, pq.Array(dsNames)) - if err != nil { - return nil, errors.New("querying: " + err.Error()) - } - defer rows.Close() - - params := map[tc.DeliveryServiceName]map[string]string{} - for rows.Next() { - dsName := tc.DeliveryServiceName("") - pName := "" - pVal := "" - if err := rows.Scan(&dsName, &pName, &pVal); err != nil { - return nil, errors.New("scanning: " + err.Error()) - } - if _, ok := params[dsName]; !ok { - params[dsName] = map[string]string{} - } - params[dsName][pName] = pVal - } - return params, nil -} - -func getParentInfo(tx *sql.Tx, server *atscfg.ServerInfo) (map[atscfg.OriginHost][]atscfg.ParentInfo, error) { - parentInfos := map[atscfg.OriginHost][]atscfg.ParentInfo{} - - serverDomain, ok, err := getCDNDomainByProfileID(tx, server.ProfileID) - if err != nil { - return nil, errors.New("getting CDN domain from profile ID: " + err.Error()) - } else if !ok || serverDomain == "" { - return parentInfos, nil // TODO warn? Perl doesn't. - } - - profileCaches, originServers, err := getServerParentCacheGroupProfiles(tx, server) - if err != nil { - return nil, errors.New("getting server parent cachegroup profiles: " + err.Error()) - } - - return atscfg.MakeParentInfo(server, serverDomain, profileCaches, originServers), nil -} - -// getServerParentCacheGroupProfiles gets the profile information for servers belonging to the parent cachegroup, and secondary parent cachegroup, of the cachegroup of each server. -func getServerParentCacheGroupProfiles(tx *sql.Tx, srv *atscfg.ServerInfo) (map[atscfg.ProfileID]atscfg.ProfileCache, map[atscfg.OriginHost][]atscfg.CGServer, error) { - // TODO make this more efficient - should be a single query - this was transliterated from Perl - it's extremely inefficient. - - profileCaches := map[atscfg.ProfileID]atscfg.ProfileCache{} - originServers := map[atscfg.OriginHost][]atscfg.CGServer{} // "deliveryServices" in Perl - - qry := "" - if srv.IsTopLevelCache() { - // multisite origins take all the org groups in to account - qry = ` -WITH parent_cachegroup_ids AS ( - SELECT cg.id as v - FROM cachegroup cg - JOIN type on type.id = cg.type - WHERE type.name = '` + tc.CacheGroupOriginTypeName + `' -) -` - } else { - qry = ` -WITH server_cachegroup_ids AS ( - SELECT cachegroup as v FROM server WHERE id = $2 -), -parent_cachegroup_ids AS ( - SELECT parent_cachegroup_id as v - FROM cachegroup WHERE id IN (SELECT v from server_cachegroup_ids) - UNION ALL - SELECT secondary_parent_cachegroup_id as v - FROM cachegroup WHERE id IN (SELECT v from server_cachegroup_ids) -) -` - } - - qry += ` -SELECT - s.id, - s.host_name, - s.tcp_port, - s.cachegroup, - s.status, - s.type, - s.profile, - s.cdn_id, - stype.name as type_name, - ARRAY(SELECT server_capability FROM server_server_capability ssc WHERE ssc.server = s.id), - s.domain_name -FROM - server s - JOIN type stype ON s.type = stype.id - JOIN cachegroup cg ON cg.id = s.cachegroup - JOIN cdn on s.cdn_id = cdn.id - JOIN status st ON st.id = s.status -WHERE - cg.id IN (SELECT v FROM parent_cachegroup_ids) - AND (stype.name = '` + tc.OriginTypeName + `' OR stype.name LIKE '` + tc.EdgeTypePrefix + `%' OR stype.name LIKE '` + tc.MidTypePrefix + `%') - AND (st.name = '` + string(tc.CacheStatusReported) + `' OR st.name = '` + string(tc.CacheStatusOnline) + `') - AND cdn.name = $1 -` - - // TODO move qry, qryParams to separate funcs/consts - qryParams := []interface{}{} - if srv.IsTopLevelCache() { - qryParams = []interface{}{srv.CDN} - } else { - qryParams = []interface{}{srv.CDN, srv.ID} - } - - rows, err := tx.Query(qry, qryParams...) - if err != nil { - return nil, nil, errors.New("querying: " + err.Error()) - } - defer rows.Close() - - cgServerIDs := []int{} - cgServers := map[int]atscfg.CGServer{} - for rows.Next() { - s := atscfg.CGServer{Capabilities: map[atscfg.ServerCapability]struct{}{}} - caps := []string{} - if err := rows.Scan(&s.ServerID, &s.ServerHost, &s.ServerPort, &s.CacheGroupID, &s.Status, &s.Type, &s.ProfileID, &s.CDN, &s.TypeName, pq.Array(&caps), &s.Domain); err != nil { - return nil, nil, errors.New("scanning: " + err.Error()) - } - - for _, cap := range caps { - s.Capabilities[atscfg.ServerCapability(cap)] = struct{}{} - } - cgServers[int(s.ServerID)] = s - cgServerIDs = append(cgServerIDs, int(s.ServerID)) - } - - interfaceRows, err := tx.Query(server.SelectInterfacesQuery, pq.Array(cgServerIDs)) - if err != nil { - return nil, nil, fmt.Errorf("querying for interfaces: %v", err) - } - defer interfaceRows.Close() - - for interfaceRows.Next() { - ifaces := []tc.ServerInterfaceInfo{} - var id int - if err := interfaceRows.Scan(pq.Array(&ifaces), &id); err != nil { - return nil, nil, fmt.Errorf("scanning server interfaces: %v", err) - } - - s, ok := cgServers[id] - if !ok { - log.Warnf("interfaces query returned interfaces for server #%d that was not in original query", id) - continue - } - - legacyNet, err := tc.InterfaceInfoToLegacyInterfaces(ifaces) - if err != nil { - return nil, nil, fmt.Errorf("Converting interfaces for server #%d to legacy: %v", id, err) - } - - if legacyNet.IPAddress != nil { - s.ServerIP = *legacyNet.IPAddress - } - - cgServers[id] = s - } - - serverCapabilities, err := ats.GetServerCapabilitiesByID(tx, cgServerIDs) - if err != nil { - return nil, nil, errors.New("getting server capabilities: " + err.Error()) - } - - cgServerDSes, err := getServerDSes(tx, cgServerIDs) - if err != nil { - return nil, nil, errors.New("getting cachegroup server deliveryservices: " + err.Error()) - } - - profileParams, err := getParentConfigServerCacheProfileParams(tx, cgServerIDs) // TODO change to take cg IDs directly? - if err != nil { - return nil, nil, errors.New("getting cachegroup server profile params: " + err.Error()) - } - - allDSMap := map[atscfg.DeliveryServiceID]struct{}{} - for _, dses := range cgServerDSes { - for _, ds := range dses { - allDSMap[ds] = struct{}{} - } - } - allDSes := []int{} - for ds, _ := range allDSMap { - allDSes = append(allDSes, int(ds)) - } - - dsRequiredCapabilities, err := ats.GetDeliveryServiceRequiredCapabilities(tx, allDSes) - if err != nil { - return nil, nil, errors.New("getting DS required capabilities: " + err.Error()) - } - - dsOrigins, err := getDSOrigins(tx, allDSes) - if err != nil { - return nil, nil, errors.New("getting deliveryservice origins: " + err.Error()) - } - - for _, cgServer := range cgServers { - if cgServer.TypeName == tc.OriginTypeName { - dses := cgServerDSes[cgServer.ServerID] - for _, ds := range dses { - orgURI := dsOrigins[ds] - if atscfg.HasRequiredCapabilities(serverCapabilities[int(cgServer.ServerID)], dsRequiredCapabilities[int(ds)]) { - originServers[atscfg.OriginHost(orgURI.Host)] = append(originServers[atscfg.OriginHost(orgURI.Host)], cgServer) - } - } - } else { - originServers[atscfg.DeliveryServicesAllParentsKey] = append(originServers[atscfg.DeliveryServicesAllParentsKey], cgServer) - } - - if _, profileCachesHasProfile := profileCaches[cgServer.ProfileID]; !profileCachesHasProfile { - defaultProfileCache := atscfg.DefaultProfileCache() - if profileCache, profileParamsHasProfile := profileParams[cgServer.ProfileID]; !profileParamsHasProfile { - log.Warnf("cachegroup has server with profile %+v but that profile has no parameters", cgServer.ProfileID) - profileCaches[cgServer.ProfileID] = defaultProfileCache - } else { - profileCaches[cgServer.ProfileID] = profileCache - } - } - } - return profileCaches, originServers, nil -} - -func getServerDSes(tx *sql.Tx, serverIDs []int) (map[atscfg.ServerID][]atscfg.DeliveryServiceID, error) { - sds := map[atscfg.ServerID][]atscfg.DeliveryServiceID{} - if len(serverIDs) == 0 { - return sds, nil - } - qry := ` -SELECT - dss.server, - dss.deliveryservice -FROM - deliveryservice_server dss -WHERE - dss.server = ANY($1) -` - rows, err := tx.Query(qry, pq.Array(serverIDs)) - if err != nil { - return nil, errors.New("querying: " + err.Error()) - } - defer rows.Close() - - for rows.Next() { - sID := atscfg.ServerID(0) - dsID := atscfg.DeliveryServiceID(0) - if err := rows.Scan(&sID, &dsID); err != nil { - return nil, errors.New("scanning: " + err.Error()) - } - sds[sID] = append(sds[sID], dsID) - } - return sds, nil -} - -func getDSOrigins(tx *sql.Tx, dsIDs []int) (map[atscfg.DeliveryServiceID]*atscfg.OriginURI, error) { - origins := map[atscfg.DeliveryServiceID]*atscfg.OriginURI{} - if len(dsIDs) == 0 { - return origins, nil - } - qry := ` -SELECT - ds.id, - o.protocol::text, - o.fqdn, - COALESCE(o.port::text, '') -FROM - deliveryservice ds - JOIN origin o ON o.deliveryservice = ds.id -WHERE - ds.id = ANY($1) - AND o.is_primary -` - rows, err := tx.Query(qry, pq.Array(dsIDs)) - if err != nil { - return nil, errors.New("querying: " + err.Error()) - } - defer rows.Close() - - for rows.Next() { - id := atscfg.DeliveryServiceID(0) - uri := &atscfg.OriginURI{} - if err := rows.Scan(&id, &uri.Scheme, &uri.Host, &uri.Port); err != nil { - return nil, errors.New("scanning: " + err.Error()) - } - if uri.Port == "" { - if uri.Scheme == "http" { - uri.Port = "80" - } else if uri.Scheme == "https" { - uri.Port = "443" - } else { - log.Warnf("parent.config generation: origin had unknown scheme '" + uri.Scheme + "' and no port; leaving port empty") - } - } - origins[id] = uri - } - return origins, nil -} - -func getParentConfigServerCacheProfileParams(tx *sql.Tx, serverIDs []int) (map[atscfg.ProfileID]atscfg.ProfileCache, error) { - qry := ` -SELECT - pr.id, - pa.name, - pa.value -FROM - parameter pa - JOIN profile_parameter pp ON pp.parameter = pa.id - JOIN profile pr ON pr.id = pp.profile - JOIN server s on s.profile = pr.id -WHERE - s.id = ANY($1) - AND pa.config_file = 'parent.config' - AND pa.name IN ( - '` + atscfg.ParentConfigCacheParamWeight + `', - '` + atscfg.ParentConfigCacheParamPort + `', - '` + atscfg.ParentConfigCacheParamUseIP + `', - '` + atscfg.ParentConfigCacheParamRank + `', - '` + atscfg.ParentConfigCacheParamNotAParent + `' - ) -` - rows, err := tx.Query(qry, pq.Array(serverIDs)) - if err != nil { - return nil, errors.New("querying: " + err.Error()) - } - defer rows.Close() - - type Param struct { - ProfileID atscfg.ProfileID - Name string - Val string - } - - params := []Param{} - for rows.Next() { - p := Param{} - if err := rows.Scan(&p.ProfileID, &p.Name, &p.Val); err != nil { - return nil, errors.New("scanning: " + err.Error()) - } - params = append(params, p) - } - - sParams := map[atscfg.ProfileID]atscfg.ProfileCache{} // TODO change to map of pointers? Does efficiency matter? - for _, param := range params { - profileCache, ok := sParams[param.ProfileID] - if !ok { - profileCache = atscfg.DefaultProfileCache() - } - switch param.Name { - case atscfg.ParentConfigCacheParamWeight: - // f, err := strconv.ParseFloat(param.Val, 64) - // if err != nil { - // log.Errorln("parent.config generation: weight param is not a float, skipping! : " + err.Error()) - // } else { - // profileCache.Weight = f - // } - // TODO validate float? - profileCache.Weight = param.Val - case atscfg.ParentConfigCacheParamPort: - i, err := strconv.ParseInt(param.Val, 10, 64) - if err != nil { - log.Errorln("parent.config generation: port param is not an integer, skipping! : " + err.Error()) - } else { - profileCache.Port = int(i) - } - case atscfg.ParentConfigCacheParamUseIP: - profileCache.UseIP = param.Val == "1" - case atscfg.ParentConfigCacheParamRank: - i, err := strconv.ParseInt(param.Val, 10, 64) - if err != nil { - log.Errorln("parent.config generation: rank param is not an integer, skipping! : " + err.Error()) - } else { - profileCache.Rank = int(i) - } - - case atscfg.ParentConfigCacheParamNotAParent: - profileCache.NotAParent = param.Val != "false" - default: - return nil, errors.New("query returned unexpected param: " + param.Name) - } - sParams[param.ProfileID] = profileCache - } - return sParams, nil -} - -type ParentConfigServerParams struct { - QString string - Algorithm string - QStringHandling bool -} - -func getCDNDomainByProfileID(tx *sql.Tx, profileID atscfg.ProfileID) (string, bool, error) { - qry := `SELECT domain_name from cdn where id = (select cdn from profile where id = $1)` - val := "" - if err := tx.QueryRow(qry, profileID).Scan(&val); err != nil { - if err == sql.ErrNoRows { - return "", false, nil - } - return "", false, errors.New("querying: " + err.Error()) - } - return val, true, nil -} diff --git a/traffic_ops/traffic_ops_golang/ats/atsserver/remapdotconfig.go b/traffic_ops/traffic_ops_golang/ats/atsserver/remapdotconfig.go deleted file mode 100644 index 81610c27ca..0000000000 --- a/traffic_ops/traffic_ops_golang/ats/atsserver/remapdotconfig.go +++ /dev/null @@ -1,95 +0,0 @@ -package atsserver - -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import ( - "errors" - "io" - "net/http" - - "github.com/apache/trafficcontrol/lib/go-atscfg" - "github.com/apache/trafficcontrol/lib/go-rfc" - "github.com/apache/trafficcontrol/lib/go-tc" - - "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/api" - "github.com/apache/trafficcontrol/traffic_ops/traffic_ops_golang/ats" -) - -func GetServerConfigRemap(w http.ResponseWriter, r *http.Request) { - inf, userErr, sysErr, errCode := api.NewInfo(r, []string{"server-name-or-id"}, nil) - if userErr != nil || sysErr != nil { - api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr) - return - } - defer inf.Close() - - serverName, userErr, sysErr, errCode := ats.GetServerNameFromNameOrID(inf.Tx.Tx, inf.Params["server-name-or-id"]) - if userErr != nil || sysErr != nil { - api.HandleErr(w, r, inf.Tx.Tx, errCode, userErr, sysErr) - return - } - - toToolName, toURL, err := ats.GetToolNameAndURL(inf.Tx.Tx) - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting tool name and url: "+err.Error())) - return - } - - atsMajorVersion, err := ats.GetATSMajorVersionFromServerName(inf.Tx.Tx, tc.CacheName(serverName)) - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting ATS major version: "+err.Error())) - return - } - - cacheURLConfigParams, err := ats.GetServerProfileParamData(inf.Tx.Tx, tc.CacheName(serverName), "cacheurl.config") - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting cacheurl.config params: "+err.Error())) - return - } - - serverInfo, ok, err := ats.GetServerInfoByHost(inf.Tx.Tx, serverName) - if !ok { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusNotFound, errors.New("server not found"), nil) - return - } - - remapDSData, err := ats.GetRemapDSData(inf.Tx.Tx, serverInfo) - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("Getting remap ds data: "+err.Error())) - return - } - - dsProfilesCacheKeyConfigParams, err := ats.GetProfilesParamData(inf.Tx.Tx, atscfg.DSProfileIDs(remapDSData), "cachekey.config") - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("Getting profiles param data for cachekey: "+err.Error())) - return - } - - serverPackageParamData, err := ats.GetServerParamData(inf.Tx.Tx, int(serverInfo.ProfileID), "package", serverInfo.HostName, serverInfo.DomainName) - if err != nil { - api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("Getting server package param data: "+err.Error())) - return - } - - txt := atscfg.MakeRemapDotConfig(tc.CacheName(serverName), toToolName, toURL, atsMajorVersion, cacheURLConfigParams, dsProfilesCacheKeyConfigParams, serverPackageParamData, serverInfo, remapDSData) - - w.Header().Set(rfc.ContentType, rfc.ContentTypeTextPlain) - io.WriteString(w, txt) -} diff --git a/traffic_ops/traffic_ops_golang/ats/atsserver/unknown.go b/traffic_ops/traffic_ops_golang/ats/atsserver/unknown.go index 0a578cf58d..e77582b2ea 100644 --- a/traffic_ops/traffic_ops_golang/ats/atsserver/unknown.go +++ b/traffic_ops/traffic_ops_golang/ats/atsserver/unknown.go @@ -52,7 +52,7 @@ func GetUnknown(w http.ResponseWriter, r *http.Request) { return } - params, err := GetServerParams(inf.Tx.Tx, serverName, inf.Params["file"]) + params, err := ats.GetServerParams(inf.Tx.Tx, serverName, inf.Params["file"]) if err != nil { api.HandleErr(w, r, inf.Tx.Tx, http.StatusInternalServerError, nil, errors.New("getting server '"+string(serverName)+"' + package parameters: "+err.Error())) return diff --git a/traffic_ops/traffic_ops_golang/ats/db.go b/traffic_ops/traffic_ops_golang/ats/db.go index 29a3405717..95062ef632 100644 --- a/traffic_ops/traffic_ops_golang/ats/db.go +++ b/traffic_ops/traffic_ops_golang/ats/db.go @@ -37,6 +37,38 @@ import ( // RemapDotConfigIncludeInactiveDeliveryServices is whether delivery services with 'active' false are included in the remap.config. const RemapDotConfigIncludeInactiveDeliveryServices = true +func GetServerParams(tx *sql.Tx, serverName tc.CacheName, configFile string) (map[string][]string, error) { + qry := ` + SELECT + pa.name, + pa.value + FROM + parameter pa + JOIN profile_parameter pp ON pp.parameter = pa.id + JOIN profile pr ON pr.id = pp.profile + JOIN server s ON s.profile = pr.id + WHERE + s.host_name = $1 + AND pa.config_file = $2 + ` + rows, err := tx.Query(qry, serverName, configFile) + if err != nil { + return nil, errors.New("querying: " + err.Error()) + } + defer rows.Close() + + params := map[string][]string{} + for rows.Next() { + name := "" + val := "" + if err := rows.Scan(&name, &val); err != nil { + return nil, errors.New("scanning: " + err.Error()) + } + params[name] = append(params[name], val) + } + return params, nil +} + // GetProfilesParamData returns a map[profileID][paramName]paramVal func GetProfilesParamData(tx *sql.Tx, profileIDs []int, configFile string) (map[int]map[string]string, error) { qry := ` diff --git a/traffic_ops/traffic_ops_golang/routing/routes.go b/traffic_ops/traffic_ops_golang/routing/routes.go index b00c51e957..4ab9f0a2a1 100644 --- a/traffic_ops/traffic_ops_golang/routing/routes.go +++ b/traffic_ops/traffic_ops_golang/routing/routes.go @@ -1251,11 +1251,7 @@ func Routes(d ServerData) ([]Route, []RawRoute, http.Handler, error) { {api.Version{1, 1}, http.MethodGet, `profiles/{profile-name-or-id}/configfiles/ats/volume\.config/?$`, atsprofile.GetVolume, auth.PrivLevelOperations, Authenticated, nil, 792704719, perlBypass}, {api.Version{1, 1}, http.MethodGet, `profiles/{profile-name-or-id}/configfiles/ats/{file}/?$`, atsprofile.GetUnknown, auth.PrivLevelOperations, Authenticated, nil, 1651257268, perlBypass}, - {api.Version{1, 1}, http.MethodGet, `servers/{server-name-or-id}/configfiles/ats/parent\.config/?(\.json)?$`, atsserver.GetParentDotConfig, auth.PrivLevelOperations, Authenticated, nil, 645056066, perlBypass}, - {api.Version{1, 1}, http.MethodGet, `servers/{server-name-or-id}/configfiles/ats/remap\.config/?(\.json)?$`, atsserver.GetServerConfigRemap, auth.PrivLevelOperations, Authenticated, nil, 2038454899, perlBypass}, - {api.Version{1, 1}, http.MethodGet, `servers/{id-or-host}/configfiles/ats/cache\.config/?(\.json)?$`, atsserver.GetCacheDotConfig, auth.PrivLevelOperations, Authenticated, nil, 34686861, perlBypass}, - {api.Version{1, 1}, http.MethodGet, `servers/{id-or-host}/configfiles/ats/ip_allow\.config/?(\.json)?$`, atsserver.GetIPAllowDotConfig, auth.PrivLevelOperations, Authenticated, nil, 724651786, perlBypass}, {api.Version{1, 1}, http.MethodGet, `servers/{id-or-host}/configfiles/ats/hosting\.config/?(\.json)?$`, atsserver.GetHostingDotConfig, auth.PrivLevelOperations, Authenticated, nil, 1387459113, perlBypass}, {api.Version{1, 1}, http.MethodGet, `servers/{id-or-host}/configfiles/ats/packages/?(\.json)?$`, atsserver.GetPackages, auth.PrivLevelOperations, Authenticated, nil, 245024839, perlBypass}, {api.Version{1, 1}, http.MethodGet, `servers/{id-or-host}/configfiles/ats/chkconfig/?(\.json)?$`, atsserver.GetChkconfig, auth.PrivLevelOperations, Authenticated, nil, 1012457987, perlBypass}, From 2831aae6ad9873e4a409adbf000f06f3455dfe8f Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 20 May 2020 14:06:54 -0600 Subject: [PATCH 59/87] Removed tests for now-non-existent routes --- traffic_ops/testing/api/v1/atsconfig_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/traffic_ops/testing/api/v1/atsconfig_test.go b/traffic_ops/testing/api/v1/atsconfig_test.go index 8abea7a60a..7a4f87df11 100644 --- a/traffic_ops/testing/api/v1/atsconfig_test.go +++ b/traffic_ops/testing/api/v1/atsconfig_test.go @@ -53,12 +53,9 @@ func GetTestATSConfigs(t *testing.T) { } serverConfigs := []string{ - "ip_allow.config", "hosting.config", "packages", "chkconfig", - "remap.config", - "parent.config", } for _, serverConfig := range serverConfigs { if _, _, err = TOSession.GetATSServerConfig(server.ID, serverConfig); err != nil { From 65beec4f0b8b07fa2353611b48e50538a7ae4821 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 20 May 2020 14:11:00 -0600 Subject: [PATCH 60/87] Added deprecation notices to docs --- docs/source/api/v1/servers_server_configfiles_ats.rst | 3 +++ docs/source/api/v1/servers_server_configfiles_ats_filename.rst | 3 +++ 2 files changed, 6 insertions(+) diff --git a/docs/source/api/v1/servers_server_configfiles_ats.rst b/docs/source/api/v1/servers_server_configfiles_ats.rst index 1bc98ea53c..2dc4f196c6 100644 --- a/docs/source/api/v1/servers_server_configfiles_ats.rst +++ b/docs/source/api/v1/servers_server_configfiles_ats.rst @@ -21,6 +21,9 @@ .. seealso:: The :ref:`to-api-v1-servers-server-configfiles-ats-filename`, :ref:`to-api-v1-cdns-cdn-configfiles-ats-filename`, and :ref:`to-api-v1-profiles-profile-configfiles-ats-filename` endpoints. +.. deprecated:: 1.4 + Using the API to retrieve generated configuration files for servers is deprecated, and unavailable in more recent API versions. Also, in ATC version 4.x and higher, it is not guaranteed that configuration files will be output correctly, or even successfully. Instead, configuration file generation is now the responsibility of :ref:`atstccfg`. + ``GET`` ======= Gets a list of the configuration files used by ``server`` diff --git a/docs/source/api/v1/servers_server_configfiles_ats_filename.rst b/docs/source/api/v1/servers_server_configfiles_ats_filename.rst index 69c8849f62..045c4405e9 100644 --- a/docs/source/api/v1/servers_server_configfiles_ats_filename.rst +++ b/docs/source/api/v1/servers_server_configfiles_ats_filename.rst @@ -21,6 +21,9 @@ .. seealso:: The :ref:`to-api-v1-servers-server-configfiles-ats` endpoint +.. deprecated:: 1.4 + Using the API to retrieve generated configuration files for servers is deprecated, and unavailable in more recent API versions. Also, in ATC version 4.x and higher, it is not guaranteed that configuration files will be output correctly, or even successfully. Instead, configuration file generation is now the responsibility of :ref:`atstccfg`. + ``GET`` ======= Returns the requested configuration file for download. From 1dc93333a2a093eabafb0b32dde507da67faf2e9 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 20 May 2020 14:38:50 -0600 Subject: [PATCH 61/87] Updated changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index df10d0f184..dcff4ca437 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ### Removed - Removed deprecated Traffic Ops Go Client methods. +- Configuration generation logic in the TO API (v1) for: + - `ip_allow.config` + - `parent.config` + - `remap.config` ## [4.1.0] - 2020-04-23 ### Added From 0ba3015e436de1898728175aab4d386cdd5268ed Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 20 May 2020 14:51:59 -0600 Subject: [PATCH 62/87] ACTUALLY removed tests for removed endpoints --- traffic_ops/testing/api/v1/atsconfig_test.go | 80 +++++++++ .../api/v1/ip_allow_dot_config_test.go | 125 -------------- .../testing/api/v1/parentdotconfig_test.go | 154 ------------------ .../testing/api/v1/remapdotconfig_test.go | 103 ------------ 4 files changed, 80 insertions(+), 382 deletions(-) delete mode 100644 traffic_ops/testing/api/v1/ip_allow_dot_config_test.go delete mode 100644 traffic_ops/testing/api/v1/parentdotconfig_test.go delete mode 100644 traffic_ops/testing/api/v1/remapdotconfig_test.go diff --git a/traffic_ops/testing/api/v1/atsconfig_test.go b/traffic_ops/testing/api/v1/atsconfig_test.go index 7a4f87df11..8fe6146cce 100644 --- a/traffic_ops/testing/api/v1/atsconfig_test.go +++ b/traffic_ops/testing/api/v1/atsconfig_test.go @@ -105,3 +105,83 @@ func GetTestATSConfigs(t *testing.T) { } } } + + + +func CreateTestDeliveryServiceServers(t *testing.T) { + dses, _, err := TOSession.GetDeliveryServices() + if err != nil { + t.Errorf("cannot GET DeliveryServices: %v", err) + } + if len(dses) < 1 { + t.Error("GET DeliveryServices returned no dses, must have at least 1 to test ds-servers") + } + + servers, _, err := TOSession.GetServers() + if err != nil { + t.Errorf("cannot GET Servers: %v", err) + } + if len(servers) < 1 { + t.Error("GET Servers returned no servers, must have at least 1 to test ds-servers") + } + + for _, ds := range dses { + serverIDs := make([]int, 0, len(servers)) + for _, server := range servers { + if server.Type == "EDGE" && server.CDNName == ds.CDNName { + serverIDs = append(serverIDs, server.ID) + } + } + + if len(serverIDs) > 0 { + _, err = TOSession.CreateDeliveryServiceServers(ds.ID, serverIDs, true) + if err != nil { + t.Errorf("POST delivery service servers: %v", err) + } + } + } +} + +// DeleteTestDeliveryServiceServersCreated deletes the dss assignments created by CreateTestDeliveryServiceServers. +func DeleteTestDeliveryServiceServersCreated(t *testing.T) { + // You gotta do this because TOSession.GetDeliveryServiceServers doesn't fetch the complete response....... + dssLen := len(testData.Servers) * len(testData.DeliveryServices) + dsServers, _, err := TOSession.GetDeliveryServiceServersN(dssLen) + if err != nil { + t.Fatalf("GET delivery service servers: %v", err) + } + + for _, dss := range dsServers.Response { + if dss.DeliveryService == nil { + t.Error("Found ds-to-server assignment with nil Delivery Service") + continue + } + if dss.Server == nil { + t.Error("Found ds-to-server assignment with nil Server") + continue + } + + _, _, err := TOSession.DeleteDeliveryServiceServer(*dss.DeliveryService, *dss.Server) + if err != nil { + t.Errorf("Failed to remove assignment of server #%d to DS #%d: %v", *dss.Server, *dss.DeliveryService, err) + } + } + + dsServers, _, err = TOSession.GetDeliveryServiceServersN(dssLen) + if err != nil { + t.Fatalf("GET delivery service servers: %v", err) + } + + for _, dss := range dsServers.Response { + if dss.DeliveryService == nil { + t.Error("Found ds-to-server assignment (after supposed deletion) with nil DeliveryService") + continue + } + if dss.Server == nil { + t.Error("Found ds-to-server assignment (after supposed deletion) with nil Server") + continue + } + + t.Errorf("Found ds-to-server assignment {DSID: %d, Server: %d} after deletion", *dss.DeliveryService, *dss.Server) + } +} diff --git a/traffic_ops/testing/api/v1/ip_allow_dot_config_test.go b/traffic_ops/testing/api/v1/ip_allow_dot_config_test.go deleted file mode 100644 index 61961a37b0..0000000000 --- a/traffic_ops/testing/api/v1/ip_allow_dot_config_test.go +++ /dev/null @@ -1,125 +0,0 @@ -package v1 - -/* - 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. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import ( - "fmt" - "net/url" - "strings" - "testing" - - "github.com/apache/trafficcontrol/lib/go-util" - - "github.com/apache/trafficcontrol/lib/go-tc" -) - -const ipAllow = "ip_allow.config" - -var ( - expectedRules = []string{ - "src_ip=127.0.0.1 action=ip_allow method=ALL\n", - "src_ip=::1 action=ip_allow method=ALL\n", - } - midExpectedRules = []string{ - "src_ip=10.0.0.0-10.255.255.255 action=ip_allow method=ALL\n", - "src_ip=172.16.0.0-172.31.255.255 action=ip_allow method=ALL\n", - "src_ip=192.168.0.0-192.168.255.255 action=ip_allow method=ALL\n", - "src_ip=::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff action=ip_deny method=ALL\n", - "src_ip=::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff action=ip_deny method=ALL\n", - } - edgeExpectedRules = []string{ - "src_ip=0.0.0.0-255.255.255.255 action=ip_deny method=PUSH|PURGE|DELETE\n", - "src_ip=::-ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff action=ip_deny method=PUSH|PURGE|DELETE\n", - } - rascalServerIP = "" - rascalRule = "src_ip=%v action=ip_allow method=ALL" -) - -func TestIPAllowDotConfig(t *testing.T) { - WithObjs(t, []TCObj{CDNs, Types, Tenants, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, DeliveryServices}, func() { - rascalServerIP = getServer(t, "RASCAL").IPAddress - // rascalRule = fmt.Sprintf("src_ip=%v action=ip_allow method=ALL", rascalServer.IPAddress) - GetTestIPAllowDotConfig(t) - GetTestIPAllowMidDotConfig(t) - }) -} - -func GetTestIPAllowDotConfig(t *testing.T) { - // Get edge server - s := getServer(t, "EDGE") - output, _, err := TOSession.GetATSServerConfig(s.ID, ipAllow) - if err != nil { - t.Fatalf("cannot GET server %v config %v: %v", s.HostName, ipAllow, err) - } - for _, r := range append(expectedRules, edgeExpectedRules...) { - if !strings.Contains(output, r) { - t.Errorf("expected rule %v not found in ip_allow config", r) - } - } - // Make sure edge does not contain rule for rascal server - exists, ipRange := getIPRule(output, rascalServerIP) - rascalRule := fmt.Sprintf(rascalRule, ipRange) - if exists && strings.Contains(output, rascalRule) { - t.Errorf("rascal IP was not supposed to be in an allowed rule: %v", rascalRule) - } -} - -func GetTestIPAllowMidDotConfig(t *testing.T) { - // Get mid server - s := getServer(t, "MID") - output, _, err := TOSession.GetATSServerConfig(s.ID, ipAllow) - if err != nil { - t.Errorf("cannot GET server %v config %v: %v", s.HostName, ipAllow, err) - } - for _, r := range append(expectedRules, midExpectedRules...) { - if !strings.Contains(output, r) { - t.Errorf("expected rule %v not found in ip_allow config", r) - } - } - - // Make sure mid contains an allowed rule that includes the rascal server - exists, ipRange := getIPRule(output, rascalServerIP) - rascalRule := fmt.Sprintf(rascalRule, ipRange) - if !(exists && strings.Contains(output, rascalRule)) { - t.Errorf("expected rascal to be include as allowed in mid ip allow config") - } -} - -func getServer(t *testing.T, serverType string) tc.ServerV1 { - v := url.Values{} - v.Add("type", serverType) - servers, _, err := TOSession.GetServersByType(v) - if err != nil { - t.Fatalf("cannot GET Server by type %v: %v", serverType, err) - } - if len(servers) == 0 { - t.Fatalf("cannot find any Servers by type %v", serverType) - } - return servers[0] -} - -// getIPRuleRange returns if the given IP is included in the set of rules and which ip range it is included in -func getIPRule(rules, ip string) (bool, string) { - for _, r := range strings.Split(rules, "\n")[1:] { - if !strings.Contains(r, "src_ip") { - continue - } - ipRange := r[7:strings.IndexAny(r, " ")] - if exists, _ := util.IP4InRange(ip, ipRange); exists { - return true, ipRange - } - } - return false, "" -} diff --git a/traffic_ops/testing/api/v1/parentdotconfig_test.go b/traffic_ops/testing/api/v1/parentdotconfig_test.go deleted file mode 100644 index b39a740362..0000000000 --- a/traffic_ops/testing/api/v1/parentdotconfig_test.go +++ /dev/null @@ -1,154 +0,0 @@ -package v1 - -/* - - 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. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import ( - "net/url" - "strconv" - "strings" - "testing" -) - -func TestParentDotConfig(t *testing.T) { - WithObjs(t, []TCObj{CDNs, Types, Tenants, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, DeliveryServices}, func() { - defer DeleteTestDeliveryServiceServersCreated(t) - CreateTestDeliveryServiceServers(t) - GetTestParentDotConfig(t) - }) -} - -func GetTestParentDotConfig(t *testing.T) { - dsServers, _, err := TOSession.GetDeliveryServiceServers() - if err != nil { - t.Fatalf("GET delivery service servers: %v", err) - } - if len(dsServers.Response) == 0 { - t.Fatal("GET delivery service servers: no servers found") - } - - dss := dsServers.Response[0] - - if dss.Server == nil { - t.Fatal("GET delivery service servers: returned nil server") - } - if dss.DeliveryService == nil { - t.Fatal("GET delivery service servers: returned nil ds") - } - - ds, _, err := TOSession.GetDeliveryService(strconv.Itoa(*dss.DeliveryService)) - if err != nil { - t.Fatalf("Getting ds %+v: %v", *dss.DeliveryService, err) - } - if ds == nil { - t.Fatalf("Getting ds %+v: got nil response", *dss.DeliveryService) - } - if ds.OrgServerFQDN == "" { - t.Fatalf("Getting ds %+v: got empty ds.OrgServerFQDN", *dss.DeliveryService) - } - - originURI, err := url.Parse(ds.OrgServerFQDN) - if err != nil { - t.Fatalf("Getting ds %+v: ds.OrgServerFQDN '%v' failed to parse as a URL: %v", *dss.DeliveryService, ds.OrgServerFQDN, err) - } - originHost := originURI.Hostname() - - parentDotConfig, _, err := TOSession.GetATSServerConfig(*dss.Server, "parent.config") - if err != nil { - t.Fatalf("Getting server %v config parent.config: %v", *dss.Server, err) - } - - if !strings.Contains(parentDotConfig, originHost) { - t.Errorf("expected: parent.config to contain delivery service origin FQDN '%v' host '%v', actual:\n'''\n%+v\n'''", ds.OrgServerFQDN, originHost, parentDotConfig) - } -} - -func CreateTestDeliveryServiceServers(t *testing.T) { - dses, _, err := TOSession.GetDeliveryServices() - if err != nil { - t.Errorf("cannot GET DeliveryServices: %v", err) - } - if len(dses) < 1 { - t.Error("GET DeliveryServices returned no dses, must have at least 1 to test ds-servers") - } - - servers, _, err := TOSession.GetServers() - if err != nil { - t.Errorf("cannot GET Servers: %v", err) - } - if len(servers) < 1 { - t.Error("GET Servers returned no servers, must have at least 1 to test ds-servers") - } - - for _, ds := range dses { - serverIDs := make([]int, 0, len(servers)) - for _, server := range servers { - if server.Type == "EDGE" && server.CDNName == ds.CDNName { - serverIDs = append(serverIDs, server.ID) - } - } - - if len(serverIDs) > 0 { - _, err = TOSession.CreateDeliveryServiceServers(ds.ID, serverIDs, true) - if err != nil { - t.Errorf("POST delivery service servers: %v", err) - } - } - } -} - -// DeleteTestDeliveryServiceServersCreated deletes the dss assignments created by CreateTestDeliveryServiceServers. -func DeleteTestDeliveryServiceServersCreated(t *testing.T) { - // You gotta do this because TOSession.GetDeliveryServiceServers doesn't fetch the complete response....... - dssLen := len(testData.Servers) * len(testData.DeliveryServices) - dsServers, _, err := TOSession.GetDeliveryServiceServersN(dssLen) - if err != nil { - t.Fatalf("GET delivery service servers: %v", err) - } - - for _, dss := range dsServers.Response { - if dss.DeliveryService == nil { - t.Error("Found ds-to-server assignment with nil Delivery Service") - continue - } - if dss.Server == nil { - t.Error("Found ds-to-server assignment with nil Server") - continue - } - - _, _, err := TOSession.DeleteDeliveryServiceServer(*dss.DeliveryService, *dss.Server) - if err != nil { - t.Errorf("Failed to remove assignment of server #%d to DS #%d: %v", *dss.Server, *dss.DeliveryService, err) - } - } - - dsServers, _, err = TOSession.GetDeliveryServiceServersN(dssLen) - if err != nil { - t.Fatalf("GET delivery service servers: %v", err) - } - - for _, dss := range dsServers.Response { - if dss.DeliveryService == nil { - t.Error("Found ds-to-server assignment (after supposed deletion) with nil DeliveryService") - continue - } - if dss.Server == nil { - t.Error("Found ds-to-server assignment (after supposed deletion) with nil Server") - continue - } - - t.Errorf("Found ds-to-server assignment {DSID: %d, Server: %d} after deletion", *dss.DeliveryService, *dss.Server) - } -} diff --git a/traffic_ops/testing/api/v1/remapdotconfig_test.go b/traffic_ops/testing/api/v1/remapdotconfig_test.go deleted file mode 100644 index 4e7e229c62..0000000000 --- a/traffic_ops/testing/api/v1/remapdotconfig_test.go +++ /dev/null @@ -1,103 +0,0 @@ -package v1 - -/* - - 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. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import ( - "net/url" - "strconv" - "strings" - "testing" - - "github.com/apache/trafficcontrol/lib/go-tc" -) - -func TestRemapDotConfig(t *testing.T) { - WithObjs(t, []TCObj{CDNs, Types, Tenants, Parameters, Profiles, Statuses, Divisions, Regions, PhysLocations, CacheGroups, Servers, DeliveryServices}, func() { - defer DeleteTestDeliveryServiceServersCreated(t) - CreateTestDeliveryServiceServers(t) - GetTestRemapDotConfig(t) - }) -} - -func GetTestRemapDotConfig(t *testing.T) { - dsServers, _, err := TOSession.GetDeliveryServiceServers() - if err != nil { - t.Fatalf("GET delivery service servers: %v", err) - } - if len(dsServers.Response) == 0 { - t.Fatal("GET delivery service servers: no servers found") - } - - var ds *tc.DeliveryService - var serverID int - for _, dsServer := range dsServers.Response { - if dsServer.Server == nil { - t.Error("Found DS-Server assignment with nil server") - continue - } - if dsServer.DeliveryService == nil { - t.Error("Found DS-Server assignment with nil Delivery Service") - continue - } - - serverID = *dsServer.Server - - ds, _, err = TOSession.GetDeliveryService(strconv.Itoa(*dsServer.DeliveryService)) - if err != nil { - t.Errorf("Getting ds %+v: %v", *dsServer.DeliveryService, err) - continue - } - if ds == nil { - t.Errorf("Getting ds %+v: got nil response", *dsServer.DeliveryService) - continue - } - if ds.OrgServerFQDN == "" { - t.Errorf("Getting ds %+v: got empty ds.OrgServerFQDN", *dsServer.DeliveryService) - continue - } - - if ds.Type != tc.DSTypeAnyMap { - break - } - } - - if ds == nil || ds.XMLID == "" { - t.Fatal("no Delivery Service found with assigned servers that isn't an ANY_MAP service, can't test remap.config") - } - - originURI, err := url.Parse(ds.OrgServerFQDN) - if err != nil { - t.Fatalf("Getting ds %+v: ds.OrgServerFQDN '%+v' failed to parse as a URL: %+v", ds.XMLID, ds.OrgServerFQDN, err) - } - originHost := originURI.Hostname() - - remapDotConfig, _, err := TOSession.GetATSServerConfig(serverID, "remap.config") - if err != nil { - t.Fatalf("Getting server %+v config remap.config: %v", serverID, err) - } - - if !strings.Contains(remapDotConfig, originHost) { - t.Errorf("expected: remap.config to contain delivery service origin FQDN '%v' host '%v', actual:\n'''\n%v\n'''", ds.OrgServerFQDN, originHost, remapDotConfig) - } - - remapDotConfigLines := strings.Split(remapDotConfig, "\n") - for i, line := range remapDotConfigLines { - line = strings.TrimSpace(line) - if len(line) > 0 && line[0] != '#' && !strings.HasPrefix(line, "map") { - t.Errorf("expected: remap.config line %v to start with 'map', actual: '%v'", i, line) - } - } -} From 42cc3cc55c2162032c5d95dec71f9032504d5a47 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 21 May 2020 10:40:31 -0600 Subject: [PATCH 63/87] Abstracted conditionals --- traffic_ops/client/server.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/traffic_ops/client/server.go b/traffic_ops/client/server.go index bf27399eb4..f5767f1aa7 100644 --- a/traffic_ops/client/server.go +++ b/traffic_ops/client/server.go @@ -34,6 +34,10 @@ const ( API_SERVER_ASSIGN_DELIVERY_SERVICES = API_SERVER_DELIVERY_SERVICES + "?replace=%t" ) +func needAndCanFetch(id *int, name *string) bool { + return (id == nil || *id == 0) && name != nil && *name != "" +} + // CreateServer creates a Server. func (to *Session) CreateServer(server tc.ServerNullable) (tc.Alerts, ReqInf, error) { @@ -41,7 +45,7 @@ func (to *Session) CreateServer(server tc.ServerNullable) (tc.Alerts, ReqInf, er var remoteAddr net.Addr reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} - if (server.CachegroupID == nil || *server.CachegroupID == 0) && server.Cachegroup != nil && *server.Cachegroup != "" { + if needAndCanFetch(server.CachegroupID, server.Cachegroup) { cg, _, err := to.GetCacheGroupNullableByName(*server.Cachegroup) if err != nil { return alerts, reqInf, fmt.Errorf("no cachegroup named %s: %v", *server.Cachegroup, err) @@ -54,7 +58,7 @@ func (to *Session) CreateServer(server tc.ServerNullable) (tc.Alerts, ReqInf, er } server.CachegroupID = cg[0].ID } - if (server.CDNID == nil || *server.CDNID == 0) && server.CDNName != nil && *server.CDNName != "" { + if needAndCanFetch(server.CDNID, server.CDNName) { c, _, err := to.GetCDNByName(*server.CDNName) if err != nil { return alerts, reqInf, fmt.Errorf("no CDN named %s: %v", *server.CDNName, err) @@ -64,7 +68,7 @@ func (to *Session) CreateServer(server tc.ServerNullable) (tc.Alerts, ReqInf, er } server.CDNID = &c[0].ID } - if (server.PhysLocationID == nil || *server.PhysLocationID == 0) && server.PhysLocation != nil && *server.PhysLocation != "" { + if needAndCanFetch(server.PhysLocationID, server.PhysLocation) { ph, _, err := to.GetPhysLocationByName(*server.PhysLocation) if err != nil { return alerts, reqInf, fmt.Errorf("no physlocation named %s: %v", *server.PhysLocation, err) @@ -74,7 +78,7 @@ func (to *Session) CreateServer(server tc.ServerNullable) (tc.Alerts, ReqInf, er } server.PhysLocationID = &ph[0].ID } - if (server.ProfileID == nil || *server.ProfileID == 0) && server.Profile != nil && *server.Profile != "" { + if needAndCanFetch(server.ProfileID, server.Profile) { pr, _, err := to.GetProfileByName(*server.Profile) if err != nil { return alerts, reqInf, fmt.Errorf("no profile named %s: %v", *server.Profile, err) @@ -84,7 +88,7 @@ func (to *Session) CreateServer(server tc.ServerNullable) (tc.Alerts, ReqInf, er } server.ProfileID = &pr[0].ID } - if (server.StatusID == nil || *server.StatusID == 0) && server.Status != nil && *server.Status != "" { + if needAndCanFetch(server.StatusID, server.Status) { st, _, err := to.GetStatusByName(*server.Status) if err != nil { return alerts, reqInf, fmt.Errorf("no status named %s: %v", *server.Status, err) From 67dcc25996b4e5a168beb5eadba30084ebbe48e5 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 21 May 2020 15:01:43 -0600 Subject: [PATCH 64/87] Removed unused queries --- .../traffic_ops_golang/server/servers.go | 32 ------------------- 1 file changed, 32 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index c19f989917..86424359a7 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -223,38 +223,6 @@ INSERT INTO server ( upd_pending ` -const insertInterfaceQuery = ` -INSERT INTO interface ( - max_bandwidth, - monitor, - mtu, - name, - server -) VALUES ( - $1, - $2, - $3, - $4, - $5 -) -` - -const insertIPQuery = ` -INSERT INTO ip_address ( - address, - gateway, - interface, - server, - service_address -) VALUES ( - $1, - $2, - $3, - $4, - $5 -) -` - const updateQuery = ` UPDATE server SET cachegroup=:cachegroup_id, From 1245e91c9b8dc32717e4e0d53053e325e7ea3d2a Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 21 May 2020 15:03:06 -0600 Subject: [PATCH 65/87] Removed unused validation function --- traffic_ops/traffic_ops_golang/server/servers.go | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 86424359a7..2d0a705689 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -412,17 +412,6 @@ func validateMTU(mtu interface{}) error { return nil } -func validateGateway(g interface{}) error { - if g == nil { - return nil - } - - if gtwy := net.ParseIP(*g.(*string)); gtwy == nil { - return errors.New("gateway not a valid IP address") - } - return nil -} - func validateV3(s tc.ServerNullable, tx *sql.Tx) (string, error) { if len(s.Interfaces) == 0 { From cf385f2970c6f946137818de7eb1450c919be2ee Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 26 May 2020 10:27:44 -0600 Subject: [PATCH 66/87] lowercase errors --- .../traffic_ops_golang/server/servers.go | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 2d0a705689..3180d9900c 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -509,7 +509,7 @@ func Read(w http.ResponseWriter, r *http.Request) { for _, server := range servers { legacyServer, err := server.ToServerV2() if err != nil { - api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Failed to convert servers to legacy format: %v", err)) + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("failed to convert servers to legacy format: %v", err)) return } legacyServers = append(legacyServers, legacyServer.ServerNullableV11) @@ -522,7 +522,7 @@ func Read(w http.ResponseWriter, r *http.Request) { for _, server := range servers { legacyServer, err := server.ToServerV2() if err != nil { - api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Failed to convert servers to legacy format: %v", err)) + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("failed to convert servers to legacy format: %v", err)) return } legacyServers = append(legacyServers, legacyServer) @@ -559,7 +559,7 @@ func ReadID(w http.ResponseWriter, r *http.Request) { for _, server := range servers { legacyServer, err := server.ToServerV2() if err != nil { - api.HandleDeprecatedErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Failed to convert servers to legacy format: %v", err), &alternative) + api.HandleDeprecatedErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("failed to convert servers to legacy format: %v", err), &alternative) return } legacyServers = append(legacyServers, legacyServer.ServerNullableV11) @@ -570,7 +570,7 @@ func ReadID(w http.ResponseWriter, r *http.Request) { func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ([]tc.ServerNullable, uint64, error, error, int) { var unfiltered uint64 if err := tx.QueryRow(unfilteredServersQuery).Scan(&unfiltered); err != nil { - return nil, 0, nil, fmt.Errorf("Failed to get servers count: %v", err), http.StatusInternalServerError + return nil, 0, nil, fmt.Errorf("failed to get servers count: %v", err), http.StatusInternalServerError } // Query Parameters to Database Query column mappings @@ -598,7 +598,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( } userErr, sysErr, _ := tenant.CheckID(tx.Tx, user, dsID) if userErr != nil || sysErr != nil { - return nil, unfiltered, errors.New("Forbidden"), sysErr, http.StatusForbidden + return nil, unfiltered, errors.New("forbidden"), sysErr, http.StatusForbidden } // only if dsId is part of params: add join on deliveryservice_server table queryAddition = "\nFULL OUTER JOIN deliveryservice_server dss ON dss.server = s.id\n" @@ -865,7 +865,7 @@ func Update(w http.ResponseWriter, r *http.Request) { server, err = newServer.ToServerV2() if err != nil { - api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Converting v3 server to v2 for update: %v", err)) + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("converting v3 server to v2 for update: %v", err)) return } server.InterfaceName = util.StrPtr(serviceInterface) @@ -884,7 +884,7 @@ func Update(w http.ResponseWriter, r *http.Request) { interfaces, err = server.LegacyInterfaceDetails.ToInterfaces(*server.IPIsService, *server.IP6IsService) if err != nil { - api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Converting server legacy interfaces to interface array: %v", err)) + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("converting server legacy interfaces to interface array: %v", err)) return } } else { @@ -902,7 +902,7 @@ func Update(w http.ResponseWriter, r *http.Request) { interfaces, err = legacyServer.LegacyInterfaceDetails.ToInterfaces(true, true) if err != nil { - api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("Converting server legacy interfaces to interface array: %v", err)) + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("converting server legacy interfaces to interface array: %v", err)) return } server = tc.ServerNullableV2{ @@ -1176,11 +1176,11 @@ func Delete(w http.ResponseWriter, r *http.Request) { } if len(servers) < 1 { - api.HandleErr(w, r, tx, http.StatusNotFound, fmt.Errorf("No server exists by id #%d", id), nil) + api.HandleErr(w, r, tx, http.StatusNotFound, fmt.Errorf("no server exists by id #%d", id), nil) return } if len(servers) > 1 { - api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("There are somehow two servers with id %d - cannot delete", id)) + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("there are somehow two servers with id %d - cannot delete", id)) return } From a05527b022b29d696e465f4ec01213574a408297 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 26 May 2020 10:57:02 -0600 Subject: [PATCH 67/87] Fixed servers tests --- .../traffic_ops_golang/server/detail.go | 4 ++-- .../traffic_ops_golang/server/detail_test.go | 2 +- .../traffic_ops_golang/server/servers_test.go | 18 ++++++------------ 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/detail.go b/traffic_ops/traffic_ops_golang/server/detail.go index 4faea0b411..27af5464ec 100644 --- a/traffic_ops/traffic_ops_golang/server/detail.go +++ b/traffic_ops/traffic_ops_golang/server/detail.go @@ -182,7 +182,7 @@ func getDetailServers(tx *sql.Tx, user *auth.CurrentUser, hostName string, physL } const JumboFrameBPS = 9000 q := ` -SELECT +SELECT cg.name AS cachegroup, cdn.name AS cdn_name, ARRAY(select deliveryservice from deliveryservice_server where server = s.id), @@ -202,7 +202,7 @@ SELECT SELECT ( json_build_object ( 'address', ip_address.address, 'gateway', ip_address.gateway, - 'service_address', ip_address.service_address + 'service_address', ip_address.serviceAddress )) FROM ip_address WHERE ip_address.interface = interface.name diff --git a/traffic_ops/traffic_ops_golang/server/detail_test.go b/traffic_ops/traffic_ops_golang/server/detail_test.go index 41fc1d5928..3b937f8d8d 100644 --- a/traffic_ops/traffic_ops_golang/server/detail_test.go +++ b/traffic_ops/traffic_ops_golang/server/detail_test.go @@ -82,7 +82,7 @@ func TestGetDetailServers(t *testing.T) { sd.ILOIPNetmask, sd.ILOPassword, sd.ILOUsername, - []byte(`{"{\"ipAddresses\" : [{\"address\" : \"127.0.0.0\", \"gateway\" : null, \"service_address\" : true}], \"max_bandwidth\" : null, \"monitor\" : true, \"mtu\" : 1500, \"name\" : \"eth0\"}"}`), + []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, diff --git a/traffic_ops/traffic_ops_golang/server/servers_test.go b/traffic_ops/traffic_ops_golang/server/servers_test.go index d9e7780450..d58a6bc83c 100644 --- a/traffic_ops/traffic_ops_golang/server/servers_test.go +++ b/traffic_ops/traffic_ops_golang/server/servers_test.go @@ -132,20 +132,14 @@ func TestUpdateServer(t *testing.T) { mock.ExpectQuery("SELECT").WillReturnRows(rows) mock.ExpectQuery("SELECT ARRAY").WillReturnRows(dsrows) - snv := tc.ServerNullableV11{ - CommonServerProperties: tc.CommonServerProperties{ - CDNID: &testServers[0].Server.CDNID, - FqdnTime: time.Time{}, - TypeID: &testServers[0].Server.TypeID, - }, - } - sn := tc.ServerNullableV2{ - ServerNullableV11: snv, - IPIsService: nil, - IP6IsService: nil, + s := tc.CommonServerProperties{ + CDNID: &testServers[0].Server.CDNID, + FqdnTime: time.Time{}, + TypeID: &testServers[0].Server.TypeID, + ID: &testServers[0].Server.ID, } - userErr, _, errCode := checkTypeChangeSafety(sn.CommonServerProperties, db.MustBegin()) + userErr, _, errCode := checkTypeChangeSafety(s, db.MustBegin()) if errCode != 409 { t.Errorf("Update servers: Expected error code of %v, but got %v", 409, errCode) } From 7457f2e96061c46a73058bff5f60509f3f976256 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 26 May 2020 10:57:19 -0600 Subject: [PATCH 68/87] go fmt --- traffic_ops/ort/atstccfg/toreqnew/toreqnew.go | 2 +- traffic_ops/testing/api/v1/atsconfig_test.go | 2 -- traffic_ops/traffic_ops_golang/server/servers.go | 1 - traffic_ops/traffic_ops_golang/server/servers_test.go | 8 ++++---- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go b/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go index 9d8f3a8ed7..56bf454634 100644 --- a/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go +++ b/traffic_ops/ort/atstccfg/toreqnew/toreqnew.go @@ -39,8 +39,8 @@ import ( "github.com/apache/trafficcontrol/lib/go-log" "github.com/apache/trafficcontrol/lib/go-tc" - toclient "github.com/apache/trafficcontrol/traffic_ops/v2-client" "github.com/apache/trafficcontrol/traffic_ops/ort/atstccfg/torequtil" + toclient "github.com/apache/trafficcontrol/traffic_ops/v2-client" ) type TOClient struct { diff --git a/traffic_ops/testing/api/v1/atsconfig_test.go b/traffic_ops/testing/api/v1/atsconfig_test.go index 8fe6146cce..98b96e91bd 100644 --- a/traffic_ops/testing/api/v1/atsconfig_test.go +++ b/traffic_ops/testing/api/v1/atsconfig_test.go @@ -106,8 +106,6 @@ func GetTestATSConfigs(t *testing.T) { } } - - func CreateTestDeliveryServiceServers(t *testing.T) { dses, _, err := TOSession.GetDeliveryServices() if err != nil { diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 3180d9900c..6aca884c25 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -848,7 +848,6 @@ func Update(w http.ResponseWriter, r *http.Request) { } defer inf.Close() - var server tc.ServerNullableV2 var interfaces []tc.ServerInterfaceInfo if inf.Version.Major >= 3 { diff --git a/traffic_ops/traffic_ops_golang/server/servers_test.go b/traffic_ops/traffic_ops_golang/server/servers_test.go index d58a6bc83c..30e6a554c4 100644 --- a/traffic_ops/traffic_ops_golang/server/servers_test.go +++ b/traffic_ops/traffic_ops_golang/server/servers_test.go @@ -133,10 +133,10 @@ func TestUpdateServer(t *testing.T) { mock.ExpectQuery("SELECT ARRAY").WillReturnRows(dsrows) s := tc.CommonServerProperties{ - CDNID: &testServers[0].Server.CDNID, - FqdnTime: time.Time{}, - TypeID: &testServers[0].Server.TypeID, - ID: &testServers[0].Server.ID, + CDNID: &testServers[0].Server.CDNID, + FqdnTime: time.Time{}, + TypeID: &testServers[0].Server.TypeID, + ID: &testServers[0].Server.ID, } userErr, _, errCode := checkTypeChangeSafety(s, db.MustBegin()) From d5c4922a0e20de17c02b8006ad4f9a17b383c798 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 26 May 2020 11:18:43 -0600 Subject: [PATCH 69/87] Fixed bad details query --- traffic_ops/traffic_ops_golang/server/detail.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traffic_ops/traffic_ops_golang/server/detail.go b/traffic_ops/traffic_ops_golang/server/detail.go index 27af5464ec..35586c7351 100644 --- a/traffic_ops/traffic_ops_golang/server/detail.go +++ b/traffic_ops/traffic_ops_golang/server/detail.go @@ -202,7 +202,7 @@ SELECT SELECT ( json_build_object ( 'address', ip_address.address, 'gateway', ip_address.gateway, - 'service_address', ip_address.serviceAddress + 'serviceAddress', ip_address.service_address )) FROM ip_address WHERE ip_address.interface = interface.name From 1855646ce290d8b411f45f97c047e7da2e20032f Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 26 May 2020 11:44:59 -0600 Subject: [PATCH 70/87] Fixed details integration test --- traffic_ops/testing/api/v3/servers_test.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/traffic_ops/testing/api/v3/servers_test.go b/traffic_ops/testing/api/v3/servers_test.go index 4656c44305..6c633e5cf7 100644 --- a/traffic_ops/testing/api/v3/servers_test.go +++ b/traffic_ops/testing/api/v3/servers_test.go @@ -66,7 +66,10 @@ func GetTestServers(t *testing.T) { func GetTestServersDetails(t *testing.T) { for _, server := range testData.Servers { - resp, _, err := TOSession.GetServerDetailsByHostName(server.HostName) + if server.HostName == nil { + t.Errorf("found server with nil hostname: %+v", server) + } + resp, _, err := TOSession.GetServerDetailsByHostName(*server.HostName) if err != nil { t.Errorf("cannot GET Server Details by name: %v - %v", err, resp) } From da8d9787d983c358494f7dc90d4d7fa7e37da5cd Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 26 May 2020 11:53:12 -0600 Subject: [PATCH 71/87] Fixed potential segfault --- traffic_ops/testing/api/v3/servers_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/traffic_ops/testing/api/v3/servers_test.go b/traffic_ops/testing/api/v3/servers_test.go index 6c633e5cf7..4faf24c849 100644 --- a/traffic_ops/testing/api/v3/servers_test.go +++ b/traffic_ops/testing/api/v3/servers_test.go @@ -68,6 +68,7 @@ func GetTestServersDetails(t *testing.T) { for _, server := range testData.Servers { if server.HostName == nil { t.Errorf("found server with nil hostname: %+v", server) + continue } resp, _, err := TOSession.GetServerDetailsByHostName(*server.HostName) if err != nil { From 948a1f30a906c3b88a0ee689e6bcfa620f1ac555 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 26 May 2020 16:06:25 -0600 Subject: [PATCH 72/87] Switched to returning response object --- traffic_ops/client/server.go | 30 +++++----- .../v3/cachegroupsdeliveryservices_test.go | 3 +- traffic_ops/testing/api/v3/crconfig_test.go | 5 +- ...veryservices_required_capabilities_test.go | 3 +- .../api/v3/deliveryserviceservers_test.go | 9 ++- traffic_ops/testing/api/v3/servers_test.go | 56 +++++++++--------- ...vers_to_deliveryservice_assignment_test.go | 18 +++--- .../api/v3/serverservercapability_test.go | 14 +++-- .../testing/api/v3/serverupdatestatus_test.go | 58 ++++++++++--------- 9 files changed, 103 insertions(+), 93 deletions(-) diff --git a/traffic_ops/client/server.go b/traffic_ops/client/server.go index f5767f1aa7..6c60c3d33f 100644 --- a/traffic_ops/client/server.go +++ b/traffic_ops/client/server.go @@ -151,27 +151,25 @@ func (to *Session) UpdateServerByID(id int, server tc.ServerNullable) (tc.Alerts // GetServers returns a list of Servers. // The 'params' parameter can be used to optionally pass URL "query string // parameters" in the request. -// It returns, in order, the requested servers, any Alerts the API returned, -// the returned summary.count value, a request info object, and any error that -// occurred. -func (to *Session) GetServers(params *url.Values) ([]tc.ServerNullable, tc.Alerts, uint64, ReqInf, error) { +// It returns, in order, the API response that Traffic Ops returned, a request +// info object, and any error that occurred. +func (to *Session) GetServers(params *url.Values) (tc.ServersV3Response, ReqInf, error) { route := API_SERVERS if params != nil { route += "?" + params.Encode() } - var alerts tc.Alerts + var data tc.ServersV3Response resp, remoteAddr, err := to.request(http.MethodGet, route, nil) reqInf := ReqInf{CacheHitStatus: CacheHitStatusMiss, RemoteAddr: remoteAddr} if err != nil { - return nil, alerts, 0, reqInf, err + return data, reqInf, err } defer resp.Body.Close() - var data tc.ServersV3Response err = json.NewDecoder(resp.Body).Decode(&data) - return data.Response, data.Alerts, data.Summary.Count, reqInf, err + return data, reqInf, err } // GetServerDetailsByHostName GETs Servers by the Server hostname. @@ -216,13 +214,13 @@ func (to *Session) GetServerFQDN(n string) (string, tc.Alerts, ReqInf, error) { params := url.Values{} params.Add("hostName", n) - servers, alerts, _, reqInf, err := to.GetServers(¶ms) + resp, reqInf, err := to.GetServers(¶ms) if err != nil { - return "", alerts, reqInf, err + return "", resp.Alerts, reqInf, err } var fdn string - for _, server := range servers { + for _, server := range resp.Response { if server.HostName != nil && server.DomainName != nil { fdn = fmt.Sprintf("%s.%s", *server.HostName, *server.DomainName) } @@ -232,19 +230,19 @@ func (to *Session) GetServerFQDN(n string) (string, tc.Alerts, ReqInf, error) { err = fmt.Errorf("No Server %s found", n) } - return fdn, alerts, reqInf, err + return fdn, resp.Alerts, reqInf, err } // GetServersShortNameSearch returns all of the Host Names of servers that // contain 'shortname'. func (to *Session) GetServersShortNameSearch(shortname string) ([]string, tc.Alerts, ReqInf, error) { var serverlst []string - servers, alerts, _, reqInf, err := to.GetServers(nil) + resp, reqInf, err := to.GetServers(nil) if err != nil { - return serverlst, alerts, reqInf, err + return serverlst, resp.Alerts, reqInf, err } - for _, server := range servers { + for _, server := range resp.Response { if server.HostName != nil && strings.Contains(*server.HostName, shortname) { serverlst = append(serverlst, *server.HostName) } @@ -254,7 +252,7 @@ func (to *Session) GetServersShortNameSearch(shortname string) ([]string, tc.Ale err = errors.New("No Servers Found") } - return serverlst, alerts, reqInf, err + return serverlst, resp.Alerts, reqInf, err } // AssignDeliveryServiceIDsToServerID assigns a set of Delivery Services to a diff --git a/traffic_ops/testing/api/v3/cachegroupsdeliveryservices_test.go b/traffic_ops/testing/api/v3/cachegroupsdeliveryservices_test.go index 1ae098db52..5af55dc6fc 100644 --- a/traffic_ops/testing/api/v3/cachegroupsdeliveryservices_test.go +++ b/traffic_ops/testing/api/v3/cachegroupsdeliveryservices_test.go @@ -107,10 +107,11 @@ func CreateTestCachegroupsDeliveryServices(t *testing.T) { params := url.Values{} for _, serverName := range resp.Response.ServerNames { params.Set("hostName", string(serverName)) - servers, _, _, _, err := TOSession.GetServers(¶ms) + resp, _, err := TOSession.GetServers(¶ms) if err != nil { t.Fatalf("getting server: %v", err) } + servers := resp.Response if len(servers) != 1 { t.Fatalf("getting servers: expected 1 got %v", len(servers)) } diff --git a/traffic_ops/testing/api/v3/crconfig_test.go b/traffic_ops/testing/api/v3/crconfig_test.go index b65edd63fb..5a88c338da 100644 --- a/traffic_ops/testing/api/v3/crconfig_test.go +++ b/traffic_ops/testing/api/v3/crconfig_test.go @@ -51,10 +51,11 @@ func UpdateTestCRConfigSnapshot(t *testing.T) { } // create an ANY_MAP DS assignment to verify that it doesn't show up in the CRConfig - servers, _, _, _, err := TOSession.GetServers(nil) + resp, _, err := TOSession.GetServers(nil) if err != nil { - t.Errorf("GetServers err expected nil, actual %+v", err) + t.Fatalf("GetServers err expected nil, actual %+v", err) } + servers := resp.Response serverID := 0 for _, server := range servers { if server.Type == "EDGE" && server.CDNName != nil && *server.CDNName == "cdn1" && server.ID != nil { diff --git a/traffic_ops/testing/api/v3/deliveryservices_required_capabilities_test.go b/traffic_ops/testing/api/v3/deliveryservices_required_capabilities_test.go index 36179d33f7..d478bf628d 100644 --- a/traffic_ops/testing/api/v3/deliveryservices_required_capabilities_test.go +++ b/traffic_ops/testing/api/v3/deliveryservices_required_capabilities_test.go @@ -185,10 +185,11 @@ func InvalidDeliveryServicesRequiredCapabilityAddition(t *testing.T) { // TODO: DON'T hard-code hostnames! params := url.Values{} params.Add("hostName", "atlanta-edge-01") - servers, _, _, _, err := TOSession.GetServers(¶ms) + resp, _, err := TOSession.GetServers(¶ms) if err != nil { t.Fatalf("cannot GET Server by hostname: %v", err) } + servers := resp.Response if len(servers) < 1 { t.Fatal("need at least one server to test invalid ds required capability assignment") } diff --git a/traffic_ops/testing/api/v3/deliveryserviceservers_test.go b/traffic_ops/testing/api/v3/deliveryserviceservers_test.go index d936cd327a..9e2c22ccab 100644 --- a/traffic_ops/testing/api/v3/deliveryserviceservers_test.go +++ b/traffic_ops/testing/api/v3/deliveryserviceservers_test.go @@ -123,10 +123,11 @@ func CreateTestDeliveryServiceServersWithRequiredCapabilities(t *testing.T) { t.Run(ctc.description, func(t *testing.T) { params := url.Values{} params.Add("hostName", ctc.serverName) - servers, _, _, _, err := TOSession.GetServers(¶ms) + resp, _, err := TOSession.GetServers(¶ms) if err != nil { t.Fatalf("cannot GET Server by hostname: %v", err) } + servers := resp.Response server := servers[0] if server.ID == nil { t.Fatalf("server %s had nil ID", ctc.serverName) @@ -170,10 +171,11 @@ func CreateTestMSODSServerWithReqCap(t *testing.T) { // TODO: DON'T hard-code server hostnames! params := url.Values{} params.Add("hostName", "denver-mso-org-01") - servers, _, _, _, err := TOSession.GetServers(¶ms) + resp, _, err := TOSession.GetServers(¶ms) if err != nil { t.Fatalf("GET server denver-mso-org-01: %v", err) } + servers := resp.Response if len(servers) != 1 { t.Fatal("expected 1 server with hostname denver-mso-org-01") } @@ -297,10 +299,11 @@ func getServersAndDSes(t *testing.T) ([]tc.DeliveryServiceNullable, []tc.ServerN t.Fatal("GET DeliveryServices returned no dses, must have at least 1 to test ds-servers") } - servers, _, _, _, err := TOSession.GetServers(nil) + resp, _, err := TOSession.GetServers(nil) if err != nil { t.Fatalf("cannot GET Servers: %v", err) } + servers := resp.Response if len(servers) < 1 { t.Fatal("GET Servers returned no dses, must have at least 1 to test ds-servers") } diff --git a/traffic_ops/testing/api/v3/servers_test.go b/traffic_ops/testing/api/v3/servers_test.go index 4faf24c849..0af24abb91 100644 --- a/traffic_ops/testing/api/v3/servers_test.go +++ b/traffic_ops/testing/api/v3/servers_test.go @@ -54,11 +54,11 @@ func GetTestServers(t *testing.T) { continue } params.Set("hostName", *server.HostName) - _, alerts, count, _, err := TOSession.GetServers(¶ms) + resp, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Errorf("cannot GET Server by name '%s': %v - %v", *server.HostName, err, alerts) - } else if count != serverCount { - t.Errorf("incorrect server count, expected: %d, actual: %d", serverCount, count) + t.Errorf("cannot GET Server by name '%s': %v - %v", *server.HostName, err, resp.Alerts) + } else if resp.Summary.Count != serverCount { + t.Errorf("incorrect server count, expected: %d, actual: %d", serverCount, resp.Summary.Count) } } } @@ -92,19 +92,19 @@ func UpdateTestServers(t *testing.T) { params.Add("hostName", hostName) // Retrieve the server by hostname so we can get the id for the Update - resp, alerts, _, _, err := TOSession.GetServers(¶ms) + resp, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Fatalf("cannot GET Server by hostname '%s': %v - %v", hostName, err, alerts) + t.Fatalf("cannot GET Server by hostname '%s': %v - %v", hostName, err, resp.Alerts) } - if len(resp) < 1 { + if len(resp.Response) < 1 { t.Fatalf("Expected at least one server to exist by hostname '%s'", hostName) } - if len(resp) > 1 { - t.Errorf("Expected exactly one server to exist by hostname '%s' - actual: %d", hostName, len(resp)) - t.Logf("Testing will proceed with server: %+v", resp[0]) + if len(resp.Response) > 1 { + t.Errorf("Expected exactly one server to exist by hostname '%s' - actual: %d", hostName, len(resp.Response)) + t.Logf("Testing will proceed with server: %+v", resp.Response[0]) } - remoteServer := resp[0] + remoteServer := resp.Response[0] if remoteServer.ID == nil { t.Fatalf("Got null ID for server '%s'", hostName) } @@ -124,25 +124,25 @@ func UpdateTestServers(t *testing.T) { remoteServer.Interfaces = infs remoteServer.Rack = &updatedServerRack - alerts, _, err = TOSession.UpdateServerByID(*remoteServer.ID, remoteServer) + alerts, _, err := TOSession.UpdateServerByID(*remoteServer.ID, remoteServer) if err != nil { t.Fatalf("cannot UPDATE Server by ID %d (hostname '%s'): %v - %v", *remoteServer.ID, hostName, err, alerts) } // Retrieve the server to check rack and interfaceName values were updated - resp, alerts, _, _, err = TOSession.GetServers(¶ms) + resp, _, err = TOSession.GetServers(¶ms) if err != nil { t.Errorf("cannot GET Server by ID: %v - %v", remoteServer.HostName, err) } - if len(resp) < 1 { + if len(resp.Response) < 1 { t.Fatalf("Expected at least one server to exist by hostname '%s'", hostName) } - if len(resp) > 1 { - t.Errorf("Expected exactly one server to exist by hostname '%s' - actual: %d", hostName, len(resp)) - t.Logf("Testing will proceed with server: %+v", resp[0]) + if len(resp.Response) > 1 { + t.Errorf("Expected exactly one server to exist by hostname '%s' - actual: %d", hostName, len(resp.Response)) + t.Logf("Testing will proceed with server: %+v", resp.Response[0]) } - respServer := resp[0] + respServer := resp.Response[0] infs = respServer.Interfaces found := false for _, inf = range infs { @@ -216,17 +216,17 @@ func DeleteTestServers(t *testing.T) { params.Set("hostName", *server.HostName) - resp, alerts, _, _, err := TOSession.GetServers(¶ms) + resp, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Errorf("cannot GET Server by hostname '%s': %v - %v", *server.HostName, err, alerts) + t.Errorf("cannot GET Server by hostname '%s': %v - %v", *server.HostName, err, resp.Alerts) continue } - if len(resp) > 0 { - if len(resp) > 1 { - t.Errorf("Expected exactly one server by hostname '%s' - actual: %d", *server.HostName, len(resp)) - t.Logf("Testing will proceed with server: %+v", resp[0]) + if len(resp.Response) > 0 { + if len(resp.Response) > 1 { + t.Errorf("Expected exactly one server by hostname '%s' - actual: %d", *server.HostName, len(resp.Response)) + t.Logf("Testing will proceed with server: %+v", resp.Response[0]) } - respServer := resp[0] + respServer := resp.Response[0] if respServer.ID == nil { t.Errorf("Server '%s' had nil ID", *server.HostName) @@ -240,11 +240,11 @@ func DeleteTestServers(t *testing.T) { } // Retrieve the Server to see if it got deleted - serv, alerts, _, _, err := TOSession.GetServers(¶ms) + resp, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Errorf("error deleting Server hostname '%s': %v - %v", *server.HostName, err, alerts) + t.Errorf("error deleting Server hostname '%s': %v - %v", *server.HostName, err, resp.Alerts) } - if len(serv) > 0 { + if len(resp.Response) > 0 { t.Errorf("expected Server hostname: %s to be deleted", *server.HostName) } } diff --git a/traffic_ops/testing/api/v3/servers_to_deliveryservice_assignment_test.go b/traffic_ops/testing/api/v3/servers_to_deliveryservice_assignment_test.go index 62d638edd0..1de5da55a8 100644 --- a/traffic_ops/testing/api/v3/servers_to_deliveryservice_assignment_test.go +++ b/traffic_ops/testing/api/v3/servers_to_deliveryservice_assignment_test.go @@ -43,13 +43,13 @@ func AssignTestDeliveryService(t *testing.T) { params := url.Values{} params.Add("hostName", *server.HostName) - rs, alerts, _, _, err := TOSession.GetServers(¶ms) + rs, _, err := TOSession.GetServers(¶ms) if err != nil { t.Fatalf("Failed to fetch server information: %v", err) - } else if len(rs) == 0 { + } else if len(rs.Response) == 0 { t.Fatalf("Failed to fetch server information: No results returned!") } - firstServer := rs[0] + firstServer := rs.Response[0] if firstServer.ID == nil { t.Fatalf("Server '%s' had nil ID", *server.HostName) } @@ -65,7 +65,7 @@ func AssignTestDeliveryService(t *testing.T) { if firstDS.ID == nil { t.Fatal("Fetch DS information returned unknown ID") } - alerts, _, err = TOSession.AssignDeliveryServiceIDsToServerID(*firstServer.ID, []int{*firstDS.ID}, true) + alerts, _, err := TOSession.AssignDeliveryServiceIDsToServerID(*firstServer.ID, []int{*firstDS.ID}, true) if err != nil { t.Errorf("Couldn't assign DS '%+v' to server '%+v': %v (alerts: %v)", firstDS, firstServer, err, alerts) } @@ -108,13 +108,13 @@ func AssignIncorrectTestDeliveryService(t *testing.T) { params := url.Values{} params.Add("hostName", hostname) - rs, alerts, _, _, err := TOSession.GetServers(¶ms) + rs, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Fatalf("Failed to fetch server information: %v - %v", err, alerts) - } else if len(rs) == 0 { + t.Fatalf("Failed to fetch server information: %v - %v", err, rs.Alerts) + } else if len(rs.Response) == 0 { t.Fatalf("Failed to fetch server information: No results returned!") } - server = &rs[0] + server = &rs.Response[0] if server.ID == nil { t.Fatalf("Server '%s' has nil ID", hostname) } @@ -130,7 +130,7 @@ func AssignIncorrectTestDeliveryService(t *testing.T) { if firstDS.ID == nil { t.Fatal("Fetch DS information returned unknown ID") } - alerts, _, err = TOSession.AssignDeliveryServiceIDsToServerID(*server.ID, []int{*firstDS.ID}, false) + alerts, _, err := TOSession.AssignDeliveryServiceIDsToServerID(*server.ID, []int{*firstDS.ID}, false) if err == nil { t.Errorf("Expected bad assignment to fail, but it didn't! (alerts: %v)", alerts) } diff --git a/traffic_ops/testing/api/v3/serverservercapability_test.go b/traffic_ops/testing/api/v3/serverservercapability_test.go index ff14413728..c2dbe7afb5 100644 --- a/traffic_ops/testing/api/v3/serverservercapability_test.go +++ b/traffic_ops/testing/api/v3/serverservercapability_test.go @@ -39,20 +39,21 @@ func CreateTestServerServerCapabilities(t *testing.T) { t.Fatalf("server-server-capability structure had nil server") } params.Set("hostName", *ssc.Server) - servResp, alerts, _, _, err := TOSession.GetServers(¶ms) + resp, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Fatalf("cannot GET Server by hostname '%s': %v - %v", *ssc.Server, err, alerts) + t.Fatalf("cannot GET Server by hostname '%s': %v - %v", *ssc.Server, err, resp.Alerts) } + servResp := resp.Response if len(servResp) != 1 { t.Fatalf("cannot GET Server by hostname: %v. Response did not include record.", *ssc.Server) } server := servResp[0] ssc.ServerID = server.ID - resp, _, err := TOSession.CreateServerServerCapability(ssc) + createResp, _, err := TOSession.CreateServerServerCapability(ssc) if err != nil { t.Errorf("could not POST the server capability %v to server %v: %v", *ssc.ServerCapability, *ssc.Server, err) } - t.Log("Response: ", *ssc.Server, " ", resp) + t.Log("Response: ", *ssc.Server, " ", createResp) } // Invalid POSTs @@ -106,10 +107,11 @@ func CreateTestServerServerCapabilities(t *testing.T) { // Attempt to assign a server capability to a non MID/EDGE server // TODO: DON'T hard-code server hostnames! params.Set("hostName", "riak") - servers, alerts, _, _, err := TOSession.GetServers(¶ms) + resp, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Fatalf("cannot GET Server by hostname 'riak': %v - %v", err, alerts) + t.Fatalf("cannot GET Server by hostname 'riak': %v - %v", err, resp.Alerts) } + servers := resp.Response if len(servers) < 1 { t.Fatal("need at least one server to test invalid server type assignment") } diff --git a/traffic_ops/testing/api/v3/serverupdatestatus_test.go b/traffic_ops/testing/api/v3/serverupdatestatus_test.go index 1c8aa50ffe..538226043e 100644 --- a/traffic_ops/testing/api/v3/serverupdatestatus_test.go +++ b/traffic_ops/testing/api/v3/serverupdatestatus_test.go @@ -59,18 +59,18 @@ func TestServerUpdateStatus(t *testing.T) { }, } { params.Set("hostName", s.name) - resp, alerts, _, _, err := TOSession.GetServers(¶ms) + resp, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Errorf("cannot GET Server by hostname '%s': %v - %v", s.name, err, alerts) + t.Errorf("cannot GET Server by hostname '%s': %v - %v", s.name, err, resp.Alerts) } - if len(resp) < 1 { + if len(resp.Response) < 1 { t.Fatalf("Expected a server named '%s' to exist", s.name) } - if len(resp) > 1 { - t.Errorf("Expected exactly one server named '%s' to exist - actual: %d", s.name, len(resp)) - t.Logf("Testing will proceed with server: %+v", resp[0]) + if len(resp.Response) > 1 { + 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[0] + *s.server = resp.Response[0] if s.server.ID == nil { t.Fatalf("server '%s' was returned with nil ID", s.name) } @@ -208,18 +208,18 @@ func TestServerQueueUpdate(t *testing.T) { var s tc.ServerNullable params := url.Values{} params.Add("hostName", serverName) - resp, alerts, _, _, err := TOSession.GetServers(¶ms) + resp, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Fatalf("failed to GET Server by hostname '%s': %v - %v", serverName, err, alerts) + t.Fatalf("failed to GET Server by hostname '%s': %v - %v", serverName, err, resp.Alerts) } - if len(resp) < 1 { + if len(resp.Response) < 1 { t.Fatalf("Expected a server named '%s' to exist", serverName) } - if len(resp) > 1 { + if len(resp.Response) > 1 { t.Errorf("Expected exactly one server named '%s' to exist", serverName) - t.Logf("Testing will proceed with server: %+v", resp[0]) + t.Logf("Testing will proceed with server: %+v", resp.Response[0]) } - s = resp[0] + s = resp.Response[0] // assert that servers don't have updates pending if s.UpdPending == nil { @@ -248,18 +248,18 @@ func TestServerQueueUpdate(t *testing.T) { } // assert that the server has updates queued - resp, alerts, _, _, err = TOSession.GetServers(¶ms) + resp, _, err = TOSession.GetServers(¶ms) if err != nil { - t.Fatalf("failed to GET Server by hostname '%s': %v - %v", serverName, err, alerts) + t.Fatalf("failed to GET Server by hostname '%s': %v - %v", serverName, err, resp.Alerts) } - if len(resp) < 1 { + if len(resp.Response) < 1 { t.Fatalf("Expected a server named '%s' to exist", serverName) } - if len(resp) > 1 { + if len(resp.Response) > 1 { t.Errorf("Expected exactly one server named '%s' to exist", serverName) - t.Logf("Testing will proceed with server: %+v", resp[0]) + t.Logf("Testing will proceed with server: %+v", resp.Response[0]) } - s = resp[0] + s = resp.Response[0] if s.UpdPending == nil { t.Fatalf("Server '%s' had null (or missing) updPending property", serverName) } @@ -308,13 +308,15 @@ func TestSetServerUpdateStatuses(t *testing.T) { params := url.Values{} params.Add("hostName", *testServer.HostName) testVals := func(queue *bool, reval *bool) { - existingServer, alerts, _, _, err := TOSession.GetServers(¶ms) + resp, _, err := TOSession.GetServers(¶ms) if err != nil { - t.Errorf("cannot GET Server by name '%s': %v - %v", *testServer.HostName, err, alerts) - } else if len(existingServer) != 1 { - t.Fatalf("GET Server expected 1, actual %v", len(existingServer)) + t.Errorf("cannot GET Server by name '%s': %v - %v", *testServer.HostName, err, resp.Alerts) + } else if len(resp.Response) != 1 { + t.Fatalf("GET Server expected 1, actual %v", len(resp.Response)) } + existingServer := resp.Response + if existingServer[0].UpdPending == nil { t.Fatalf("Server '%s' had nil UpdPending before update status change", *testServer.HostName) } @@ -326,13 +328,15 @@ func TestSetServerUpdateStatuses(t *testing.T) { t.Fatalf("UpdateServerStatuses error expected: nil, actual: %v", err) } - newServer, alerts, _, _, err := TOSession.GetServers(¶ms) + resp, _, err = TOSession.GetServers(¶ms) if err != nil { - t.Errorf("cannot GET Server by name '%s': %v - %v", *testServer.HostName, err, alerts) - } else if len(newServer) != 1 { - t.Fatalf("GET Server expected 1, actual %v", len(newServer)) + t.Errorf("cannot GET Server by name '%s': %v - %v", *testServer.HostName, err, resp.Alerts) + } else if len(resp.Response) != 1 { + t.Fatalf("GET Server expected 1, actual %v", len(resp.Response)) } + newServer := resp.Response + if newServer[0].UpdPending == nil { t.Fatalf("Server '%s' had nil UpdPending after update status change", *testServer.HostName) } From e6ba2fb8b757f8bdc6a7f1220e35c9a015ca0760 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 1 Jun 2020 09:35:47 -0600 Subject: [PATCH 73/87] Fixed max bandwidth case issue --- traffic_ops/traffic_ops_golang/server/detail.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traffic_ops/traffic_ops_golang/server/detail.go b/traffic_ops/traffic_ops_golang/server/detail.go index 35586c7351..f0dfd26c05 100644 --- a/traffic_ops/traffic_ops_golang/server/detail.go +++ b/traffic_ops/traffic_ops_golang/server/detail.go @@ -208,7 +208,7 @@ SELECT WHERE ip_address.interface = interface.name AND ip_address.server = s.id ), - 'max_bandwidth', interface.max_bandwidth, + 'maxBandwidth', interface.max_bandwidth, 'monitor', interface.monitor, 'mtu', COALESCE (interface.mtu, 9000), 'name', interface.name From 83f3df363ea5996c6f9930a1c4a3ca6d6a5e9eea Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 1 Jun 2020 10:43:06 -0600 Subject: [PATCH 74/87] Pulled interfaces array into shared constant --- .../traffic_ops_golang/server/detail.go | 137 ++++++++---------- .../traffic_ops_golang/server/servers.go | 11 +- 2 files changed, 65 insertions(+), 83 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/detail.go b/traffic_ops/traffic_ops_golang/server/detail.go index f0dfd26c05..a80f83c1e2 100644 --- a/traffic_ops/traffic_ops_golang/server/detail.go +++ b/traffic_ops/traffic_ops_golang/server/detail.go @@ -141,40 +141,40 @@ func GetDetailParamHandler(w http.ResponseWriter, r *http.Request) { func getDetailServers(tx *sql.Tx, user *auth.CurrentUser, hostName string, physLocationID int, orderBy string, limit int, reqVersion api.Version) ([]tc.ServerDetailV30, error) { allowedOrderByCols := map[string]string{ "": "", - "cachegroup": "s.cachegroup", + "cachegroup": "server.cachegroup", "cdn_name": "cdn.name", - "domain_name": "s.domain_name", - "guid": "s.guid", - "host_name": "s.host_name", - "https_port": "s.https_port", - "id": "s.id", - "ilo_ip_address": "s.ilo_ip_address", - "ilo_ip_gateway": "s.ilo_ip_gateway", - "ilo_ip_netmask": "s.ilo_ip_netmask", - "ilo_password": "s.ilo_password", - "ilo_username": "s.ilo_username", + "domain_name": "server.domain_name", + "guid": "server.guid", + "host_name": "server.host_name", + "https_port": "server.https_port", + "id": "server.id", + "ilo_ip_address": "server.ilo_ip_address", + "ilo_ip_gateway": "server.ilo_ip_gateway", + "ilo_ip_netmask": "server.ilo_ip_netmask", + "ilo_password": "server.ilo_password", + "ilo_username": "server.ilo_username", "interface_mtu": "interface_mtu", - "interface_name": "s.interface_name", - "ip6_address": "s.ip6_address", - "ip6_gateway": "s.ip6_gateway", - "ip_address": "s.ip_address", - "ip_gateway": "s.ip_gateway", - "ip_netmask": "s.ip_netmask", - "mgmt_ip_address": "s.mgmt_ip_address", - "mgmt_ip_gateway": "s.mgmt_ip_gateway", - "mgmt_ip_netmask": "s.mgmt_ip_netmask", - "offline_reason": "s.offline_reason", + "interface_name": "server.interface_name", + "ip6_address": "server.ip6_address", + "ip6_gateway": "server.ip6_gateway", + "ip_address": "server.ip_address", + "ip_gateway": "server.ip_gateway", + "ip_netmask": "server.ip_netmask", + "mgmt_ip_address": "server.mgmt_ip_address", + "mgmt_ip_gateway": "server.mgmt_ip_gateway", + "mgmt_ip_netmask": "server.mgmt_ip_netmask", + "offline_reason": "server.offline_reason", "phys_location": "pl.name", "profile": "p.name", "profile_desc": "p.description", - "rack": "s.rack", - "router_host_name": "s.router_host_name", - "router_port_name": "s.router_port_name", + "rack": "server.rack", + "router_host_name": "server.router_host_name", + "router_port_name": "server.router_port_name", "status": "st.name", - "tcp_port": "s.tcp_port", + "tcp_port": "server.tcp_port", "server_type": "t.name", - "xmpp_id": "s.xmpp_id", - "xmpp_passwd": "s.xmpp_passwd", + "xmpp_id": "server.xmpp_id", + "xmpp_passwd": "server.xmpp_passwd", } orderBy, ok := allowedOrderByCols[orderBy] if !ok { @@ -185,59 +185,40 @@ func getDetailServers(tx *sql.Tx, user *auth.CurrentUser, hostName string, physL SELECT cg.name AS cachegroup, cdn.name AS cdn_name, - ARRAY(select deliveryservice from deliveryservice_server where server = s.id), - s.domain_name, - s.guid, - s.host_name, - s.https_port, - s.id, - s.ilo_ip_address, - s.ilo_ip_gateway, - s.ilo_ip_netmask, - s.ilo_password, - s.ilo_username, - 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 - ), - 'maxBandwidth', interface.max_bandwidth, - 'monitor', interface.monitor, - 'mtu', COALESCE (interface.mtu, 9000), - 'name', interface.name - )) - FROM interface - WHERE interface.server = s.id - ) AS interfaces, - s.mgmt_ip_address, - s.mgmt_ip_gateway, - s.mgmt_ip_netmask, - s.offline_reason, + ARRAY(select deliveryservice from deliveryservice_server where server = server.id), + server.domain_name, + server.guid, + server.host_name, + server.https_port, + server.id, + server.ilo_ip_address, + server.ilo_ip_gateway, + server.ilo_ip_netmask, + server.ilo_password, + server.ilo_username, + ` + InterfacesArray + ` AS interfaces, + server.mgmt_ip_address, + 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, - s.rack, - s.router_host_name, - s.router_port_name, + server.rack, + server.router_host_name, + server.router_port_name, st.name as status, - s.tcp_port, + server.tcp_port, t.name as server_type, - s.xmpp_id, - s.xmpp_passwd -FROM server AS s -JOIN cachegroup cg ON s.cachegroup = cg.id -JOIN cdn ON s.cdn_id = cdn.id -JOIN phys_location pl ON s.phys_location = pl.id -JOIN profile p ON s.profile = p.id -JOIN status st ON s.status = st.id -JOIN type t ON s.type = t.id + server.xmpp_id, + server.xmpp_passwd +FROM server +JOIN cachegroup cg ON server.cachegroup = cg.id +JOIN cdn ON server.cdn_id = cdn.id +JOIN phys_location pl ON server.phys_location = pl.id +JOIN profile p ON server.profile = p.id +JOIN status st ON server.status = st.id +JOIN type t ON server.type = t.id ` limitStr := "" if limit != 0 { @@ -250,13 +231,13 @@ JOIN type t ON s.type = t.id rows := (*sql.Rows)(nil) err := error(nil) if hostName != "" && physLocationID != -1 { - q += ` WHERE s.host_name = $1::text AND s.phys_location = $2::bigint` + orderByStr + limitStr + q += ` WHERE server.host_name = $1::text AND server.phys_location = $2::bigint` + orderByStr + limitStr rows, err = tx.Query(q, hostName, physLocationID) } else if hostName != "" { - q += ` WHERE s.host_name = $1::text` + orderByStr + limitStr + q += ` WHERE server.host_name = $1::text` + orderByStr + limitStr rows, err = tx.Query(q, hostName) } else if physLocationID != -1 { - q += ` WHERE s.phys_location = $1::int` + orderByStr + limitStr + q += ` WHERE server.phys_location = $1::int` + orderByStr + limitStr rows, err = tx.Query(q, physLocationID) } else { q += orderByStr + limitStr diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 6aca884c25..5320d7a4cb 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -99,10 +99,8 @@ JOIN profile p ON s.profile = p.id JOIN status st ON s.status = st.id JOIN type t ON s.type = t.id ` - -const SelectInterfacesQuery = ` -SELECT ( - ARRAY ( SELECT ( +const InterfacesArray = ` +ARRAY ( SELECT ( json_build_object ( 'ipAddresses', ARRAY ( @@ -125,7 +123,10 @@ SELECT ( ) FROM interface WHERE interface.server = server.id -)) AS interfaces, +)` +const SelectInterfacesQuery = ` +SELECT ( ` + InterfacesArray + ` + ) AS interfaces, server.id FROM server WHERE server.id = ANY ($1) From e51421eab3d917ae2ffe468b9884516591079061 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 1 Jun 2020 10:48:40 -0600 Subject: [PATCH 75/87] Fixed possible segfault in MTU validation --- traffic_ops/traffic_ops_golang/server/servers.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 5320d7a4cb..4f038dd41d 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -402,7 +402,10 @@ func validateV2(s *tc.ServerNullableV2, tx *sql.Tx) error { } func validateMTU(mtu interface{}) error { - m := mtu.(*uint64) + m, ok := mtu.(*uint64) + if !ok { + return errors.New("must be an unsigned integer with 64-bit precision") + } if m == nil { return nil } From 1ec1ab21bad4665ebd6e3d42ce415f893beee3e3 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 1 Jun 2020 10:50:36 -0600 Subject: [PATCH 76/87] Moved back to grave accents for query addition --- traffic_ops/traffic_ops_golang/server/servers.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 4f038dd41d..f564d8e774 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -605,7 +605,9 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( return nil, unfiltered, errors.New("forbidden"), sysErr, http.StatusForbidden } // only if dsId is part of params: add join on deliveryservice_server table - queryAddition = "\nFULL OUTER JOIN deliveryservice_server dss ON dss.server = s.id\n" + queryAddition = ` + FULL OUTER JOIN deliveryservice_server dss ON dss.server = s.id + ` // depending on ds type, also need to add mids dsType, exists, err := dbhelpers.GetDeliveryServiceType(dsID, tx.Tx) if err != nil { From 0961c350e2eb9e049c6554d6264c1560c7d1c20d Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 1 Jun 2020 11:43:04 -0600 Subject: [PATCH 77/87] Fix server count query It wasn't properly considering non-paginiation query parameters. Also changed 'unfiltered' names to be more appropriate. --- traffic_ops/testing/api/v3/servers_test.go | 6 +- .../traffic_ops_golang/server/servers.go | 60 ++++++++++++------- 2 files changed, 39 insertions(+), 27 deletions(-) diff --git a/traffic_ops/testing/api/v3/servers_test.go b/traffic_ops/testing/api/v3/servers_test.go index 0af24abb91..ff04d95724 100644 --- a/traffic_ops/testing/api/v3/servers_test.go +++ b/traffic_ops/testing/api/v3/servers_test.go @@ -45,8 +45,6 @@ func CreateTestServers(t *testing.T) { } func GetTestServers(t *testing.T) { - serverCount := uint64(len(testData.Servers)) - params := url.Values{} for _, server := range testData.Servers { if server.HostName == nil { @@ -57,8 +55,8 @@ func GetTestServers(t *testing.T) { resp, _, err := TOSession.GetServers(¶ms) if err != nil { t.Errorf("cannot GET Server by name '%s': %v - %v", *server.HostName, err, resp.Alerts) - } else if resp.Summary.Count != serverCount { - t.Errorf("incorrect server count, expected: %d, actual: %d", serverCount, resp.Summary.Count) + } else if resp.Summary.Count != 1 { + t.Errorf("incorrect server count, expected: 1, actual: %d", resp.Summary.Count) } } } diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index f564d8e774..d1e8bccd32 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -48,9 +48,9 @@ import ( "github.com/lib/pq" ) -const unfilteredServersQuery = ` -SELECT COUNT(server.id) -FROM server +const serverCountQuery = ` +SELECT COUNT(s.id) +FROM server AS s ` const selectQuery = ` @@ -495,8 +495,8 @@ func Read(w http.ResponseWriter, r *http.Request) { } servers := []tc.ServerNullable{} - var unfiltered uint64 - servers, unfiltered, userErr, sysErr, errCode = getServers(inf.Params, inf.Tx, inf.User) + var serverCount uint64 + servers, serverCount, userErr, sysErr, errCode = getServers(inf.Params, inf.Tx, inf.User) if userErr != nil || sysErr != nil { api.HandleErr(w, r, tx, errCode, userErr, sysErr) @@ -504,7 +504,7 @@ func Read(w http.ResponseWriter, r *http.Request) { } if version.Major >= 3 { - api.WriteRespWithSummary(w, r, servers, unfiltered) + api.WriteRespWithSummary(w, r, servers, serverCount) return } @@ -572,10 +572,6 @@ func ReadID(w http.ResponseWriter, r *http.Request) { } func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ([]tc.ServerNullable, uint64, error, error, int) { - var unfiltered uint64 - if err := tx.QueryRow(unfilteredServersQuery).Scan(&unfiltered); err != nil { - return nil, 0, nil, fmt.Errorf("failed to get servers count: %v", err), http.StatusInternalServerError - } // Query Parameters to Database Query column mappings // see the fields mapped in the SQL query @@ -598,11 +594,11 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( // don't allow query on ds outside user's tenant dsID, err := strconv.Atoi(dsIDStr) if err != nil { - return nil, unfiltered, errors.New("dsId must be an integer"), nil, http.StatusNotFound + return nil, 0, errors.New("dsId must be an integer"), nil, http.StatusNotFound } userErr, sysErr, _ := tenant.CheckID(tx.Tx, user, dsID) if userErr != nil || sysErr != nil { - return nil, unfiltered, errors.New("forbidden"), sysErr, http.StatusForbidden + return nil, 0, errors.New("forbidden"), sysErr, http.StatusForbidden } // only if dsId is part of params: add join on deliveryservice_server table queryAddition = ` @@ -611,10 +607,10 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( // depending on ds type, also need to add mids dsType, exists, err := dbhelpers.GetDeliveryServiceType(dsID, tx.Tx) if err != nil { - return nil, unfiltered, nil, err, http.StatusInternalServerError + return nil, 0, nil, err, http.StatusInternalServerError } if !exists { - return nil, unfiltered, fmt.Errorf("a deliveryservice with id %v was not found", dsID), nil, http.StatusBadRequest + return nil, 0, fmt.Errorf("a deliveryservice with id %v was not found", dsID), nil, http.StatusBadRequest } usesMids = dsType.UsesMidCache() log.Debugf("Servers for ds %d; uses mids? %v\n", dsID, usesMids) @@ -622,7 +618,25 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( where, orderBy, pagination, queryValues, errs := dbhelpers.BuildWhereAndOrderByAndPagination(params, queryParamsToSQLCols) if len(errs) > 0 { - return nil, unfiltered, util.JoinErrs(errs), nil, http.StatusBadRequest + return nil, 0, util.JoinErrs(errs), nil, http.StatusBadRequest + } + + // TODO there's probably a cleaner way to do this by preparing a NamedStmt first and using its QueryRow method + var serverCount uint64 + countRows, err := tx.NamedQuery(serverCountQuery + where, queryValues) + if err != nil { + return nil, 0, nil, fmt.Errorf("failed to get servers count: %v", err), http.StatusInternalServerError + } + defer countRows.Close() + rowsAffected := 0 + for countRows.Next() { + if err = countRows.Scan(&serverCount); err != nil { + return nil, 0, nil, fmt.Errorf("failed to read servers count: %v", err), http.StatusInternalServerError + } + rowsAffected++ + } + if rowsAffected != 1 { + return nil, 0, nil, fmt.Errorf("incorrect rows returned for server count, want: 1 got: %v", rowsAffected), http.StatusInternalServerError } query := selectQuery + queryAddition + where + orderBy + pagination @@ -630,7 +644,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( rows, err := tx.NamedQuery(query, queryValues) if err != nil { - return nil, unfiltered, nil, errors.New("querying: " + err.Error()), http.StatusInternalServerError + return nil, serverCount, nil, errors.New("querying: " + err.Error()), http.StatusInternalServerError } defer rows.Close() @@ -641,7 +655,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( for rows.Next() { var s tc.ServerNullable if err = rows.StructScan(&s); err != nil { - return nil, unfiltered, nil, errors.New("getting servers: " + err.Error()), http.StatusInternalServerError + return nil, serverCount, nil, errors.New("getting servers: " + err.Error()), http.StatusInternalServerError } if user.PrivLevel < auth.PrivLevelOperations { s.ILOPassword = &HiddenField @@ -649,10 +663,10 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( } if s.ID == nil { - return nil, unfiltered, nil, errors.New("found server with nil ID"), http.StatusInternalServerError + return nil, serverCount, nil, errors.New("found server with nil ID"), http.StatusInternalServerError } if _, ok := servers[*s.ID]; ok { - return nil, unfiltered, nil, fmt.Errorf("found more than one server with ID #%d", *s.ID), http.StatusInternalServerError + return nil, serverCount, nil, fmt.Errorf("found more than one server with ID #%d", *s.ID), http.StatusInternalServerError } servers[*s.ID] = s ids = append(ids, *s.ID) @@ -660,7 +674,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( interfaceRows, err := tx.Tx.Query(SelectInterfacesQuery, pq.Array(ids)) if err != nil { - return nil, unfiltered, nil, fmt.Errorf("querying for interfaces: %v", err), http.StatusInternalServerError + return nil, serverCount, nil, fmt.Errorf("querying for interfaces: %v", err), http.StatusInternalServerError } defer interfaceRows.Close() @@ -668,7 +682,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( ifaces := []tc.ServerInterfaceInfo{} var id int if err = interfaceRows.Scan(pq.Array(&ifaces), &id); err != nil { - return nil, unfiltered, nil, fmt.Errorf("getting server interfaces: %v", err), http.StatusInternalServerError + return nil, serverCount, nil, fmt.Errorf("getting server interfaces: %v", err), http.StatusInternalServerError } if s, ok := servers[id]; !ok { @@ -691,12 +705,12 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( log.Debugf("getting mids: %v, %v, %s\n", userErr, sysErr, http.StatusText(errCode)) if userErr != nil || sysErr != nil { - return nil, unfiltered, userErr, sysErr, errCode + return nil, serverCount, userErr, sysErr, errCode } returnable = append(returnable, mids...) } - return returnable, unfiltered, nil, nil, http.StatusOK + return returnable, serverCount, nil, nil, http.StatusOK } // getMidServers gets the mids used by the servers in this DS. From e5aeb79823889ced0fe0f5226fee8254a1d48706 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 1 Jun 2020 12:08:07 -0600 Subject: [PATCH 78/87] Changed querys to exec's wherever results don't matter --- traffic_ops/traffic_ops_golang/server/servers.go | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index d1e8bccd32..19812f9959 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -824,35 +824,28 @@ func createInterfaces(id int, interfaces []tc.ServerInterfaceInfo, tx *sql.Tx) ( ifaceQry += strings.Join(ifaceQueryParts, ",") log.Debugf("Inserting interfaces for new server, query is: %s", ifaceQry) - ifaceRows, err := tx.Query(ifaceQry, ifaceArgs...) + _, err := tx.Exec(ifaceQry, ifaceArgs...) if err != nil { return api.ParseDBError(err) } - defer ifaceRows.Close() - insertedIfaces := 0 - for ifaceRows.Next() { - insertedIfaces++ - } - log.Debugf("Inserted %d interfaces", insertedIfaces) ipQry += strings.Join(ipQueryParts, ",") log.Debugf("Inserting IP addresses for new server, query is: %s", ipQry) - ipRows, err := tx.Query(ipQry, ipArgs...) + _, err = tx.Exec(ipQry, ipArgs...) if err != nil { return api.ParseDBError(err) } - defer ipRows.Close() return nil, nil, http.StatusOK } func deleteInterfaces(id int, tx *sql.Tx) (error, error, int) { - if err := tx.QueryRow(deleteIPsQuery, id).Scan(); err != nil && err != sql.ErrNoRows { + if _, err := tx.Exec(deleteIPsQuery, id); err != nil && err != sql.ErrNoRows { return api.ParseDBError(err) } - if err := tx.QueryRow(deleteInterfacesQuery, id).Scan(); err != nil && err != sql.ErrNoRows { + if _, err := tx.Exec(deleteInterfacesQuery, id); err != nil && err != sql.ErrNoRows { return api.ParseDBError(err) } From a1b896bf2a5491147f851406ba5e90256a825d16 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 1 Jun 2020 12:14:44 -0600 Subject: [PATCH 79/87] Fixed unit tests --- traffic_ops/traffic_ops_golang/server/servers_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers_test.go b/traffic_ops/traffic_ops_golang/server/servers_test.go index 30e6a554c4..0afb9d0df9 100644 --- a/traffic_ops/traffic_ops_golang/server/servers_test.go +++ b/traffic_ops/traffic_ops_golang/server/servers_test.go @@ -218,7 +218,7 @@ func TestGetServersByCachegroup(t *testing.T) { } mock.ExpectBegin() - mock.ExpectQuery("SELECT COUNT\\(server.id\\) FROM server").WillReturnRows(unfilteredRows) + mock.ExpectQuery("SELECT COUNT\\(s.id\\) FROM s").WillReturnRows(unfilteredRows) mock.ExpectQuery("SELECT").WillReturnRows(rows) mock.ExpectQuery("SELECT").WillReturnRows(interfaceRows) @@ -307,7 +307,7 @@ func TestGetMidServers(t *testing.T) { ) } mock.ExpectBegin() - mock.ExpectQuery("SELECT COUNT\\(server.id\\) FROM server").WillReturnRows(unfilteredRows) + mock.ExpectQuery("SELECT COUNT\\(s.id\\) FROM s").WillReturnRows(unfilteredRows) mock.ExpectQuery("SELECT").WillReturnRows(rows) mock.ExpectQuery("SELECT").WillReturnRows(interfaceRows) v := map[string]string{} From 4292ff495b9a67fbbd70baceec1a3a656906232c Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 1 Jun 2020 12:15:05 -0600 Subject: [PATCH 80/87] go fmt --- traffic_ops/traffic_ops_golang/server/servers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 19812f9959..89e5e58ab6 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -623,7 +623,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( // TODO there's probably a cleaner way to do this by preparing a NamedStmt first and using its QueryRow method var serverCount uint64 - countRows, err := tx.NamedQuery(serverCountQuery + where, queryValues) + countRows, err := tx.NamedQuery(serverCountQuery+where, queryValues) if err != nil { return nil, 0, nil, fmt.Errorf("failed to get servers count: %v", err), http.StatusInternalServerError } From 695ed447e4e718357910e5667f6176d092176ee9 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Mon, 1 Jun 2020 12:18:55 -0600 Subject: [PATCH 81/87] Stop ignoring no rows error --- traffic_ops/traffic_ops_golang/server/servers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 89e5e58ab6..1689df06c2 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -1202,7 +1202,7 @@ func Delete(w http.ResponseWriter, r *http.Request) { return } - if err := tx.QueryRow(deleteServerQuery, id).Scan(); err != nil && err != sql.ErrNoRows { + if err := tx.QueryRow(deleteServerQuery, id).Scan(); err != nil { userErr, sysErr, errCode = api.ParseDBError(err) api.HandleErr(w, r, tx, errCode, userErr, sysErr) return From e30f8201143c41dd36b55304ad417db2b0010d85 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Tue, 2 Jun 2020 20:23:33 -0600 Subject: [PATCH 82/87] Fixed api tests --- .../api/v3/deliveryserviceservers_test.go | 14 ++++++------- ...vers_to_deliveryservice_assignment_test.go | 21 ++++++++++++------- .../traffic_ops_golang/server/servers.go | 11 ++++++++-- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/traffic_ops/testing/api/v3/deliveryserviceservers_test.go b/traffic_ops/testing/api/v3/deliveryserviceservers_test.go index 9e2c22ccab..a34ad88fe3 100644 --- a/traffic_ops/testing/api/v3/deliveryserviceservers_test.go +++ b/traffic_ops/testing/api/v3/deliveryserviceservers_test.go @@ -51,10 +51,10 @@ func AssignServersToTopologyBasedDeliveryService(t *testing.T) { if ds[0].Topology == nil { t.Fatal("expected delivery service: 'ds-top' to have a non-nil Topology, actual: nil") } - serversResp, _, err := TOSession.GetServers() - servers := []tc.Server{} - for _, s := range serversResp { - if s.CDNID == *ds[0].CDNID && s.Type == tc.CacheTypeEdge.String() { + serversResp, _, err := TOSession.GetServers(nil) + servers := []tc.ServerNullable{} + for _, s := range serversResp.Response { + if s.CDNID != nil && *s.CDNID == *ds[0].CDNID && s.Type == tc.CacheTypeEdge.String() { servers = append(servers, s) } } @@ -63,8 +63,8 @@ func AssignServersToTopologyBasedDeliveryService(t *testing.T) { } serverNames := []string{} for _, s := range servers { - if s.CDNID == *ds[0].CDNID && s.Type == tc.CacheTypeEdge.String() { - serverNames = append(serverNames, s.HostName) + if s.CDNID != nil && *s.CDNID == *ds[0].CDNID && s.Type == tc.CacheTypeEdge.String() && s.HostName != nil { + serverNames = append(serverNames, *s.HostName) } else { t.Fatalf("expected only EDGE servers in cdn '%s', actual: %v", *ds[0].CDNName, servers) } @@ -77,7 +77,7 @@ func AssignServersToTopologyBasedDeliveryService(t *testing.T) { t.Fatalf("assigning servers to topology-based delivery service - expected: 400-level status code, actual: %d", reqInf.StatusCode) } - _, reqInf, err = TOSession.CreateDeliveryServiceServers(*ds[0].ID, []int{servers[0].ID}, false) + _, reqInf, err = TOSession.CreateDeliveryServiceServers(*ds[0].ID, []int{*servers[0].ID}, false) if err == nil { t.Fatal("creating deliveryserviceserver assignment for topology-based delivery service - expected: error, actual: nil error") } diff --git a/traffic_ops/testing/api/v3/servers_to_deliveryservice_assignment_test.go b/traffic_ops/testing/api/v3/servers_to_deliveryservice_assignment_test.go index 1de5da55a8..dee4472324 100644 --- a/traffic_ops/testing/api/v3/servers_to_deliveryservice_assignment_test.go +++ b/traffic_ops/testing/api/v3/servers_to_deliveryservice_assignment_test.go @@ -156,24 +156,29 @@ func AssignIncorrectTestDeliveryService(t *testing.T) { } func AssignTopologyBasedDeliveryService(t *testing.T) { - var server *tc.Server + var server *tc.ServerNullable for _, s := range testData.Servers { - if s.CDNName == "cdn1" && s.Type == string(tc.CacheTypeEdge) { + if s.CDNName != nil && *s.CDNName == "cdn1" && s.Type == string(tc.CacheTypeEdge) { server = &s break } } - if server == nil { + if server == nil || server.HostName == nil { t.Fatalf("Couldn't find an EDGE server in CDN 'cdn1'!") } - rs, _, err := TOSession.GetServerByHostName(server.HostName) + params := url.Values{} + params.Add("hostName", *server.HostName) + rs, _, err := TOSession.GetServers(¶ms) if err != nil { t.Fatalf("Failed to fetch server information: %v", err) - } else if len(rs) == 0 { + } else if len(rs.Response) == 0 { t.Fatalf("Failed to fetch server information: No results returned!") } - server = &rs[0] + server = &rs.Response[0] + if server.ID == nil { + t.Fatal("Server had nil ID") + } rd, _, err := TOSession.GetDeliveryServiceByXMLIDNullable("ds-top") if err != nil { @@ -186,7 +191,7 @@ func AssignTopologyBasedDeliveryService(t *testing.T) { if firstDS.ID == nil { t.Fatal("Fetch DS information returned unknown ID") } - alerts, reqInf, err := TOSession.AssignDeliveryServiceIDsToServerID(server.ID, []int{*firstDS.ID}, false) + alerts, reqInf, err := TOSession.AssignDeliveryServiceIDsToServerID(*server.ID, []int{*firstDS.ID}, false) if err == nil { t.Errorf("Expected bad assignment to fail, but it didn't! (alerts: %v)", alerts) } @@ -194,7 +199,7 @@ func AssignTopologyBasedDeliveryService(t *testing.T) { t.Fatalf("assigning Topology-based delivery service to server - expected: 400-level status code, actual: %d", reqInf.StatusCode) } - response, _, err := TOSession.GetServerIDDeliveryServices(server.ID) + response, _, err := TOSession.GetServerIDDeliveryServices(*server.ID) t.Logf("response: %+v", response) if err != nil { t.Fatalf("Couldn't get Delivery Services assigned to Server '%+v': %v", *server, err) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 1689df06c2..fdf22a8bd5 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -1202,8 +1202,15 @@ func Delete(w http.ResponseWriter, r *http.Request) { return } - if err := tx.QueryRow(deleteServerQuery, id).Scan(); err != nil { - userErr, sysErr, errCode = api.ParseDBError(err) + if _, err := tx.Exec(deleteServerQuery, id); err != nil { + if err == sql.ErrNoRows { + log.Warnf("Server #%d existed earlier in DELETE handler but no longer did on deletion", id) + userErr = fmt.Errorf("no server exists by id #%d", id) + errCode = http.StatusNotFound + } else { + log.Errorf("Raw error: %v", err) + userErr, sysErr, errCode = api.ParseDBError(err) + } api.HandleErr(w, r, tx, errCode, userErr, sysErr) return } From af5b941a595fbf59687ba74c46ae1105f94e3a36 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Wed, 3 Jun 2020 14:32:39 -0600 Subject: [PATCH 83/87] Switched to checking rows affected in DELETE --- .../traffic_ops_golang/server/servers.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index fdf22a8bd5..0977987ece 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -1202,17 +1202,17 @@ func Delete(w http.ResponseWriter, r *http.Request) { return } - if _, err := tx.Exec(deleteServerQuery, id); err != nil { - if err == sql.ErrNoRows { - log.Warnf("Server #%d existed earlier in DELETE handler but no longer did on deletion", id) - userErr = fmt.Errorf("no server exists by id #%d", id) - errCode = http.StatusNotFound - } else { - log.Errorf("Raw error: %v", err) - userErr, sysErr, errCode = api.ParseDBError(err) - } + if result, err := tx.Exec(deleteServerQuery, id); err != nil { + log.Errorf("Raw error: %v", err) + userErr, sysErr, errCode = api.ParseDBError(err) api.HandleErr(w, r, tx, errCode, userErr, sysErr) return + } else if rowsAffected, err := result.RowsAffected(); err != nil { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("getting rows affected by server delete: %v", err)) + return + } else if rowsAffected != 1 { + api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, fmt.Errorf("incorrect number of rows affected: %d", rowsAffected)) + return } server := servers[0] From 8dbba2f9f026d8a7c50164f24b176b213e3e2308 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 4 Jun 2020 17:55:48 -0600 Subject: [PATCH 84/87] Reworked query to build out data structures after db fetch --- .../traffic_ops_golang/server/servers.go | 108 ++++++++++++------ 1 file changed, 74 insertions(+), 34 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index 0977987ece..af67089fea 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -672,42 +672,76 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( ids = append(ids, *s.ID) } - interfaceRows, err := tx.Tx.Query(SelectInterfacesQuery, pq.Array(ids)) + // if ds requested uses mid-tier caches, add those to the list as well + if usesMids { + userErr, sysErr, errCode := getMidServers(ids, servers, tx) + + log.Debugf("getting mids: %v, %v, %s\n", userErr, sysErr, http.StatusText(errCode)) + + if userErr != nil || sysErr != nil { + return nil, serverCount, userErr, sysErr, errCode + } + } + + interfaces := map[int]map[string]tc.ServerInterfaceInfo{} + interfaceRows, err := tx.Tx.Query(`SELECT monitor, mtu, name, server FROM interface`) if err != nil { return nil, serverCount, nil, fmt.Errorf("querying for interfaces: %v", err), http.StatusInternalServerError } defer interfaceRows.Close() for interfaceRows.Next() { - ifaces := []tc.ServerInterfaceInfo{} - var id int - if err = interfaceRows.Scan(pq.Array(&ifaces), &id); err != nil { + iface := tc.ServerInterfaceInfo{ + IPAddresses: []tc.ServerIPAddress{}, + } + var server int + + if err = interfaceRows.Scan(&iface.Monitor, &iface.MTU, &iface.Name, &server); err != nil { return nil, serverCount, nil, fmt.Errorf("getting server interfaces: %v", err), http.StatusInternalServerError } - if s, ok := servers[id]; !ok { - log.Warnf("interfaces query returned interfaces for server #%d that was not in original query", id) - } else { - s.Interfaces = ifaces - servers[id] = s + if _, ok := servers[server]; !ok { + continue + } + + if _, ok := interfaces[server]; !ok { + interfaces[server] = map[string]tc.ServerInterfaceInfo{} } + interfaces[server][iface.Name] = iface } - returnable := make([]tc.ServerNullable, 0, len(servers)) - for _, server := range servers { - returnable = append(returnable, server) + ipRows, err := tx.Tx.Query(`SELECT address, gateway, service_address, server, interface FROM ip_address`) + if err != nil { + return nil, serverCount, nil, fmt.Errorf("querying for IP addresses: %v", err), http.StatusInternalServerError } + defer ipRows.Close() - // if ds requested uses mid-tier caches, add those to the list as well - if usesMids { - mids, userErr, sysErr, errCode := getMidServers(returnable, tx) + for ipRows.Next() { + var ip tc.ServerIPAddress + var server int + var iface string - log.Debugf("getting mids: %v, %v, %s\n", userErr, sysErr, http.StatusText(errCode)) + if err = ipRows.Scan(&ip.Address, &ip.Gateway, &ip.ServiceAddress, &server, &iface); err != nil { + return nil, serverCount, nil, fmt.Errorf("getting server IP addresses: %v", err), http.StatusInternalServerError + } - if userErr != nil || sysErr != nil { - return nil, serverCount, userErr, sysErr, errCode + if _, ok := interfaces[server]; !ok { + continue } - returnable = append(returnable, mids...) + if i, ok := interfaces[server][iface]; !ok { + log.Warnf("IP addresses query returned addresses for an interface that was not found in interfaces query: %s", iface) + } else { + i.IPAddresses = append(i.IPAddresses, ip) + interfaces[server][iface] = i + } + } + + returnable := make([]tc.ServerNullable, 0, len(servers)) + for _, server := range servers { + for _, iface := range interfaces[*server.ID] { + server.Interfaces = append(server.Interfaces, iface) + } + returnable = append(returnable, server) } return returnable, serverCount, nil, nil, http.StatusOK @@ -721,40 +755,45 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( // pulling the cachegroups of the edges and finding those cachegroups parent // cachegroup... then we see which servers have cachegroup in parent cachegroup // list...that's how we find mids for the ds :) -func getMidServers(servers []tc.ServerNullable, tx *sqlx.Tx) ([]tc.ServerNullable, error, error, int) { - if len(servers) == 0 { - return nil, nil, nil, http.StatusOK - } - var ids []string - for _, s := range servers { - ids = append(ids, strconv.Itoa(*s.ID)) +func getMidServers(edgeIDs []int, servers map[int]tc.ServerNullable, tx *sqlx.Tx) (error, error, int) { + if len(edgeIDs) == 0 { + return nil, nil, http.StatusOK } - edgeIDs := strings.Join(ids, ",") // TODO: include secondary parent? q := selectQuery + ` WHERE t.name = 'MID' AND s.cachegroup IN ( SELECT cg.parent_cachegroup_id FROM cachegroup AS cg WHERE cg.id IN ( SELECT s.cachegroup FROM server AS s - WHERE s.id IN (` + edgeIDs + `))) + WHERE s.id IN ($1))) ` - rows, err := tx.Queryx(q) + rows, err := tx.Queryx(q, pq.Array(edgeIDs)) if err != nil { - return nil, err, nil, http.StatusBadRequest + return err, nil, http.StatusBadRequest } defer rows.Close() - var mids []tc.ServerNullable for rows.Next() { var s tc.ServerNullable if err := rows.StructScan(&s); err != nil { log.Error.Printf("could not scan mid servers: %s\n", err) - return nil, nil, err, http.StatusInternalServerError + return nil, err, http.StatusInternalServerError + } + if s.ID == nil { + return nil, errors.New("found server with nil ID"), http.StatusInternalServerError + } + + // This may mean that the server was caught by other query parameters, + // so not technically an error, unlike earlier in 'getServers'. + if _, ok := servers[*s.ID]; ok { + continue } - mids = append(mids, s) + + servers[*s.ID] = s } - return mids, nil, nil, http.StatusOK + + return nil, nil, http.StatusOK } func checkTypeChangeSafety(server tc.CommonServerProperties, tx *sqlx.Tx) (error, error, int) { @@ -1021,6 +1060,7 @@ func createV1(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { ifaces, err := server.LegacyInterfaceDetails.ToInterfaces(true, true) if err != nil { api.HandleErr(w, r, tx, http.StatusInternalServerError, nil, err) + return } if userErr, sysErr, errCode := createInterfaces(*server.ID, ifaces, tx); err != nil { From 0abe7fe302e9f77f4a480e99f2c7c3fc28ac85a5 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 4 Jun 2020 19:39:36 -0600 Subject: [PATCH 85/87] Improved performance by only fetching interfaces for requested servers --- .../traffic_ops_golang/server/servers.go | 46 ++++++++++++++----- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index af67089fea..c7ed54870b 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -674,17 +674,27 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( // if ds requested uses mid-tier caches, add those to the list as well if usesMids { - userErr, sysErr, errCode := getMidServers(ids, servers, tx) + midIDs, userErr, sysErr, errCode := getMidServers(ids, servers, tx) log.Debugf("getting mids: %v, %v, %s\n", userErr, sysErr, http.StatusText(errCode)) if userErr != nil || sysErr != nil { return nil, serverCount, userErr, sysErr, errCode } + ids = append(ids, midIDs...) } + if len(ids) < 1 { + return []tc.ServerNullable{}, serverCount, nil, nil, http.StatusOK + } + + query, args, err := sqlx.In(`SELECT monitor, mtu, name, server FROM interface WHERE server IN (?)`, ids) + if err != nil { + return nil, serverCount, nil, fmt.Errorf("building interfaces query: %v", err), http.StatusInternalServerError + } + query = tx.Rebind(query) interfaces := map[int]map[string]tc.ServerInterfaceInfo{} - interfaceRows, err := tx.Tx.Query(`SELECT monitor, mtu, name, server FROM interface`) + interfaceRows, err := tx.Queryx(query, args...) if err != nil { return nil, serverCount, nil, fmt.Errorf("querying for interfaces: %v", err), http.StatusInternalServerError } @@ -710,7 +720,12 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( interfaces[server][iface.Name] = iface } - ipRows, err := tx.Tx.Query(`SELECT address, gateway, service_address, server, interface FROM ip_address`) + query, args, err = sqlx.In(`SELECT address, gateway, service_address, server, interface FROM ip_address WHERE server IN (?)`, ids) + if err != nil { + return nil, serverCount, nil, fmt.Errorf("building IP addresses query: %v", err), http.StatusInternalServerError + } + query = tx.Rebind(query) + ipRows, err := tx.Tx.Query(query, args...) if err != nil { return nil, serverCount, nil, fmt.Errorf("querying for IP addresses: %v", err), http.StatusInternalServerError } @@ -755,9 +770,9 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( // pulling the cachegroups of the edges and finding those cachegroups parent // cachegroup... then we see which servers have cachegroup in parent cachegroup // list...that's how we find mids for the ds :) -func getMidServers(edgeIDs []int, servers map[int]tc.ServerNullable, tx *sqlx.Tx) (error, error, int) { +func getMidServers(edgeIDs []int, servers map[int]tc.ServerNullable, tx *sqlx.Tx) ([]int, error, error, int) { if len(edgeIDs) == 0 { - return nil, nil, http.StatusOK + return nil, nil, nil, http.StatusOK } // TODO: include secondary parent? @@ -766,22 +781,30 @@ func getMidServers(edgeIDs []int, servers map[int]tc.ServerNullable, tx *sqlx.Tx SELECT cg.parent_cachegroup_id FROM cachegroup AS cg WHERE cg.id IN ( SELECT s.cachegroup FROM server AS s - WHERE s.id IN ($1))) + WHERE s.id IN (?))) ` - rows, err := tx.Queryx(q, pq.Array(edgeIDs)) + + query, args, err := sqlx.In(q, edgeIDs) if err != nil { - return err, nil, http.StatusBadRequest + return nil, nil, fmt.Errorf("constructing mid servers query: %v", err), http.StatusInternalServerError + } + query = tx.Rebind(query) + + rows, err := tx.Queryx(query, args...) + if err != nil { + return nil, err, nil, http.StatusBadRequest } defer rows.Close() + ids := []int{} for rows.Next() { var s tc.ServerNullable if err := rows.StructScan(&s); err != nil { log.Error.Printf("could not scan mid servers: %s\n", err) - return nil, err, http.StatusInternalServerError + return nil, nil, err, http.StatusInternalServerError } if s.ID == nil { - return nil, errors.New("found server with nil ID"), http.StatusInternalServerError + return nil, nil, errors.New("found server with nil ID"), http.StatusInternalServerError } // This may mean that the server was caught by other query parameters, @@ -791,9 +814,10 @@ func getMidServers(edgeIDs []int, servers map[int]tc.ServerNullable, tx *sqlx.Tx } servers[*s.ID] = s + ids = append(ids, *s.ID) } - return nil, nil, http.StatusOK + return ids, nil, nil, http.StatusOK } func checkTypeChangeSafety(server tc.CommonServerProperties, tx *sqlx.Tx) (error, error, int) { From 45bc7db99cd869806ce73ba9f41d00d3ab0c299a Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Thu, 4 Jun 2020 20:31:25 -0600 Subject: [PATCH 86/87] Fixed XMPPIDs not being properly set on server creation --- .../traffic_ops_golang/server/servers.go | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index c7ed54870b..fac6cfd8e6 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -293,7 +293,7 @@ const deleteServerQuery = `DELETE FROM server WHERE id=$1` const deleteInterfacesQuery = `DELETE FROM interface WHERE server=$1` const deleteIPsQuery = `DELETE FROM ip_address WHERE server = $1` -func validateCommon(s tc.CommonServerProperties, tx *sql.Tx) []error { +func validateCommon(s *tc.CommonServerProperties, tx *sql.Tx) []error { noSpaces := validation.NewStringRule(tovalidate.NoSpaces, "cannot contain spaces") @@ -343,7 +343,7 @@ func validateCommon(s tc.CommonServerProperties, tx *sql.Tx) []error { return errs } -func validateV1(s tc.ServerNullableV11, tx *sql.Tx) error { +func validateV1(s *tc.ServerNullableV11, tx *sql.Tx) error { if s.IP6Address != nil && len(strings.TrimSpace(*s.IP6Address)) == 0 { s.IP6Address = nil } @@ -367,7 +367,7 @@ func validateV1(s tc.ServerNullableV11, tx *sql.Tx) error { validateErrs["ip6Address"] = validation.Validate(s.IP6Address, validation.By(tovalidate.IsValidIPv6CIDROrAddress)) } errs = append(errs, tovalidate.ToErrors(validateErrs)...) - errs = append(errs, validateCommon(s.CommonServerProperties, tx)...) + errs = append(errs, validateCommon(&s.CommonServerProperties, tx)...) return util.JoinErrs(errs) } @@ -375,7 +375,7 @@ func validateV1(s tc.ServerNullableV11, tx *sql.Tx) error { func validateV2(s *tc.ServerNullableV2, tx *sql.Tx) error { var errs []error - if err := validateV1(s.ServerNullableV11, tx); err != nil { + if err := validateV1(&s.ServerNullableV11, tx); err != nil { return err } @@ -416,7 +416,7 @@ func validateMTU(mtu interface{}) error { return nil } -func validateV3(s tc.ServerNullable, tx *sql.Tx) (string, error) { +func validateV3(s *tc.ServerNullable, tx *sql.Tx) (string, error) { if len(s.Interfaces) == 0 { return "", errors.New("a server must have at least one interface") @@ -474,7 +474,7 @@ func validateV3(s tc.ServerNullable, tx *sql.Tx) (string, error) { } } - errs = append(errs, validateCommon(s.CommonServerProperties, tx)...) + errs = append(errs, validateCommon(&s.CommonServerProperties, tx)...) return serviceInterface, util.JoinErrs(errs) } @@ -932,7 +932,7 @@ func Update(w http.ResponseWriter, r *http.Request) { api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) return } - serviceInterface, err := validateV3(newServer, tx) + serviceInterface, err := validateV3(&newServer, tx) if err != nil { api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) return @@ -969,7 +969,7 @@ func Update(w http.ResponseWriter, r *http.Request) { return } - err := validateV1(legacyServer, tx) + err := validateV1(&legacyServer, tx) if err != nil { api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) return @@ -1053,7 +1053,7 @@ func createV1(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { return } - if err := validateV1(server, tx); err != nil { + if err := validateV1(&server, tx); err != nil { api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) return } @@ -1164,7 +1164,7 @@ func createV3(inf *api.APIInfo, w http.ResponseWriter, r *http.Request) { return } - serviceInterface, err := validateV3(server, tx) + serviceInterface, err := validateV3(&server, tx) if err != nil { api.HandleErr(w, r, tx, http.StatusBadRequest, err, nil) return From d4a3d56a4ee1ee61774725697f73d8598bf64e95 Mon Sep 17 00:00:00 2001 From: ocket8888 Date: Fri, 5 Jun 2020 12:34:19 -0600 Subject: [PATCH 87/87] Fixed unit tests --- .../traffic_ops_golang/server/servers.go | 4 +- .../traffic_ops_golang/server/servers_test.go | 118 ++++++++++++++---- 2 files changed, 95 insertions(+), 27 deletions(-) diff --git a/traffic_ops/traffic_ops_golang/server/servers.go b/traffic_ops/traffic_ops_golang/server/servers.go index fac6cfd8e6..8d72737016 100644 --- a/traffic_ops/traffic_ops_golang/server/servers.go +++ b/traffic_ops/traffic_ops_golang/server/servers.go @@ -688,7 +688,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( return []tc.ServerNullable{}, serverCount, nil, nil, http.StatusOK } - query, args, err := sqlx.In(`SELECT monitor, mtu, name, server FROM interface WHERE server IN (?)`, ids) + query, args, err := sqlx.In(`SELECT max_bandwidth, monitor, mtu, name, server FROM interface WHERE server IN (?)`, ids) if err != nil { return nil, serverCount, nil, fmt.Errorf("building interfaces query: %v", err), http.StatusInternalServerError } @@ -706,7 +706,7 @@ func getServers(params map[string]string, tx *sqlx.Tx, user *auth.CurrentUser) ( } var server int - if err = interfaceRows.Scan(&iface.Monitor, &iface.MTU, &iface.Name, &server); err != nil { + if err = interfaceRows.Scan(&iface.MaxBandwidth, &iface.Monitor, &iface.MTU, &iface.Name, &server); err != nil { return nil, serverCount, nil, fmt.Errorf("getting server interfaces: %v", err), http.StatusInternalServerError } diff --git a/traffic_ops/traffic_ops_golang/server/servers_test.go b/traffic_ops/traffic_ops_golang/server/servers_test.go index 0afb9d0df9..2f80a8a7eb 100644 --- a/traffic_ops/traffic_ops_golang/server/servers_test.go +++ b/traffic_ops/traffic_ops_golang/server/servers_test.go @@ -20,7 +20,6 @@ package server */ import ( - "fmt" "net/http" "testing" "time" @@ -36,8 +35,8 @@ import ( ) type ServerAndInterfaces struct { - Server tc.Server - Interfaces []byte + Server tc.Server + Interface tc.ServerInterfaceInfo } func getTestServers() []ServerAndInterfaces { @@ -90,21 +89,35 @@ func getTestServers() []ServerAndInterfaces { XMPPPasswd: "xmppPasswd", } - interfaces := []byte(fmt.Sprintf(`{"{\"ipAddresses\" : [{\"address\" : \"%s\", \"gateway\" : null, \"service_address\" : true}], \"max_bandwidth\" : null, \"monitor\" : true, \"mtu\" : %d, \"name\" : \"%s\"}"}`, testServer.IPAddress, testServer.InterfaceMtu, testServer.InterfaceName)) + mtu := uint64(testServer.InterfaceMtu) - servers = append(servers, ServerAndInterfaces{Server: testServer, Interfaces: interfaces}) + iface := tc.ServerInterfaceInfo{ + IPAddresses: []tc.ServerIPAddress{ + tc.ServerIPAddress{ + Address: testServer.IPAddress, + Gateway: nil, + ServiceAddress: true, + }, + }, + MaxBandwidth: nil, + Monitor: true, + MTU: &mtu, + Name: testServer.InterfaceName, + } + + servers = append(servers, ServerAndInterfaces{Server: testServer, Interface: iface}) testServer2 := testServer testServer2.Cachegroup = "cachegroup2" testServer2.HostName = "server2" testServer2.ID = 2 - servers = append(servers, ServerAndInterfaces{Server: testServer2, Interfaces: interfaces}) + servers = append(servers, ServerAndInterfaces{Server: testServer2, Interface: iface}) testServer3 := testServer testServer3.Cachegroup = "cachegroup3" testServer3.HostName = "server3" testServer3.ID = 3 - servers = append(servers, ServerAndInterfaces{Server: testServer3, Interfaces: interfaces}) + servers = append(servers, ServerAndInterfaces{Server: testServer3, Interface: iface}) return servers } @@ -165,10 +178,13 @@ func TestGetServersByCachegroup(t *testing.T) { unfilteredRows := sqlmock.NewRows(unfilteredCols).AddRow(len(testServers)) cols := test.ColsFromStructByTag("db", tc.CommonServerProperties{}) - interfaceCols := []string{"interfaces", "id"} + interfaceCols := []string{"max_bandwidth", "monitor", "mtu", "name", "server"} rows := sqlmock.NewRows(cols) interfaceRows := sqlmock.NewRows(interfaceCols) + ipCols := []string{"address", "gateway", "service_address", "server", "interface"} + ipRows := sqlmock.NewRows(ipCols) + //TODO: drichardson - build helper to add these Rows from the struct values // or by CSV if types get in the way for _, srv := range testServers { @@ -212,15 +228,29 @@ func TestGetServersByCachegroup(t *testing.T) { ts.XMPPPasswd, ) interfaceRows = interfaceRows.AddRow( - srv.Interfaces, + srv.Interface.MaxBandwidth, + srv.Interface.Monitor, + srv.Interface.MTU, + srv.Interface.Name, ts.ID, ) + + for _, ip := range srv.Interface.IPAddresses { + ipRows = ipRows.AddRow( + ip.Address, + ip.Gateway, + ip.ServiceAddress, + ts.ID, + srv.Interface.Name, + ) + } } mock.ExpectBegin() mock.ExpectQuery("SELECT COUNT\\(s.id\\) FROM s").WillReturnRows(unfilteredRows) mock.ExpectQuery("SELECT").WillReturnRows(rows) mock.ExpectQuery("SELECT").WillReturnRows(interfaceRows) + mock.ExpectQuery("SELECT").WillReturnRows(ipRows) v := map[string]string{"cachegroup": "2"} @@ -257,10 +287,13 @@ func TestGetMidServers(t *testing.T) { unfilteredRows := sqlmock.NewRows(unfilteredCols).AddRow(len(testServers)) cols := test.ColsFromStructByTag("db", tc.CommonServerProperties{}) - interfaceCols := []string{"interfaces", "id"} + interfaceCols := []string{"max_bandwidth", "monitor", "mtu", "name", "server"} rows := sqlmock.NewRows(cols) interfaceRows := sqlmock.NewRows(interfaceCols) + ipCols := []string{"address", "gateway", "service_address", "server", "interface"} + ipRows := sqlmock.NewRows(ipCols) + for _, srv := range testServers { ts := srv.Server rows = rows.AddRow( @@ -302,14 +335,28 @@ func TestGetMidServers(t *testing.T) { ts.XMPPPasswd, ) interfaceRows = interfaceRows.AddRow( - srv.Interfaces, + srv.Interface.MaxBandwidth, + srv.Interface.Monitor, + srv.Interface.MTU, + srv.Interface.Name, ts.ID, ) + + for _, ip := range srv.Interface.IPAddresses { + ipRows = ipRows.AddRow( + ip.Address, + ip.Gateway, + ip.ServiceAddress, + ts.ID, + srv.Interface.Name, + ) + } } mock.ExpectBegin() mock.ExpectQuery("SELECT COUNT\\(s.id\\) FROM s").WillReturnRows(unfilteredRows) mock.ExpectQuery("SELECT").WillReturnRows(rows) mock.ExpectQuery("SELECT").WillReturnRows(interfaceRows) + mock.ExpectQuery("SELECT").WillReturnRows(ipRows) v := map[string]string{} user := auth.CurrentUser{} @@ -366,7 +413,18 @@ func TestGetMidServers(t *testing.T) { } cgs = append(cgs, testCG2) + serverMap := make(map[int]tc.ServerNullable, len(servers)) + serverIDs := make([]int, 0, len(servers)) + for _, server := range servers { + if server.ID == nil { + t.Fatal("Found server with nil ID") + } + serverIDs = append(serverIDs, *server.ID) + serverMap[*server.ID] = server + } + ts := servers[1] + *ts.ID = *ts.ID + 1 rows2 = rows2.AddRow( ts.Cachegroup, ts.CachegroupID, @@ -408,7 +466,7 @@ func TestGetMidServers(t *testing.T) { mock.ExpectBegin() mock.ExpectQuery("SELECT").WillReturnRows(rows2) - mid, userErr, sysErr, errCode := getMidServers(servers, db.MustBegin()) + mid, userErr, sysErr, errCode := getMidServers(serverIDs, serverMap, db.MustBegin()) if userErr != nil || sysErr != nil { t.Fatalf("getMidServers expected: no errors, actual: %v %v with status: %s", userErr, sysErr, http.StatusText(errCode)) @@ -416,10 +474,20 @@ func TestGetMidServers(t *testing.T) { if len(mid) != 1 { t.Fatalf("getMidServers expected: len(mid) == 1, actual: %v", len(mid)) } - if mid[0].Type != "MID" || *(mid[0].CachegroupID) != 2 || *(mid[0].Cachegroup) != "parentCacheGroup" { - t.Fatalf("getMidServers expected: Type == MID, actual: %v", mid[0].Type) - t.Fatalf("getMidServers expected: CachegroupID == 2, actual: %v", *(mid[0].CachegroupID)) - t.Fatalf("getMidServers expected: Cachegroup == parentCacheGroup, actual: %v", *(mid[0].Cachegroup)) + if serverMap[mid[0]].Type != "MID" { + t.Errorf("getMidServers expected: Type == MID, actual: %v", serverMap[mid[0]].Type) + } + + if serverMap[mid[0]].Cachegroup == nil { + t.Error("getMidServers expected: Cachegroup == parentCacheGroup, actual: nil") + } else if *(serverMap[mid[0]].Cachegroup) != "parentCacheGroup" { + t.Errorf("getMidServers expected: Cachegroup == parentCacheGroup, actual: %v", *(serverMap[mid[0]].Cachegroup)) + } + + if serverMap[mid[0]].CachegroupID == nil { + t.Error("getMidServers expected: CachegroupID == 2, actual: nil") + } else if *(serverMap[mid[0]].CachegroupID) != 2 { + t.Errorf("getMidServers expected: CachegroupID == 2, actual: %v", *(serverMap[mid[0]].CachegroupID)) } } @@ -473,7 +541,7 @@ func TestV3Validations(t *testing.T) { tx := db.MustBegin().Tx - _, err = validateV3(testServer, tx) + _, err = validateV3(&testServer, tx) if err != nil { t.Errorf("Unexpected error validating test server: %v", err) } @@ -483,7 +551,7 @@ func TestV3Validations(t *testing.T) { mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) - _, err = validateV3(testServer, tx) + _, err = validateV3(&testServer, tx) if err == nil { t.Errorf("Expected a server with no interfaces to be invalid") } else { @@ -495,7 +563,7 @@ func TestV3Validations(t *testing.T) { mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) - _, err = validateV3(testServer, tx) + _, err = validateV3(&testServer, tx) if err == nil { t.Errorf("Expected a server with nil interfaces to be invalid") } else { @@ -510,7 +578,7 @@ func TestV3Validations(t *testing.T) { mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) - _, err = validateV3(testServer, tx) + _, err = validateV3(&testServer, tx) if err == nil { t.Errorf("Expected a server an MTU < 1280 to be invalid") } else { @@ -524,7 +592,7 @@ func TestV3Validations(t *testing.T) { mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) - _, err = validateV3(testServer, tx) + _, err = validateV3(&testServer, tx) if err == nil { t.Errorf("Expected a server with no IP addresses to be invalid") } else { @@ -537,7 +605,7 @@ func TestV3Validations(t *testing.T) { mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) - _, err = validateV3(testServer, tx) + _, err = validateV3(&testServer, tx) if err == nil { t.Errorf("Expected a server with nil IP addresses to be invalid") } else { @@ -556,7 +624,7 @@ func TestV3Validations(t *testing.T) { mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) - _, err = validateV3(testServer, tx) + _, err = validateV3(&testServer, tx) if err == nil { t.Errorf("Expected a server with no service addresses to be invalid") } else { @@ -568,7 +636,7 @@ func TestV3Validations(t *testing.T) { mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) - _, err = validateV3(testServer, tx) + _, err = validateV3(&testServer, tx) if err == nil { t.Errorf("Expected a server with too many interfaces with service addresses to be invalid") } else { @@ -586,7 +654,7 @@ func TestV3Validations(t *testing.T) { mock.ExpectQuery("SELECT name, use_in_table").WillReturnRows(typeRows) mock.ExpectQuery("SELECT").WillReturnRows(cdnRows) - _, err = validateV3(testServer, tx) + _, err = validateV3(&testServer, tx) if err == nil { t.Errorf("Expected a server with no service addresses to be invalid") } else {