lib/go-tc/servers.go (1,216 lines of code) (raw):

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 ( "database/sql/driver" "encoding/json" "errors" "fmt" "net" "strconv" "strings" "time" "github.com/apache/trafficcontrol/v8/lib/go-util" ) // ServersV4Response is the format of a response to a GET request for API v4.x /servers. type ServersV4Response struct { Response []ServerV40 `json:"response"` Summary struct { Count uint64 `json:"count"` } `json:"summary"` Alerts } // ServersV3Response is the format of a response to a GET request for /servers. type ServersV3Response struct { Response []ServerV30 `json:"response"` Summary struct { Count uint64 `json:"count"` } `json:"summary"` Alerts } // 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 } // ServersDetailResponse is the JSON object returned for a single server. type ServersDetailResponse struct { Response Server `json:"response"` Alerts } // ServerDetailV11 is the type of each entry in the `response` array property // of responses from Traffic Ops to GET requests made to its /servers/details // API endpoint in API version 2.0. // // The reason it's named with "V11" is because it was originally used to model // the response in API version 1.1, and the structure simply hasn't changed // between then and 2.0. type ServerDetailV11 struct { ServerDetail LegacyInterfaceDetails RouterHostName *string `json:"routerHostName" db:"router_host_name"` RouterPortName *string `json:"routerPortName" db:"router_port_name"` } // ServerDetailV30 is the details for a server for API v3. type ServerDetailV30 struct { ServerDetail ServerInterfaces *[]ServerInterfaceInfo `json:"interfaces"` RouterHostName *string `json:"routerHostName" db:"router_host_name"` RouterPortName *string `json:"routerPortName" db:"router_port_name"` } // ServerDetailV40 is the details for a server for API v4. type ServerDetailV40 struct { CacheGroup *string `json:"cachegroup" db:"cachegroup"` CDNName *string `json:"cdnName" db:"cdn_name"` DeliveryServiceIDs []int64 `json:"deliveryservices,omitempty"` DomainName *string `json:"domainName" db:"domain_name"` GUID *string `json:"guid" db:"guid"` HardwareInfo map[string]string `json:"hardwareInfo"` HostName *string `json:"hostName" db:"host_name"` HTTPSPort *int `json:"httpsPort" db:"https_port"` ID *int `json:"id" db:"id"` ILOIPAddress *string `json:"iloIpAddress" db:"ilo_ip_address"` ILOIPGateway *string `json:"iloIpGateway" db:"ilo_ip_gateway"` ILOIPNetmask *string `json:"iloIpNetmask" db:"ilo_ip_netmask"` ILOPassword *string `json:"iloPassword" db:"ilo_password"` ILOUsername *string `json:"iloUsername" db:"ilo_username"` MgmtIPAddress *string `json:"mgmtIpAddress" db:"mgmt_ip_address"` MgmtIPGateway *string `json:"mgmtIpGateway" db:"mgmt_ip_gateway"` MgmtIPNetmask *string `json:"mgmtIpNetmask" db:"mgmt_ip_netmask"` OfflineReason *string `json:"offlineReason" db:"offline_reason"` PhysLocation *string `json:"physLocation" db:"phys_location"` ProfileNames []string `json:"profileNames" db:"profile_name"` Rack *string `json:"rack" db:"rack"` Status *string `json:"status" db:"status"` TCPPort *int `json:"tcpPort" db:"tcp_port"` Type string `json:"type" db:"server_type"` XMPPID *string `json:"xmppId" db:"xmpp_id"` XMPPPasswd *string `json:"xmppPasswd" db:"xmpp_passwd"` ServerInterfaces []ServerInterfaceInfoV40 `json:"interfaces"` } // ServersV1DetailResponse is the JSON object returned for a single server for v1. type ServersV1DetailResponse struct { Response []ServerDetailV11 `json:"response"` Alerts } // ServersV3DetailResponse is the JSON object returned for a single server for v3. type ServersV3DetailResponse struct { Response []ServerDetailV30 `json:"response"` Alerts } // ServersV4DetailResponse is the JSON object returned for a single server for v4. type ServersV4DetailResponse struct { Response []ServerDetailV40 `json:"response"` Alerts } // 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"` } // Copy creates a deep copy of the IP address. func (ip ServerIPAddress) Copy() ServerIPAddress { return ServerIPAddress{ Address: ip.Address, Gateway: util.CopyIfNotNil(ip.Gateway), ServiceAddress: ip.ServiceAddress, } } // ServerInterfaceInfo is the data associated with a server's interface. type ServerInterfaceInfo struct { 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"` Name string `json:"name" db:"name"` } // Copy creates a deep copy of the Server Interface. func (inf ServerInterfaceInfo) Copy() ServerInterfaceInfo { newInf := ServerInterfaceInfo{ IPAddresses: make([]ServerIPAddress, len(inf.IPAddresses)), MaxBandwidth: util.CopyIfNotNil(inf.MaxBandwidth), Monitor: inf.Monitor, MTU: util.CopyIfNotNil(inf.MTU), Name: inf.Name, } for i, ip := range inf.IPAddresses { newInf.IPAddresses[i] = ip.Copy() } return newInf } // ServerInterfaceInfoV40 is the data associated with a V40 server's interface. type ServerInterfaceInfoV40 struct { ServerInterfaceInfo RouterHostName string `json:"routerHostName" db:"router_host_name"` RouterPortName string `json:"routerPortName" db:"router_port_name"` } // Copy creates a deep copy of the Server Interface. func (inf ServerInterfaceInfoV40) Copy() ServerInterfaceInfoV40 { return ServerInterfaceInfoV40{ ServerInterfaceInfo: inf.ServerInterfaceInfo.Copy(), RouterHostName: inf.RouterHostName, RouterPortName: inf.RouterPortName, } } // GetDefaultAddress returns the IPv4 and IPv6 service addresses of the // interface - without any subnet/masking that may or may not be present on said // address(es). func (i *ServerInterfaceInfo) GetDefaultAddress() (string, string) { ipv4, ipv6 := i.GetDefaultAddressOrCIDR() address, _, err := net.ParseCIDR(ipv4) if address != nil && err == nil { ipv4 = address.String() } address, _, err = net.ParseCIDR(ipv6) if address != nil && err == nil { ipv6 = address.String() } return ipv4, ipv6 } // GetDefaultAddressOrCIDR returns the IPv4 and IPv6 service addresses of the interface, // including a subnet, if one exists. func (i *ServerInterfaceInfo) GetDefaultAddressOrCIDR() (string, string) { var ipv4, ipv6 string var err error for _, ip := range i.IPAddresses { if ip.ServiceAddress { address := net.ParseIP(ip.Address) if address == nil { address, _, err = net.ParseCIDR(ip.Address) if err != nil || address == nil { continue } } if address.To4() != nil { ipv4 = ip.Address } else if address.To16() != nil { ipv6 = ip.Address } if ipv4 != "" && ipv6 != "" { break } } } return ipv4, ipv6 } // Value implements the driver.Valuer interface // marshals struct to json to pass back as a json.RawMessage. func (i *ServerInterfaceInfo) Value() (driver.Value, error) { b, err := json.Marshal(i) return b, err } // Scan implements the sql.Scanner interface. // // This expects src to be a json.RawMessage and unmarshals it into the // ServerInterfaceInfo. func (i *ServerInterfaceInfo) Scan(src interface{}) error { b, ok := src.([]byte) if !ok { return fmt.Errorf("expected deliveryservice in byte array form; got %T", src) } return json.Unmarshal(b, i) } // LegacyInterfaceDetails is the details for interfaces on servers for API v2. // // Deprecated: Traffic Ops API version 2 is deprecated, upgrade to Server // representations that support interfaces (i.e. ServerInterfaceInfoV40 // slices). type LegacyInterfaceDetails struct { 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"` } // ToInterfaces converts a LegacyInterfaceDetails to a slice of // ServerInterfaceInfo structures. Only one interface is expected and will be marked for monitoring. // It will generate service addresses according to the passed indicators // for each address family. // // Deprecated: LegacyInterfaceDetails is deprecated, and this will be removed // with it. 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 // default to true since there should only be one interface from legacy API versions // if Monitor is false on all interfaces, then TM will see the server as unhealthy iface.Monitor = true 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 } // ToInterfacesV4 upgrades server interfaces from their APIv3 representation to // an APIv4 representation. // // The passed routerName and routerPort can be nil, which will leave the // upgradeded interfaces' RouterHostName and RouterPortName unset, or they can // be pointers to string values to which ALL of the interfaces will have their // RouterHostName and RouterPortName set. func ToInterfacesV4(oldInterfaces []ServerInterfaceInfo, routerName, routerPort *string) ([]ServerInterfaceInfoV40, error) { v4Interfaces := make([]ServerInterfaceInfoV40, 0) var v4Int ServerInterfaceInfoV40 for _, i := range oldInterfaces { v4Int.ServerInterfaceInfo = i if routerName != nil { v4Int.RouterHostName = *routerName } if routerPort != nil { v4Int.RouterPortName = *routerPort } v4Interfaces = append(v4Interfaces, v4Int) } return v4Interfaces, nil } // ToInterfacesV4 converts a LegacyInterfaceDetails to a slice of // ServerInterfaceInfoV40 structures. // // Only one interface is expected and will be marked for monitoring. This will // generate service addresses according to the passed indicators for each // address family. // // The passed routerName and routerPort can be nil, which will leave the // upgradeded interfaces' RouterHostName and RouterPortName unset, or they can // be pointers to string values to which ALL of the interfaces will have their // RouterHostName and RouterPortName set. // // Deprecated: LegacyInterfaceDetails is deprecated, and this will be removed // with it. func (lid *LegacyInterfaceDetails) ToInterfacesV4(ipv4IsService, ipv6IsService bool, routerName, routerPort *string) ([]ServerInterfaceInfoV40, error) { var iface ServerInterfaceInfoV40 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 // default to true since there should only be one interface from legacy API versions // if Monitor is false on all interfaces, then TM will see the server as unhealthy iface.Monitor = true 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 if routerName != nil { iface.RouterHostName = *routerName } if routerPort != nil { iface.RouterPortName = *routerPort } return []ServerInterfaceInfoV40{iface}, nil } // String implements the fmt.Stringer interface. func (lid LegacyInterfaceDetails) String() string { var b strings.Builder b.Write([]byte("LegacyInterfaceDetails(InterfaceMtu=")) if lid.InterfaceMtu == nil { b.Write([]byte("nil")) } else { b.WriteString(strconv.FormatInt(int64(*lid.InterfaceMtu), 10)) } b.Write([]byte(", InterfaceName=")) if lid.InterfaceName != nil { b.WriteRune('\'') b.WriteString(*lid.InterfaceName) b.WriteRune('\'') } else { b.Write([]byte("nil")) } b.Write([]byte(", IP6Address=")) if lid.IP6Address != nil { b.WriteRune('\'') b.WriteString(*lid.IP6Address) b.WriteRune('\'') } else { b.Write([]byte("nil")) } b.Write([]byte(", IP6Gateway=")) if lid.IP6Gateway != nil { b.WriteRune('\'') b.WriteString(*lid.IP6Gateway) b.WriteRune('\'') } else { b.Write([]byte("nil")) } b.Write([]byte(", IPAddress=")) if lid.IPAddress != nil { b.WriteRune('\'') b.WriteString(*lid.IPAddress) b.WriteRune('\'') } else { b.Write([]byte("nil")) } b.Write([]byte(", IPGateway=")) if lid.IPGateway != nil { b.WriteRune('\'') b.WriteString(*lid.IPGateway) b.WriteRune('\'') } else { b.Write([]byte("nil")) } b.Write([]byte(", IPNetmask=")) if lid.IPNetmask != nil { b.WriteRune('\'') b.WriteString(*lid.IPNetmask) b.WriteRune('\'') } else { b.Write([]byte("nil")) } b.WriteRune(')') return b.String() } // V4InterfaceInfoToV3Interfaces downgrades a set of ServerInterfaceInfoV40s to // ServerInterfaceInfos. func V4InterfaceInfoToV3Interfaces(serverInterfaces []ServerInterfaceInfoV40) ([]ServerInterfaceInfo, error) { var interfaces []ServerInterfaceInfo for _, intFace := range serverInterfaces { var interfaceV3 ServerInterfaceInfo interfaceV3.IPAddresses = intFace.IPAddresses interfaceV3.Monitor = intFace.Monitor interfaceV3.MaxBandwidth = intFace.MaxBandwidth interfaceV3.MTU = intFace.MTU interfaceV3.Name = intFace.Name interfaces = append(interfaces, interfaceV3) } return interfaces, nil } // V4InterfaceInfoToLegacyInterfaces downgrades a set of // ServerInterfaceInfoV40s to a LegacyInterfaceDetails. // // Deprecated: LegacyInterfaceDetails is deprecated, and this will be removed // with it. func V4InterfaceInfoToLegacyInterfaces(serverInterfaces []ServerInterfaceInfoV40) (LegacyInterfaceDetails, error) { var legacyDetails LegacyInterfaceDetails for _, intFace := range serverInterfaces { foundServiceInterface := false for _, addr := range intFace.IPAddresses { if !addr.ServiceAddress { continue } foundServiceInterface = true address := addr.Address gateway := addr.Gateway var parsedIp net.IP var mask *net.IPNet var err error parsedIp, mask, err = net.ParseCIDR(address) if err != nil { 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 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 legacyDetails.IPNetmask = new(string) } if intFace.MTU != nil { legacyDetails.InterfaceMtu = util.IntPtr(int(*intFace.MTU)) } // This should no longer matter now that short-circuiting is better, // but this temporary variable is necessary because the 'intFace' // variable is referential, so taking '&intFace.Name' would cause // problems when intFace is reassigned. name := intFace.Name legacyDetails.InterfaceName = &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 != "" { break } } if foundServiceInterface { return legacyDetails, nil } } return legacyDetails, errors.New("no service addresses found") } // 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 // are discarded, as the legacy format is incapable of representing them. // // Deprecated: LegacyInterfaceDetails is deprecated, and this will be removed // with it. func InterfaceInfoToLegacyInterfaces(serverInterfaces []ServerInterfaceInfo) (LegacyInterfaceDetails, error) { var legacyDetails LegacyInterfaceDetails for _, intFace := range serverInterfaces { foundServiceInterface := false for _, addr := range intFace.IPAddresses { if !addr.ServiceAddress { continue } foundServiceInterface = true address := addr.Address gateway := addr.Gateway var parsedIp net.IP var mask *net.IPNet var err error parsedIp, mask, err = net.ParseCIDR(address) if err != nil { 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 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 legacyDetails.IPNetmask = new(string) } if intFace.MTU != nil { legacyDetails.InterfaceMtu = util.IntPtr(int(*intFace.MTU)) } // This should no longer matter now that short-circuiting is better, // but this temporary variable is necessary because the 'intFace' // variable is referential, so taking '&intFace.Name' would cause // problems when intFace is reassigned. name := intFace.Name legacyDetails.InterfaceName = &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 != "" { break } } if foundServiceInterface { return legacyDetails, nil } } return legacyDetails, errors.New("no service addresses found") } // Server is a non-"nullable" representation of a Server as it appeared in API // version 2.0 // // Deprecated: Please use versioned and nullable structures from now on. type Server struct { Cachegroup string `json:"cachegroup" db:"cachegroup"` CachegroupID int `json:"cachegroupId" db:"cachegroup_id"` CDNID int `json:"cdnId" db:"cdn_id"` CDNName string `json:"cdnName" db:"cdn_name"` DeliveryServices map[string][]string `json:"deliveryServices,omitempty"` DomainName string `json:"domainName" db:"domain_name"` FQDN *string `json:"fqdn,omitempty"` FqdnTime time.Time `json:"-"` GUID string `json:"guid" db:"guid"` HostName string `json:"hostName" db:"host_name"` HTTPSPort int `json:"httpsPort" db:"https_port"` ID int `json:"id" db:"id"` ILOIPAddress string `json:"iloIpAddress" db:"ilo_ip_address"` ILOIPGateway string `json:"iloIpGateway" db:"ilo_ip_gateway"` ILOIPNetmask string `json:"iloIpNetmask" db:"ilo_ip_netmask"` ILOPassword string `json:"iloPassword" db:"ilo_password"` ILOUsername string `json:"iloUsername" db:"ilo_username"` InterfaceMtu int `json:"interfaceMtu" db:"interface_mtu"` InterfaceName string `json:"interfaceName" db:"interface_name"` IP6Address string `json:"ip6Address" db:"ip6_address"` IP6IsService bool `json:"ip6IsService" db:"ip6_address_is_service"` IP6Gateway string `json:"ip6Gateway" db:"ip6_gateway"` IPAddress string `json:"ipAddress" db:"ip_address"` IPIsService bool `json:"ipIsService" db:"ip_address_is_service"` 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"` MgmtIPNetmask string `json:"mgmtIpNetmask" db:"mgmt_ip_netmask"` OfflineReason string `json:"offlineReason" db:"offline_reason"` PhysLocation string `json:"physLocation" db:"phys_location"` PhysLocationID int `json:"physLocationId" db:"phys_location_id"` Profile string `json:"profile" db:"profile"` ProfileDesc string `json:"profileDesc" db:"profile_desc"` ProfileID int `json:"profileId" db:"profile_id"` Rack string `json:"rack" db:"rack"` RevalPending bool `json:"revalPending" db:"reval_pending"` RouterHostName string `json:"routerHostName" db:"router_host_name"` RouterPortName string `json:"routerPortName" db:"router_port_name"` Status string `json:"status" db:"status"` StatusID int `json:"statusId" db:"status_id"` TCPPort int `json:"tcpPort" db:"tcp_port"` Type string `json:"type" db:"server_type"` TypeID int `json:"typeId" db:"server_type_id"` UpdPending bool `json:"updPending" db:"upd_pending"` XMPPID string `json:"xmppId" db:"xmpp_id"` XMPPPasswd string `json:"xmppPasswd" db:"xmpp_passwd"` } // 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"` CDNName *string `json:"cdnName" db:"cdn_name"` DeliveryServices *map[string][]string `json:"deliveryServices,omitempty"` DomainName *string `json:"domainName" db:"domain_name"` FQDN *string `json:"fqdn,omitempty"` FqdnTime time.Time `json:"-"` GUID *string `json:"guid" db:"guid"` HostName *string `json:"hostName" db:"host_name"` HTTPSPort *int `json:"httpsPort" db:"https_port"` ID *int `json:"id" db:"id"` ILOIPAddress *string `json:"iloIpAddress" db:"ilo_ip_address"` ILOIPGateway *string `json:"iloIpGateway" db:"ilo_ip_gateway"` ILOIPNetmask *string `json:"iloIpNetmask" db:"ilo_ip_netmask"` ILOPassword *string `json:"iloPassword" db:"ilo_password"` ILOUsername *string `json:"iloUsername" db:"ilo_username"` LastUpdated *TimeNoMod `json:"lastUpdated" db:"last_updated"` // Deprecated: In the future, management interfaces must be configured as // interfaces within the Interfaces of the server, not separately on these // properties. MgmtIPAddress *string `json:"mgmtIpAddress" db:"mgmt_ip_address"` // Deprecated: In the future, management interfaces must be configured as // interfaces within the Interfaces of the server, not separately on these // properties. MgmtIPGateway *string `json:"mgmtIpGateway" db:"mgmt_ip_gateway"` // Deprecated: In the future, management interfaces must be configured as // interfaces within the Interfaces of the server, not separately on these // properties. MgmtIPNetmask *string `json:"mgmtIpNetmask" db:"mgmt_ip_netmask"` OfflineReason *string `json:"offlineReason" db:"offline_reason"` PhysLocation *string `json:"physLocation" db:"phys_location"` PhysLocationID *int `json:"physLocationId" db:"phys_location_id"` Profile *string `json:"profile" db:"profile"` // Deprecated: In API versions 4 and later, Profile descriptions must be // taken from the Profiles themselves, and Servers only contain identifying // information for their Profiles. ProfileDesc *string `json:"profileDesc" db:"profile_desc"` // Deprecated: In API versions 4 and later, Servers identify their Profiles // by Name, not ID. ProfileID *int `json:"profileId" db:"profile_id"` Rack *string `json:"rack" db:"rack"` // Deprecated: In APIv5 and later, this extraneous field is not calculated // by Traffic Ops; the information is available by comparing RevalUpdateTime // to RevalApplyTime. RevalPending *bool `json:"revalPending" db:"reval_pending"` Status *string `json:"status" db:"status"` StatusID *int `json:"statusId" db:"status_id"` TCPPort *int `json:"tcpPort" db:"tcp_port"` Type string `json:"type" db:"server_type"` TypeID *int `json:"typeId" db:"server_type_id"` // Deprecated: In APIv5 and later, this extraneous field is not calculated // by Traffic Ops; the information is available by comparing // ConfigUpdateTime to ConfigApplyTime. UpdPending *bool `json:"updPending" db:"upd_pending"` XMPPID *string `json:"xmppId" db:"xmpp_id"` XMPPPasswd *string `json:"xmppPasswd" db:"xmpp_passwd"` } // ServerNullableV11 is a server as it appeared in API version 1.1. type ServerNullableV11 struct { LegacyInterfaceDetails CommonServerProperties RouterHostName *string `json:"routerHostName" db:"router_host_name"` RouterPortName *string `json:"routerPortName" db:"router_port_name"` } // ServerNullableV2 is a server as it appeared in API v2. // // Deprecated: Traffic Ops API version 2 is deprecated, new code should use // ServerV40 or newer structures. type ServerNullableV2 struct { ServerNullableV11 IPIsService *bool `json:"ipIsService" db:"ip_address_is_service"` IP6IsService *bool `json:"ip6IsService" db:"ip6_address_is_service"` } // ToNullable converts the Server to an equivalent, "nullable" structure. // // Note that "zero" values (e.g. the empty string "") are NOT coerced to actual // null values. In particular, the only fields that will possibly be nil are // FQDN - if the original server had a nil FQDN - and DeliveryServices - which // will actually be a pointer to a nil map if the original server had a nil // DeliveryServices map. // Further note that this makes "shallow" copies of member properties; if // reference types (map, slice, pointer etc.) are altered on the original after // conversion, the changes WILL affect the nullable copy. // // Deprecated: Traffic Ops API version 2 is deprecated, new code should use // ServerV40 or newer structures. func (s Server) ToNullable() ServerNullableV2 { return 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, Status: &s.Status, StatusID: &s.StatusID, TCPPort: &s.TCPPort, Type: s.Type, TypeID: &s.TypeID, UpdPending: &s.UpdPending, XMPPID: &s.XMPPID, XMPPPasswd: &s.XMPPPasswd, }, LegacyInterfaceDetails: LegacyInterfaceDetails{ InterfaceMtu: &s.InterfaceMtu, InterfaceName: &s.InterfaceName, IPAddress: &s.IPAddress, IPGateway: &s.IPGateway, IPNetmask: &s.IPNetmask, IP6Address: &s.IP6Address, IP6Gateway: &s.IP6Gateway, }, RouterHostName: &s.RouterHostName, RouterPortName: &s.RouterPortName, }, IPIsService: &s.IPIsService, IP6IsService: &s.IP6IsService, } } // ToNonNullable converts the ServerNullableV2 safely to a Server structure. // // Deprecated: Traffic Ops API version 2 is deprecated, new code should use // ServerV40 or newer structures. func (s ServerNullableV2) ToNonNullable() Server { ret := Server{ Cachegroup: util.CoalesceToDefault(s.Cachegroup), CachegroupID: util.CoalesceToDefault(s.CachegroupID), CDNID: util.CoalesceToDefault((s.CDNID)), CDNName: util.CoalesceToDefault(s.CDNName), DomainName: util.CoalesceToDefault(s.DomainName), FQDN: s.FQDN, FqdnTime: s.FqdnTime, GUID: util.CoalesceToDefault(s.GUID), HostName: util.CoalesceToDefault(s.HostName), HTTPSPort: util.CoalesceToDefault(s.HTTPSPort), ID: util.CoalesceToDefault(s.ID), ILOIPAddress: util.CoalesceToDefault(s.ILOIPAddress), ILOIPGateway: util.CoalesceToDefault(s.ILOIPGateway), ILOIPNetmask: util.CoalesceToDefault(s.ILOIPNetmask), ILOPassword: util.CoalesceToDefault(s.ILOPassword), ILOUsername: util.CoalesceToDefault(s.ILOUsername), InterfaceMtu: util.CoalesceToDefault(s.InterfaceMtu), InterfaceName: util.CoalesceToDefault(s.InterfaceName), IP6Address: util.CoalesceToDefault(s.IP6Address), IP6IsService: util.CoalesceToDefault(s.IP6IsService), IP6Gateway: util.CoalesceToDefault(s.IP6Gateway), IPAddress: util.CoalesceToDefault(s.IPAddress), IPIsService: util.CoalesceToDefault(s.IPIsService), IPGateway: util.CoalesceToDefault(s.IPGateway), IPNetmask: util.CoalesceToDefault(s.IPNetmask), MgmtIPAddress: util.CoalesceToDefault(s.MgmtIPAddress), MgmtIPGateway: util.CoalesceToDefault(s.MgmtIPGateway), MgmtIPNetmask: util.CoalesceToDefault(s.MgmtIPNetmask), OfflineReason: util.CoalesceToDefault(s.OfflineReason), PhysLocation: util.CoalesceToDefault(s.PhysLocation), PhysLocationID: util.CoalesceToDefault(s.PhysLocationID), Profile: util.CoalesceToDefault(s.Profile), ProfileDesc: util.CoalesceToDefault(s.ProfileDesc), ProfileID: util.CoalesceToDefault(s.ProfileID), Rack: util.CoalesceToDefault(s.Rack), RevalPending: util.CoalesceToDefault(s.RevalPending), RouterHostName: util.CoalesceToDefault(s.RouterHostName), RouterPortName: util.CoalesceToDefault(s.RouterPortName), Status: util.CoalesceToDefault(s.Status), StatusID: util.CoalesceToDefault(s.StatusID), TCPPort: util.CoalesceToDefault(s.TCPPort), Type: s.Type, TypeID: util.CoalesceToDefault(s.TypeID), UpdPending: util.CoalesceToDefault(s.UpdPending), XMPPID: util.CoalesceToDefault(s.XMPPID), XMPPPasswd: util.CoalesceToDefault(s.XMPPPasswd), } if s.DeliveryServices == nil { ret.DeliveryServices = nil } else { ret.DeliveryServices = *s.DeliveryServices } if s.LastUpdated == nil { ret.LastUpdated = TimeNoMod{} } else { ret.LastUpdated = *s.LastUpdated } return ret } // Upgrade upgrades the ServerNullableV2 to the new ServerNullable structure. // // Note that this makes "shallow" copies of all underlying data, so changes to // the original will affect the upgraded copy. // // Deprecated: Traffic Ops API versions 2 and 3 are both deprecated, new code // should use ServerV40 or newer structures. func (s ServerNullableV2) Upgrade() (ServerV30, error) { ipv4IsService := false if s.IPIsService != nil { ipv4IsService = *s.IPIsService } ipv6IsService := false if s.IP6IsService != nil { ipv6IsService = *s.IP6IsService } upgraded := ServerV30{ CommonServerProperties: s.CommonServerProperties, RouterHostName: s.RouterHostName, RouterPortName: s.RouterPortName, } infs, err := s.LegacyInterfaceDetails.ToInterfaces(ipv4IsService, ipv6IsService) if err != nil { return upgraded, err } upgraded.Interfaces = infs return upgraded, nil } // UpgradeToV40 upgrades the ServerV30 to a ServerV40. // // This makes a "shallow" copy of the structure's properties. // // Deprecated: Traffic Ops API version 3 is deprecated, new code should use // ServerV40 or newer structures. func (s ServerV30) UpgradeToV40(profileNames []string) (ServerV40, error) { upgraded := UpdateServerPropertiesV40(profileNames, s.CommonServerProperties) upgraded.StatusLastUpdated = s.StatusLastUpdated infs, err := ToInterfacesV4(s.Interfaces, s.RouterHostName, s.RouterPortName) if err != nil { return upgraded, err } upgraded.Interfaces = infs return upgraded, nil } // UpgradeToV40 upgrades the ServerNullableV2 to a ServerV40. // // This makes a "shallow" copy of the structure's properties. // // Deprecated: Traffic Ops API version 2 is gone, new code should use // ServerV40 or newer structures. func (s ServerNullableV2) UpgradeToV40(profileNames []string) (ServerV40, error) { ipv4IsService := false if s.IPIsService != nil { ipv4IsService = *s.IPIsService } ipv6IsService := false if s.IP6IsService != nil { ipv6IsService = *s.IP6IsService } upgraded := UpdateServerPropertiesV40(profileNames, s.CommonServerProperties) infs, err := s.LegacyInterfaceDetails.ToInterfacesV4(ipv4IsService, ipv6IsService, s.RouterHostName, s.RouterPortName) if err != nil { return upgraded, err } upgraded.Interfaces = infs return upgraded, nil } // UpdateServerPropertiesV40 updates CommonServerProperties of V2 and V3 to // ServerV40. // // Deprecated: Traffic Ops API version 3 is deprecated, new code should use // ServerV40 or newer structures. func UpdateServerPropertiesV40(profileNames []string, properties CommonServerProperties) ServerV40 { return ServerV40{ Cachegroup: properties.Cachegroup, CachegroupID: properties.CachegroupID, CDNID: properties.CDNID, CDNName: properties.CDNName, DeliveryServices: properties.DeliveryServices, DomainName: properties.DomainName, FQDN: properties.FQDN, FqdnTime: properties.FqdnTime, GUID: properties.GUID, HostName: properties.HostName, HTTPSPort: properties.HTTPSPort, ID: properties.ID, ILOIPAddress: properties.ILOIPAddress, ILOIPGateway: properties.ILOIPGateway, ILOIPNetmask: properties.ILOIPNetmask, ILOPassword: properties.ILOPassword, ILOUsername: properties.ILOUsername, LastUpdated: properties.LastUpdated, MgmtIPAddress: properties.MgmtIPAddress, MgmtIPGateway: properties.MgmtIPGateway, MgmtIPNetmask: properties.MgmtIPNetmask, OfflineReason: properties.OfflineReason, ProfileNames: profileNames, PhysLocation: properties.PhysLocation, PhysLocationID: properties.PhysLocationID, Rack: properties.Rack, RevalPending: properties.RevalPending, Status: properties.Status, StatusID: properties.StatusID, TCPPort: properties.TCPPort, Type: properties.Type, TypeID: properties.TypeID, UpdPending: properties.UpdPending, XMPPID: properties.XMPPID, XMPPPasswd: properties.XMPPPasswd, } } // ServerV40 is the representation of a Server in version 4.0 of the Traffic Ops API. type ServerV40 struct { Cachegroup *string `json:"cachegroup" db:"cachegroup"` CachegroupID *int `json:"cachegroupId" db:"cachegroup_id"` CDNID *int `json:"cdnId" db:"cdn_id"` CDNName *string `json:"cdnName" db:"cdn_name"` // Deprecated: this has no known purpose, doesn't appear in any known API // responses, and it doesn't exist in the V5 version of this structure. DeliveryServices *map[string][]string `json:"deliveryServices,omitempty"` DomainName *string `json:"domainName" db:"domain_name"` FQDN *string `json:"fqdn,omitempty"` FqdnTime time.Time `json:"-"` GUID *string `json:"guid" db:"guid"` HostName *string `json:"hostName" db:"host_name"` HTTPSPort *int `json:"httpsPort" db:"https_port"` ID *int `json:"id" db:"id"` ILOIPAddress *string `json:"iloIpAddress" db:"ilo_ip_address"` ILOIPGateway *string `json:"iloIpGateway" db:"ilo_ip_gateway"` ILOIPNetmask *string `json:"iloIpNetmask" db:"ilo_ip_netmask"` ILOPassword *string `json:"iloPassword" db:"ilo_password"` ILOUsername *string `json:"iloUsername" db:"ilo_username"` LastUpdated *TimeNoMod `json:"lastUpdated" db:"last_updated"` // Deprecated: In the future, management interfaces must be configured as // interfaces within the Interfaces of the server, not separately on these // properties. MgmtIPAddress *string `json:"mgmtIpAddress" db:"mgmt_ip_address"` // Deprecated: In the future, management interfaces must be configured as // interfaces within the Interfaces of the server, not separately on these // properties. MgmtIPGateway *string `json:"mgmtIpGateway" db:"mgmt_ip_gateway"` // Deprecated: In the future, management interfaces must be configured as // interfaces within the Interfaces of the server, not separately on these // properties. MgmtIPNetmask *string `json:"mgmtIpNetmask" db:"mgmt_ip_netmask"` OfflineReason *string `json:"offlineReason" db:"offline_reason"` PhysLocation *string `json:"physLocation" db:"phys_location"` PhysLocationID *int `json:"physLocationId" db:"phys_location_id"` ProfileNames []string `json:"profileNames" db:"profile_name"` Rack *string `json:"rack" db:"rack"` // Deprecated: In APIv5 and later, this extraneous field is not calculated // by Traffic Ops; the information is available by comparing RevalUpdateTime // to RevalApplyTime. RevalPending *bool `json:"revalPending" db:"reval_pending"` Status *string `json:"status" db:"status"` StatusID *int `json:"statusId" db:"status_id"` TCPPort *int `json:"tcpPort" db:"tcp_port"` Type string `json:"type" db:"server_type"` TypeID *int `json:"typeId" db:"server_type_id"` // Deprecated: In APIv5 and later, this extraneous field is not calculated // by Traffic Ops; the information is available by comparing // ConfigUpdateTime to ConfigApplyTime. UpdPending *bool `json:"updPending" db:"upd_pending"` XMPPID *string `json:"xmppId" db:"xmpp_id"` XMPPPasswd *string `json:"xmppPasswd" db:"xmpp_passwd"` Interfaces []ServerInterfaceInfoV40 `json:"interfaces" db:"interfaces"` StatusLastUpdated *time.Time `json:"statusLastUpdated" db:"status_last_updated"` ConfigUpdateTime *time.Time `json:"configUpdateTime" db:"config_update_time"` ConfigApplyTime *time.Time `json:"configApplyTime" db:"config_apply_time"` RevalUpdateTime *time.Time `json:"revalUpdateTime" db:"revalidate_update_time"` RevalApplyTime *time.Time `json:"revalApplyTime" db:"revalidate_apply_time"` } // ServerV4 is the representation of a Server in the latest minor version of // version 4 of the Traffic Ops API. type ServerV4 = ServerV40 // Upgrade upgrades to an APIv5 representation of a Server. func (s ServerV4) Upgrade() ServerV50 { upgraded := ServerV50{ CacheGroup: util.CoalesceToDefault(s.Cachegroup), CacheGroupID: util.CoalesceToDefault(s.CachegroupID), CDNID: util.CoalesceToDefault(s.CDNID), CDN: util.CoalesceToDefault(s.CDNName), DomainName: util.CoalesceToDefault(s.DomainName), GUID: util.CopyIfNotNil(s.GUID), HostName: util.CoalesceToDefault(s.HostName), HTTPSPort: util.CopyIfNotNil(s.HTTPSPort), ID: util.CoalesceToDefault(s.ID), ILOIPAddress: util.CopyIfNotNil(s.ILOIPAddress), ILOIPGateway: util.CopyIfNotNil(s.ILOIPGateway), ILOIPNetmask: util.CopyIfNotNil(s.ILOIPNetmask), ILOPassword: util.CopyIfNotNil(s.ILOPassword), ILOUsername: util.CopyIfNotNil(s.ILOUsername), LastUpdated: util.CoalesceToDefault(s.LastUpdated).Time, MgmtIPAddress: util.CopyIfNotNil(s.MgmtIPAddress), MgmtIPGateway: util.CopyIfNotNil(s.MgmtIPGateway), MgmtIPNetmask: util.CopyIfNotNil(s.MgmtIPNetmask), OfflineReason: util.CopyIfNotNil(s.OfflineReason), PhysicalLocation: util.CoalesceToDefault(s.PhysLocation), PhysicalLocationID: util.CoalesceToDefault(s.PhysLocationID), Profiles: make([]string, len(s.ProfileNames)), Rack: util.CopyIfNotNil(s.Rack), Status: util.CoalesceToDefault(s.Status), StatusID: util.CoalesceToDefault(s.StatusID), TCPPort: util.CopyIfNotNil(s.TCPPort), Type: s.Type, TypeID: util.CoalesceToDefault(s.TypeID), XMPPID: util.CopyIfNotNil(s.XMPPID), XMPPPasswd: util.CopyIfNotNil(s.XMPPPasswd), Interfaces: make([]ServerInterfaceInfoV40, len(s.Interfaces)), StatusLastUpdated: util.CopyIfNotNil(s.StatusLastUpdated), ConfigUpdateTime: util.CopyIfNotNil(s.ConfigUpdateTime), ConfigApplyTime: util.CopyIfNotNil(s.ConfigApplyTime), RevalUpdateTime: util.CopyIfNotNil(s.RevalUpdateTime), RevalApplyTime: util.CopyIfNotNil(s.RevalApplyTime), } copy(upgraded.Profiles, s.ProfileNames) for i, inf := range s.Interfaces { upgraded.Interfaces[i] = inf.Copy() } return upgraded } // ServerV30 is the representation of a Server in version 3 of the Traffic Ops API. // // Deprecated: Traffic Ops API version 3 is deprecated, new code should use // ServerV40 or newer structures. type ServerV30 struct { CommonServerProperties RouterHostName *string `json:"routerHostName" db:"router_host_name"` RouterPortName *string `json:"routerPortName" db:"router_port_name"` Interfaces []ServerInterfaceInfo `json:"interfaces" db:"interfaces"` StatusLastUpdated *time.Time `json:"statusLastUpdated" db:"status_last_updated"` } // ServerNullable represents an ATC server, as returned by the TO API. // // Deprecated: Traffic Ops API version 3 is deprecated, new code should use // ServerV40 or newer structures. type ServerNullable ServerV30 // 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) { nullable := ServerV30(*s) return nullable.ToServerV2() } // ToServerV2 converts the server to an equivalent ServerNullableV2 structure, // if possible. If the conversion could not be performed, an error is returned. // // Deprecated: Traffic Ops API version 2 is deprecated, new code should use // ServerV40 or newer structures. func (s *ServerV30) ToServerV2() (ServerNullableV2, error) { legacyServer := ServerNullableV2{ ServerNullableV11: ServerNullableV11{ CommonServerProperties: s.CommonServerProperties, }, IPIsService: new(bool), IP6IsService: new(bool), } var err error legacyServer.LegacyInterfaceDetails, err = InterfaceInfoToLegacyInterfaces(s.Interfaces) 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 } // ToServerV3FromV4 downgrades the ServerV40 to a ServerV30. // // This makes a "shallow" copy of most of the structure's properties. // // Deprecated: Traffic Ops API version 3 is deprecated, new code should use // ServerV40 or newer structures. func (s *ServerV40) ToServerV3FromV4(csp CommonServerProperties) (ServerV30, error) { routerHostName := "" routerPortName := "" interfaces := make([]ServerInterfaceInfo, 0) i := ServerInterfaceInfo{} for _, in := range s.Interfaces { i.Name = in.Name i.MTU = in.MTU i.MaxBandwidth = in.MaxBandwidth i.Monitor = in.Monitor i.IPAddresses = in.IPAddresses for _, ip := range i.IPAddresses { if ip.ServiceAddress { routerHostName = in.RouterHostName routerPortName = in.RouterPortName } } interfaces = append(interfaces, i) } serverV30 := ServerV30{ CommonServerProperties: csp, Interfaces: interfaces, StatusLastUpdated: s.StatusLastUpdated, } if len(s.Interfaces) != 0 { serverV30.RouterHostName = &routerHostName serverV30.RouterPortName = &routerPortName } return serverV30, nil } // ToServerV2FromV4 downgrades the ServerV40 to a ServerNullableV2. // // This makes a "shallow" copy of most of the structure's properties. // // Deprecated: Traffic Ops API version 2 is deprecated, new code should use // ServerV40 or newer structures. func (s *ServerV40) ToServerV2FromV4(csp CommonServerProperties) (ServerNullableV2, error) { routerHostName := "" routerPortName := "" legacyServer := ServerNullableV2{ ServerNullableV11: ServerNullableV11{ CommonServerProperties: csp, }, IPIsService: new(bool), IP6IsService: new(bool), } interfaces := make([]ServerInterfaceInfo, 0) i := ServerInterfaceInfo{} for _, in := range s.Interfaces { i.Name = in.Name i.MTU = in.MTU i.MaxBandwidth = in.MaxBandwidth i.Monitor = in.Monitor i.IPAddresses = in.IPAddresses for _, ip := range i.IPAddresses { if ip.ServiceAddress { routerHostName = in.RouterHostName routerPortName = in.RouterPortName } } interfaces = append(interfaces, i) } var err error legacyServer.LegacyInterfaceDetails, err = InterfaceInfoToLegacyInterfaces(interfaces) if err != nil { return legacyServer, err } *legacyServer.IPIsService = legacyServer.LegacyInterfaceDetails.IPAddress != nil && *legacyServer.LegacyInterfaceDetails.IPAddress != "" *legacyServer.IP6IsService = legacyServer.LegacyInterfaceDetails.IP6Address != nil && *legacyServer.LegacyInterfaceDetails.IP6Address != "" if len(s.Interfaces) != 0 { legacyServer.RouterHostName = &routerHostName legacyServer.RouterPortName = &routerPortName } return legacyServer, nil } // ServerV50 is the representation of a Server in version 5.0 of the Traffic Ops // API. type ServerV50 struct { CacheGroup string `json:"cacheGroup" db:"cachegroup"` CacheGroupID int `json:"cacheGroupID" db:"cachegroup_id"` CDNID int `json:"cdnID" db:"cdn_id"` CDN string `json:"cdn" db:"cdn_name"` // The time at which configuration updates were last applied for this server // by t3c. ConfigApplyTime *time.Time `json:"configApplyTime,omitempty" db:"config_apply_time"` // The time at which configuration updates were last queued for this server. ConfigUpdateTime *time.Time `json:"configUpdateTime,omitempty" db:"config_update_time"` // If the last config apply failed for this server ConfigUpdateFailed bool `json:"configUpdateFailed" db:"config_update_failed"` DomainName string `json:"domainName" db:"domain_name"` // Deprecated: This property has unknown purpose and should not be used so // that we can get rid of it. GUID *string `json:"guid" db:"guid"` HostName string `json:"hostName" db:"host_name"` HTTPSPort *int `json:"httpsPort,omitempty" db:"https_port"` ID int `json:"id" db:"id"` ILOIPAddress *string `json:"iloIpAddress,omitempty" db:"ilo_ip_address"` ILOIPGateway *string `json:"iloIpGateway,omitempty" db:"ilo_ip_gateway"` ILOIPNetmask *string `json:"iloIpNetmask,omitempty" db:"ilo_ip_netmask"` ILOPassword *string `json:"iloPassword,omitempty" db:"ilo_password"` ILOUsername *string `json:"iloUsername,omitempty" db:"ilo_username"` Interfaces []ServerInterfaceInfoV40 `json:"interfaces" db:"interfaces"` LastUpdated time.Time `json:"lastUpdated" db:"last_updated"` // Deprecated: In the future, management interfaces must be configured as // interfaces within the Interfaces of the server, not separately on these // properties. MgmtIPAddress *string `json:"mgmtIpAddress,omitempty" db:"mgmt_ip_address"` // Deprecated: In the future, management interfaces must be configured as // interfaces within the Interfaces of the server, not separately on these // properties. MgmtIPGateway *string `json:"mgmtIpGateway,omitempty" db:"mgmt_ip_gateway"` // Deprecated: In the future, management interfaces must be configured as // interfaces within the Interfaces of the server, not separately on these // properties. MgmtIPNetmask *string `json:"mgmtIpNetmask,omitempty" db:"mgmt_ip_netmask"` OfflineReason *string `json:"offlineReason" db:"offline_reason"` PhysicalLocation string `json:"physicalLocation" db:"phys_location"` PhysicalLocationID int `json:"physicalLocationID" db:"phys_location_id"` Profiles []string `json:"profiles,omitempty" db:"profile_name"` // Deprecated: This property has unknown purpose and should not be used so // that we can get rid of it. Rack *string `json:"rack" db:"rack"` // The time at which revalidations for this server were last updated by t3c. RevalApplyTime *time.Time `json:"revalApplyTime,omitempty" db:"revalidate_apply_time"` // The time at which revalidations were last queued for this server. RevalUpdateTime *time.Time `json:"revalUpdateTime,omitempty" db:"revalidate_update_time"` // If the last reval apply failed for this server RevalUpdateFailed bool `json:"revalUpdateFailed" db:"revalidate_update_failed"` Status string `json:"status" db:"status"` StatusID int `json:"statusID" db:"status_id"` StatusLastUpdated *time.Time `json:"statusLastUpdated,omitempty" db:"status_last_updated"` TCPPort *int `json:"tcpPort" db:"tcp_port"` Type string `json:"type" db:"server_type"` TypeID int `json:"typeID" db:"server_type_id"` XMPPID *string `json:"xmppId" db:"xmpp_id"` // Deprecated: This property has unknown purpose and should not be used so // that we can get rid of it. XMPPPasswd *string `json:"xmppPasswd" db:"xmpp_passwd"` } // Downgrade downgrades to a V4 representation of a Server. func (s ServerV50) Downgrade() ServerV4 { downgraded := ServerV40{ Cachegroup: util.Ptr(s.CacheGroup), CachegroupID: util.Ptr(s.CacheGroupID), CDNID: util.Ptr(s.CDNID), CDNName: util.Ptr(s.CDN), DeliveryServices: nil, DomainName: util.Ptr(s.DomainName), FQDN: util.Ptr(s.HostName + "." + s.DomainName), FqdnTime: time.Time{}, GUID: util.CopyIfNotNil(s.GUID), HostName: util.Ptr(s.HostName), HTTPSPort: util.CopyIfNotNil(s.HTTPSPort), ID: util.Ptr(s.ID), ILOIPAddress: util.CopyIfNotNil(s.ILOIPAddress), ILOIPGateway: util.CopyIfNotNil(s.ILOIPGateway), ILOIPNetmask: util.CopyIfNotNil(s.ILOIPNetmask), ILOPassword: util.CopyIfNotNil(s.ILOPassword), ILOUsername: util.CopyIfNotNil(s.ILOUsername), LastUpdated: &TimeNoMod{Time: s.LastUpdated}, MgmtIPAddress: util.CopyIfNotNil(s.MgmtIPAddress), MgmtIPGateway: util.CopyIfNotNil(s.MgmtIPGateway), MgmtIPNetmask: util.CopyIfNotNil(s.MgmtIPNetmask), OfflineReason: util.CopyIfNotNil(s.OfflineReason), PhysLocation: util.Ptr(s.PhysicalLocation), PhysLocationID: util.Ptr(s.PhysicalLocationID), ProfileNames: make([]string, len(s.Profiles)), Rack: util.CopyIfNotNil(s.Rack), RevalPending: util.Ptr(s.RevalidationPending()), Status: util.Ptr(s.Status), StatusID: util.Ptr(s.StatusID), TCPPort: util.CopyIfNotNil(s.TCPPort), Type: s.Type, TypeID: util.Ptr(s.TypeID), UpdPending: util.Ptr(s.UpdatePending()), XMPPID: util.CopyIfNotNil(s.XMPPID), XMPPPasswd: util.CopyIfNotNil(s.XMPPPasswd), Interfaces: make([]ServerInterfaceInfoV40, len(s.Interfaces)), StatusLastUpdated: util.CopyIfNotNil(s.StatusLastUpdated), ConfigUpdateTime: util.CopyIfNotNil(s.ConfigUpdateTime), ConfigApplyTime: util.CopyIfNotNil(s.ConfigApplyTime), RevalUpdateTime: util.CopyIfNotNil(s.RevalUpdateTime), RevalApplyTime: util.CopyIfNotNil(s.RevalApplyTime), } copy(downgraded.ProfileNames, s.Profiles) for i, inf := range s.Interfaces { downgraded.Interfaces[i] = inf.Copy() } return downgraded } // UpdatePending tells whether the Server has pending updates. func (s ServerV50) UpdatePending() bool { return s.ConfigApplyTime != nil && s.ConfigUpdateTime != nil && s.ConfigApplyTime.Before(*s.ConfigUpdateTime) } // RevalidationPending tells whether the Server has pending revalidations. func (s ServerV50) RevalidationPending() bool { return s.RevalApplyTime != nil && s.RevalUpdateTime != nil && s.RevalApplyTime.Before(*s.RevalUpdateTime) } // ServerV5 is the representation of a Server in the latest minor version of // version 5 of the Traffic Ops API. type ServerV5 = ServerV50 // ServerUpdateStatusV5 is the type of each entry in the `response` property of // the response from Traffic Ops to GET requests made to its // /servers/{{host name}}/update_status in the latest minor API // v5.0 endpoint. type ServerUpdateStatusV5 ServerUpdateStatusV50 // ServerUpdateStatusV50 is the type of each entry in the `response` property of // the response from Traffic Ops to GET requests made to its // /servers/{{host name}}/update_status in API v5.0 endpoint. type ServerUpdateStatusV50 struct { HostName string `json:"host_name"` // Deprecated: In APIv5 and later, this extraneous field is not calculated // by Traffic Ops; the information is available by comparing ConfigUpdateTime // to ConfigApplyTime. UpdatePending bool `json:"upd_pending"` // Deprecated: In APIv5 and later, this extraneous field is not calculated // by Traffic Ops; the information is available by comparing RevalUpdateTime // to RevalApplyTime. RevalPending bool `json:"reval_pending"` UseRevalPending bool `json:"use_reval_pending"` HostId int `json:"host_id"` Status string `json:"status"` ParentPending bool `json:"parent_pending"` ParentRevalPending bool `json:"parent_reval_pending"` ConfigUpdateTime *time.Time `json:"config_update_time"` ConfigApplyTime *time.Time `json:"config_apply_time"` ConfigUpdateFailed *bool `json:"config_update_failed"` RevalidateUpdateTime *time.Time `json:"revalidate_update_time"` RevalidateApplyTime *time.Time `json:"revalidate_apply_time"` RevalidateUpdateFailed *bool `json:"revalidate_update_failed"` } func (sus ServerUpdateStatusV5) Downgrade() ServerUpdateStatusV40 { return ServerUpdateStatusV40{ sus.HostName, sus.UpdatePending, sus.RevalPending, sus.UseRevalPending, sus.HostId, sus.Status, sus.ParentPending, sus.ParentRevalPending, sus.ConfigUpdateTime, sus.ConfigApplyTime, sus.RevalidateUpdateTime, sus.RevalidateApplyTime, } } // ServerUpdateStatusV4 is the type of each entry in the `response` property of // the response from Traffic Ops to GET requests made to its // /servers/{{host name}}/update_status in the latest minor API // v4.0 endpoint. type ServerUpdateStatusV4 ServerUpdateStatusV40 // ServerUpdateStatusV40 is the type of each entry in the `response` property of // the response from Traffic Ops to GET requests made to its // /servers/{{host name}}/update_status in API v4.0 endpoint. type ServerUpdateStatusV40 struct { HostName string `json:"host_name"` UpdatePending bool `json:"upd_pending"` // Deprecated: In APIv5 and later, this extraneous field is not calculated // by Traffic Ops; the information is available by comparing RevalUpdateTime // to RevalApplyTime. RevalPending bool `json:"reval_pending"` UseRevalPending bool `json:"use_reval_pending"` HostId int `json:"host_id"` Status string `json:"status"` ParentPending bool `json:"parent_pending"` ParentRevalPending bool `json:"parent_reval_pending"` ConfigUpdateTime *time.Time `json:"config_update_time"` ConfigApplyTime *time.Time `json:"config_apply_time"` RevalidateUpdateTime *time.Time `json:"revalidate_update_time"` RevalidateApplyTime *time.Time `json:"revalidate_apply_time"` } // Downgrade strips the Config and Revalidate timestamps from // ServerUpdateStatusV40 to return previous versions of the struct to ensure // previous compatibility. func (sus ServerUpdateStatusV40) Downgrade() ServerUpdateStatus { return ServerUpdateStatus{ HostName: sus.HostName, UpdatePending: sus.UpdatePending, RevalPending: sus.RevalPending, UseRevalPending: sus.UseRevalPending, HostId: sus.HostId, Status: sus.Status, ParentPending: sus.ParentPending, ParentRevalPending: sus.ParentRevalPending, } } // ServerUpdateStatus is the type of each entry in the `response` property of // the response from Traffic Ops to GET requests made to its // /servers/{{host name}}/update_status API endpoint. // // This is a subset of Server structure information mainly relating to what // operations t3c has done/needs to do. For most purposes, using Server // structures will be better - especially since the basic principle of this // type is predicated on a lie: that server host names are unique. // // Deprecated: ServerUpdateStatus is for use only in APIs below V4. New code // should use ServerUpdateStatusV40 or newer. type ServerUpdateStatus struct { HostName string `json:"host_name"` UpdatePending bool `json:"upd_pending"` RevalPending bool `json:"reval_pending"` UseRevalPending bool `json:"use_reval_pending"` HostId int `json:"host_id"` Status string `json:"status"` ParentPending bool `json:"parent_pending"` ParentRevalPending bool `json:"parent_reval_pending"` } // Upgrade converts the deprecated ServerUpdateStatus to a // ServerUpdateStatusV4 struct. func (sus ServerUpdateStatus) Upgrade() ServerUpdateStatusV4 { return ServerUpdateStatusV4{ HostName: sus.HostName, UpdatePending: sus.UpdatePending, RevalPending: sus.RevalPending, UseRevalPending: sus.UseRevalPending, HostId: sus.HostId, Status: sus.Status, ParentPending: sus.ParentPending, ParentRevalPending: sus.ParentRevalPending, } } // ServerUpdateStatusResponseV50 is the type of a response from the Traffic // Ops API to a request to its /servers/{{host name}}/update_status endpoint // in API version 5.0. type ServerUpdateStatusResponseV50 struct { Response []ServerUpdateStatusV50 `json:"response"` Alerts } // ServerUpdateStatusResponseV5 is the type of a response from the Traffic // Ops API to a request to its /servers/{{host name}}/update_status endpoint // in the latest minor version of API version 5. type ServerUpdateStatusResponseV5 = ServerUpdateStatusResponseV50 // ServerUpdateStatusResponseV40 is the type of a response from the Traffic // Ops API to a request to its /servers/{{host name}}/update_status endpoint // in API version 4.0. type ServerUpdateStatusResponseV40 struct { Response []ServerUpdateStatusV40 `json:"response"` Alerts } // ServerUpdateStatusResponseV4 is the type of a response from the Traffic // Ops API to a request to its /servers/{{host name}}/update_status endpoint // in the latest minor version of API version 4. type ServerUpdateStatusResponseV4 = ServerUpdateStatusResponseV40 // ServerPutStatus is a request to change the Status of a server, optionally // with an explanation. type ServerPutStatus struct { Status util.JSONNameOrIDStr `json:"status"` OfflineReason *string `json:"offlineReason"` } // ServerInfo is a stripped-down type containing a subset of information for a // server. // // This is primarily only useful internally in Traffic Ops for // constructing/examining the relationships between servers and other ATC // objects. That is to say, for most other purposes a ServerV4 would be better // suited. type ServerInfo struct { Cachegroup string CachegroupID int CDNID int DomainName string HostName string ID int Status string Type string } // ServerDetail is a type that contains a superset of the information available // in a ServerNullable. // // This should NOT be used in general, it's almost always better to use a // proper server representation. However, this structure is not deprecated // because it is embedded in structures still in use, and its future is unclear // and undecided. // // Deprecated: The API versions that use this representation have been // deprecated, newer structures like ServerV4 should be used instead. type ServerDetail struct { CacheGroup *string `json:"cachegroup" db:"cachegroup"` CDNName *string `json:"cdnName" db:"cdn_name"` DeliveryServiceIDs []int64 `json:"deliveryservices,omitempty"` DomainName *string `json:"domainName" db:"domain_name"` GUID *string `json:"guid" db:"guid"` HardwareInfo map[string]string `json:"hardwareInfo"` HostName *string `json:"hostName" db:"host_name"` HTTPSPort *int `json:"httpsPort" db:"https_port"` ID *int `json:"id" db:"id"` ILOIPAddress *string `json:"iloIpAddress" db:"ilo_ip_address"` ILOIPGateway *string `json:"iloIpGateway" db:"ilo_ip_gateway"` ILOIPNetmask *string `json:"iloIpNetmask" db:"ilo_ip_netmask"` ILOPassword *string `json:"iloPassword" db:"ilo_password"` ILOUsername *string `json:"iloUsername" db:"ilo_username"` MgmtIPAddress *string `json:"mgmtIpAddress" db:"mgmt_ip_address"` MgmtIPGateway *string `json:"mgmtIpGateway" db:"mgmt_ip_gateway"` MgmtIPNetmask *string `json:"mgmtIpNetmask" db:"mgmt_ip_netmask"` OfflineReason *string `json:"offlineReason" db:"offline_reason"` PhysLocation *string `json:"physLocation" db:"phys_location"` Profile *string `json:"profile" db:"profile"` ProfileDesc *string `json:"profileDesc" db:"profile_desc"` Rack *string `json:"rack" db:"rack"` Status *string `json:"status" db:"status"` TCPPort *int `json:"tcpPort" db:"tcp_port"` Type string `json:"type" db:"server_type"` XMPPID *string `json:"xmppId" db:"xmpp_id"` XMPPPasswd *string `json:"xmppPasswd" db:"xmpp_passwd"` } // ServerQueueUpdateRequest encodes the request data for the POST // servers/{{ID}}/queue_update endpoint. type ServerQueueUpdateRequest struct { Action string `json:"action"` } // ServerQueueUpdateResponse decodes the full response with alerts from the POST // servers/{{ID}}/queue_update endpoint. type ServerQueueUpdateResponse struct { Response ServerQueueUpdate `json:"response"` Alerts } // ServerQueueUpdate decodes the update data from the POST // servers/{{ID}}/queue_update endpoint. type ServerQueueUpdate struct { ServerID util.JSONIntStr `json:"serverId"` Action string `json:"action"` } // ServersV5Response is the format of a response to a GET request to /servers in // APIv5. type ServersV5Response struct { Response []ServerV5 `json:"response"` Summary struct { Count uint64 `json:"count"` } `json:"summary"` Alerts } // ServerV5Response is the format of a response to single-server operations // using /servers in APIv5. type ServerV5Response struct { Response ServerV5 `json:"response"` Summary struct { Count uint64 `json:"count"` } `json:"summary"` Alerts }