blob: ab56c42c47f21c7ad774c3140d2a3a451ad6569b [file] [log] [blame]
package client
/*
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"
"net/url"
"strconv"
"github.com/apache/trafficcontrol/lib/go-tc"
"github.com/apache/trafficcontrol/traffic_ops/toclientlib"
)
const (
// apiServers is the API version-relative path to the /servers API
// endpoint.
apiServers = "/servers"
)
func needAndCanFetch(id *int, name *string) bool {
return (id == nil || *id == 0) && name != nil && *name != ""
}
// CreateServer creates the given Server.
func (to *Session) CreateServer(server tc.ServerV4, opts RequestOptions) (tc.Alerts, toclientlib.ReqInf, error) {
var alerts tc.Alerts
var remoteAddr net.Addr
reqInf := toclientlib.ReqInf{CacheHitStatus: toclientlib.CacheHitStatusMiss, RemoteAddr: remoteAddr}
if needAndCanFetch(server.CachegroupID, server.Cachegroup) {
innerOpts := NewRequestOptions()
innerOpts.QueryParameters.Set("name", *server.Cachegroup)
cg, reqInf, err := to.GetCacheGroups(innerOpts)
if err != nil {
return cg.Alerts, reqInf, fmt.Errorf("no cachegroup named %s: %w", *server.Cachegroup, err)
}
if len(cg.Response) == 0 {
return cg.Alerts, reqInf, fmt.Errorf("no cachegroup named %s", *server.Cachegroup)
}
if cg.Response[0].ID == nil {
return cg.Alerts, reqInf, fmt.Errorf("Cachegroup named %s has a nil ID", *server.Cachegroup)
}
server.CachegroupID = cg.Response[0].ID
}
if needAndCanFetch(server.CDNID, server.CDNName) {
innerOpts := NewRequestOptions()
innerOpts.QueryParameters.Set("name", *server.CDNName)
c, reqInf, err := to.GetCDNs(innerOpts)
if err != nil {
return c.Alerts, reqInf, fmt.Errorf("no CDN named %s: %w", *server.CDNName, err)
}
if len(c.Response) == 0 {
return c.Alerts, reqInf, fmt.Errorf("no CDN named %s", *server.CDNName)
}
server.CDNID = &c.Response[0].ID
}
if needAndCanFetch(server.PhysLocationID, server.PhysLocation) {
innerOpts := NewRequestOptions()
innerOpts.QueryParameters.Set("name", *server.PhysLocation)
ph, reqInf, err := to.GetPhysLocations(innerOpts)
if err != nil {
return ph.Alerts, reqInf, fmt.Errorf("no physlocation named %s: %w", *server.PhysLocation, err)
}
if len(ph.Response) == 0 {
return ph.Alerts, reqInf, fmt.Errorf("no physlocation named %s", *server.PhysLocation)
}
server.PhysLocationID = &ph.Response[0].ID
}
if needAndCanFetch(server.StatusID, server.Status) {
innerOpts := NewRequestOptions()
innerOpts.QueryParameters.Set("name", *server.Status)
st, reqInf, err := to.GetStatuses(innerOpts)
if err != nil {
return st.Alerts, reqInf, fmt.Errorf("no Status named %s: %w", *server.Status, err)
}
if len(st.Response) == 0 {
return alerts, reqInf, fmt.Errorf("no Status named %s", *server.Status)
}
server.StatusID = &st.Response[0].ID
}
if (server.TypeID == nil || *server.TypeID == 0) && server.Type != "" {
innerOpts := NewRequestOptions()
innerOpts.QueryParameters.Set("name", server.Type)
ty, _, err := to.GetTypes(innerOpts)
if err != nil {
return ty.Alerts, reqInf, fmt.Errorf("no Type named '%s': %w", server.Type, err)
}
if len(ty.Response) == 0 {
return ty.Alerts, reqInf, fmt.Errorf("no type named %s", server.Type)
}
server.TypeID = &ty.Response[0].ID
}
reqInf, err := to.post(apiServers, opts, server, &alerts)
return alerts, reqInf, err
}
// UpdateServer replaces the Server identified by ID with the provided one.
func (to *Session) UpdateServer(id int, server tc.ServerV4, opts RequestOptions) (tc.Alerts, toclientlib.ReqInf, error) {
var alerts tc.Alerts
route := fmt.Sprintf("%s/%d", apiServers, id)
reqInf, err := to.put(route, opts, server, &alerts)
return alerts, reqInf, err
}
// GetServers retrieves Servers from Traffic Ops.
func (to *Session) GetServers(opts RequestOptions) (tc.ServersV4Response, toclientlib.ReqInf, error) {
var data tc.ServersV4Response
reqInf, err := to.get(apiServers, opts, &data)
return data, reqInf, err
}
// DeleteServer deletes the Server with the given ID.
func (to *Session) DeleteServer(id int, opts RequestOptions) (tc.Alerts, toclientlib.ReqInf, error) {
route := fmt.Sprintf("%s/%d", apiServers, id)
var alerts tc.Alerts
reqInf, err := to.del(route, opts, &alerts)
return 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
// assignments to the server will be replaced.
func (to *Session) AssignDeliveryServiceIDsToServerID(server int, dsIDs []int, replace bool, opts RequestOptions) (tc.Alerts, toclientlib.ReqInf, error) {
// datatypes here match the library tc.Server's and tc.DeliveryService's ID fields
if opts.QueryParameters == nil {
opts.QueryParameters = url.Values{}
}
opts.QueryParameters.Set("replace", strconv.FormatBool(replace))
endpoint := fmt.Sprintf(apiServerDeliveryServices, server)
var alerts tc.Alerts
reqInf, err := to.post(endpoint, opts, dsIDs, &alerts)
return alerts, reqInf, err
}
// GetServerIDDeliveryServices returns all of the Delivery Services assigned to the server identified
// by the integral, unique identifier 'server'.
func (to *Session) GetServerIDDeliveryServices(server int, opts RequestOptions) (tc.DeliveryServicesResponseV4, toclientlib.ReqInf, error) {
endpoint := fmt.Sprintf(apiServerDeliveryServices, server)
var data tc.DeliveryServicesResponseV4
reqInf, err := to.get(endpoint, opts, &data)
return data, reqInf, err
}
// GetServerUpdateStatus retrieves the Server Update Status of the Server with
// the given (short) hostname.
func (to *Session) GetServerUpdateStatus(hostName string, opts RequestOptions) (tc.ServerUpdateStatusResponseV4, toclientlib.ReqInf, error) {
path := apiServers + `/` + url.PathEscape(hostName) + `/update_status`
var data tc.ServerUpdateStatusResponseV4
reqInf, err := to.get(path, opts, &data)
return data, reqInf, err
}